#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.Text; using System.Threading; using System.ServiceModel; namespace HeuristicLab.Grid { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] public class EngineStore : IEngineStore { private List engineList; private Dictionary waitingEngines; private Dictionary runningEngines; private Dictionary waitHandles; private Dictionary results; private Dictionary resultDate; private Dictionary runningEngineDate; private const int RESULT_EXPIRY_TIME_MIN = 10; private const int RUNNING_JOB_EXPIRY_TIME_MIN = 10; private object bigLock; public int WaitingJobs { get { return waitingEngines.Count; } } public int RunningJobs { get { return runningEngines.Count; } } public int WaitingResults { get { return results.Count; } } public EngineStore() { engineList = new List(); waitingEngines = new Dictionary(); runningEngines = new Dictionary(); waitHandles = new Dictionary(); results = new Dictionary(); resultDate = new Dictionary(); runningEngineDate = new Dictionary(); bigLock = new object(); } public bool TryTakeEngine(out Guid guid, out byte[] engine) { lock(bigLock) { if(engineList.Count == 0) { guid = Guid.Empty; engine = null; return false; } else { guid = engineList[0]; engineList.RemoveAt(0); engine = waitingEngines[guid]; waitingEngines.Remove(guid); runningEngines[guid] = engine; runningEngineDate[guid] = DateTime.Now; return true; } } } public void StoreResult(Guid guid, byte[] result) { lock(bigLock) { // clear old results List expiredResults = FindExpiredResults(DateTime.Now.AddMinutes(-RESULT_EXPIRY_TIME_MIN)); foreach(Guid expiredGuid in expiredResults) { results.Remove(expiredGuid); waitHandles.Remove(expiredGuid); resultDate.Remove(expiredGuid); } // add the new result runningEngines.Remove(guid); runningEngineDate.Remove(guid); results[guid] = result; resultDate[guid] = DateTime.Now; waitHandles[guid].Set(); } } private List FindExpiredResults(DateTime expirationDate) { List expiredResults = new List(); foreach(Guid guid in results.Keys) { if(resultDate[guid] < expirationDate) { expiredResults.Add(guid); } } return expiredResults; } private List FindExpiredJobs(DateTime expirationDate) { List expiredJobs = new List(); foreach(Guid guid in runningEngines.Keys) { if(runningEngineDate[guid] < expirationDate) { expiredJobs.Add(guid); } } return expiredJobs; } internal void AddEngine(Guid guid, byte[] engine) { lock(bigLock) { engineList.Add(guid); waitingEngines.Add(guid, engine); waitHandles.Add(guid, new ManualResetEvent(false)); } } internal byte[] GetResult(Guid guid) { return GetResult(guid, System.Threading.Timeout.Infinite); } internal byte[] GetResult(Guid guid, int timeout) { lock(bigLock) { // result already available if(results.ContainsKey(guid)) { // if the wait-handle for this result is still alive then close and remove it if(waitHandles.ContainsKey(guid)) { ManualResetEvent waitHandle = waitHandles[guid]; waitHandle.Close(); waitHandles.Remove(guid); } byte[] result = results[guid]; results.Remove(guid); return result; } else { // result not yet available, if there is also no wait-handle for that result then we will never have a result and can return null if(!waitHandles.ContainsKey(guid)) return null; // otherwise we have a wait-handle and can wait for the result ManualResetEvent waitHandle = waitHandles[guid]; // wait if(waitHandle.WaitOne(timeout, true)) { // ok got the result in within the wait time => close and remove the wait-hande and return the result waitHandle.Close(); waitHandles.Remove(guid); byte[] result = results[guid]; return result; } else { // no result yet, check for which jobs we waited too long and requeue those jobs List expiredJobs = FindExpiredJobs(DateTime.Now.AddMinutes(-RUNNING_JOB_EXPIRY_TIME_MIN)); foreach(Guid expiredGuid in expiredJobs) { engineList.Insert(0, expiredGuid); waitingEngines[expiredGuid] = runningEngines[expiredGuid]; runningEngines.Remove(expiredGuid); runningEngineDate.Remove(expiredGuid); } return null; } } } } internal void AbortEngine(Guid guid) { throw new NotImplementedException(); } internal JobState JobState(Guid guid) { lock(bigLock) { if(waitingEngines.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Waiting; else if(waitHandles.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Busy; else if(results.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Finished; else return HeuristicLab.Grid.JobState.Unkown; } } } }