#region License Information /* HeuristicLab * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using System.Data.Common; using System.Threading; namespace HeuristicLab.Grid { class Database { private string connectionString; private ReaderWriterLockSlim rwLock; private DbProviderFactory factory; public Database(string connectionString) { this.connectionString = connectionString; rwLock = new ReaderWriterLockSlim(); factory = DbProviderFactories.GetFactory("System.Data.SQLite"); } #region create empty database public void CreateNew() { rwLock.EnterWriteLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); using(DbTransaction t = cnn.BeginTransaction()) { using(DbCommand cmd = cnn.CreateCommand()) { cmd.CommandText = "CREATE TABLE Job (ID integer primary key autoincrement, Guid text, Status text, CreationTime DateTime, StartTime DateTime, RawData blob)"; cmd.Transaction = t; cmd.ExecuteNonQuery(); } t.Commit(); } } } finally { rwLock.ExitWriteLock(); } } #endregion internal void InsertJob(Guid guid, JobState jobState, byte[] rawData) { rwLock.EnterWriteLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); using(DbTransaction t = cnn.BeginTransaction()) { using(DbCommand c = cnn.CreateCommand()) { c.Transaction = t; c.CommandText = "Insert into Job (Guid, Status, CreationTime, StartTime, RawData) values (@Guid, @Status, @CreationTime, @StartTime, @RawData)"; DbParameter guidParam = c.CreateParameter(); guidParam.ParameterName = "@Guid"; guidParam.Value = guid.ToString(); c.Parameters.Add(guidParam); DbParameter statusParam = c.CreateParameter(); statusParam.ParameterName = "@Status"; statusParam.Value = jobState.ToString(); c.Parameters.Add(statusParam); DbParameter creationParam = c.CreateParameter(); creationParam.ParameterName = "@CreationTime"; DateTime now = DateTime.Now; creationParam.Value = now; c.Parameters.Add(creationParam); DbParameter startParam = c.CreateParameter(); startParam.ParameterName = "@StartTime"; if(jobState == JobState.Busy) startParam.Value = now; else startParam.Value = null; c.Parameters.Add(startParam); DbParameter rawDataParam = c.CreateParameter(); rawDataParam.ParameterName = "@RawData"; rawDataParam.Value = rawData; c.Parameters.Add(rawDataParam); c.ExecuteNonQuery(); } t.Commit(); } } } finally { rwLock.ExitWriteLock(); } } internal JobEntry GetNextWaitingJob() { rwLock.EnterUpgradeableReadLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); JobEntry job = new JobEntry(); using(DbTransaction t = cnn.BeginTransaction()) { using(DbCommand c = cnn.CreateCommand()) { c.Transaction = t; c.CommandText = "select guid,creationtime,starttime,rawdata from job, (select id from job where status=@Status order by creationtime limit 1) as next where job.id=next.id"; DbParameter statusParameter = c.CreateParameter(); statusParameter.ParameterName = "@Status"; statusParameter.Value = JobState.Waiting.ToString(); c.Parameters.Add(statusParameter); DbDataReader r = c.ExecuteReader(); if(!r.HasRows) { r.Close(); t.Commit(); return null; } r.Read(); job.Status = JobState.Busy; job.Guid = r.GetGuid(0); job.CreationTime = r.GetDateTime(1); job.StartTime = r.IsDBNull(2) ? null : new Nullable(r.GetDateTime(2)); job.RawData = (byte[])r.GetValue(3); r.Close(); } rwLock.EnterWriteLock(); try { using(DbCommand updateCmd = cnn.CreateCommand()) { updateCmd.Transaction = t; updateCmd.CommandText = "Update job set Status=@Status where Guid=@Guid"; DbParameter statusParam = updateCmd.CreateParameter(); statusParam.ParameterName = "@Status"; statusParam.Value = JobState.Busy.ToString(); DbParameter guidParam = updateCmd.CreateParameter(); guidParam.ParameterName = "@Guid"; guidParam.Value = job.Guid.ToString(); updateCmd.Parameters.Add(statusParam); updateCmd.Parameters.Add(guidParam); updateCmd.ExecuteNonQuery(); } t.Commit(); } finally { rwLock.ExitWriteLock(); } return job; } } } finally { rwLock.ExitUpgradeableReadLock(); } } internal void SetJobResult(Guid guid, byte[] result) { rwLock.EnterWriteLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); using(DbTransaction t = cnn.BeginTransaction()) { using(DbCommand c = cnn.CreateCommand()) { c.Transaction = t; c.CommandText = "Update Job set Status=@Status, RawData=@RawData where Guid=@Guid"; DbParameter rawDataParam = c.CreateParameter(); DbParameter statusParam = c.CreateParameter(); DbParameter guidParam = c.CreateParameter(); rawDataParam.ParameterName = "@RawData"; rawDataParam.Value = result; guidParam.ParameterName = "@Guid"; guidParam.Value = guid.ToString(); statusParam.ParameterName = "@Status"; statusParam.Value = JobState.Finished.ToString(); c.Parameters.Add(rawDataParam); c.Parameters.Add(statusParam); c.Parameters.Add(guidParam); c.ExecuteNonQuery(); } t.Commit(); } } } finally { rwLock.ExitWriteLock(); } } internal void UpdateJobState(Guid guid, JobState jobState) { rwLock.EnterWriteLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); using(DbTransaction t = cnn.BeginTransaction()) { using(DbCommand c = cnn.CreateCommand()) { c.Transaction = t; c.CommandText = "Update Job set Status=@Status, StartTime=@StartTime where Guid=@Guid"; DbParameter statusParam = c.CreateParameter(); DbParameter startTimeParam = c.CreateParameter(); DbParameter guidParam = c.CreateParameter(); startTimeParam.ParameterName = "@StartTime"; if(jobState == JobState.Busy) startTimeParam.Value = DateTime.Now; else startTimeParam.Value = null; guidParam.ParameterName = "@Guid"; guidParam.Value = guid.ToString(); statusParam.ParameterName = "@Status"; statusParam.Value = jobState.ToString(); c.Parameters.Add(startTimeParam); c.Parameters.Add(statusParam); c.Parameters.Add(guidParam); c.ExecuteNonQuery(); } t.Commit(); } } } finally { rwLock.ExitWriteLock(); } } internal JobEntry GetJob(Guid guid) { rwLock.EnterReadLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); DbCommand c = cnn.CreateCommand(); c.CommandText = "Select Status, CreationTime, StartTime, Rawdata from Job where Guid=@Guid"; DbParameter guidParameter = c.CreateParameter(); guidParameter.ParameterName = "@Guid"; guidParameter.Value = guid.ToString(); c.Parameters.Add(guidParameter); DbDataReader r = c.ExecuteReader(); if(r.HasRows) { r.Read(); JobEntry job = new JobEntry(); job.Guid = guid; job.Status = (JobState)Enum.Parse(typeof(JobState), r.GetString(0)); job.CreationTime = r.GetDateTime(1); job.StartTime = r.IsDBNull(2) ? null : new Nullable(r.GetDateTime(2)); job.RawData = (byte[])r.GetValue(3); return job; } r.Close(); } } finally { rwLock.ExitReadLock(); } return null; } internal JobState GetJobState(Guid guid) { rwLock.EnterReadLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); DbCommand c = cnn.CreateCommand(); c.CommandText = "Select Status from Job where Guid=@Guid"; DbParameter guidParameter = c.CreateParameter(); guidParameter.ParameterName = "@Guid"; guidParameter.Value = guid.ToString(); c.Parameters.Add(guidParameter); DbDataReader r = c.ExecuteReader(); if(r.HasRows) { r.Read(); return (JobState)Enum.Parse(typeof(JobState), r.GetString(0)); } r.Close(); } } finally { rwLock.ExitReadLock(); } return JobState.Unknown; } internal long GetJobCount(JobState status) { rwLock.EnterReadLock(); try { using (DbConnection cnn = factory.CreateConnection()) { cnn.ConnectionString = connectionString; cnn.Open(); DbCommand c = cnn.CreateCommand(); c.CommandText = "Select Count(id) from Job where Status=@Status"; DbParameter stateParameter = c.CreateParameter(); stateParameter.ParameterName = "@Status"; stateParameter.Value = status.ToString(); c.Parameters.Add(stateParameter); return (long)c.ExecuteScalar(); } } finally { rwLock.ExitReadLock(); } } /// /// Does nothing right now (= running jobs that disappear are never restarted). /// internal void RestartExpiredActiveJobs() { } /// /// Does nothing right now (= results are never deleted). /// internal void DeleteExpiredResults() { } } }