[2] | 1 | #region License Information
|
---|
| 2 | /* HeuristicLab
|
---|
| 3 | * Copyright (C) 2002-2008 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
| 4 | *
|
---|
| 5 | * This file is part of HeuristicLab.
|
---|
| 6 | *
|
---|
| 7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
| 8 | * it under the terms of the GNU General Public License as published by
|
---|
| 9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 10 | * (at your option) any later version.
|
---|
| 11 | *
|
---|
| 12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 15 | * GNU General Public License for more details.
|
---|
| 16 | *
|
---|
| 17 | * You should have received a copy of the GNU General Public License
|
---|
| 18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 19 | */
|
---|
| 20 | #endregion
|
---|
| 21 |
|
---|
| 22 | using System;
|
---|
| 23 | using System.Collections.Generic;
|
---|
| 24 | using System.Text;
|
---|
| 25 | using System.Threading;
|
---|
| 26 | using System.ServiceModel;
|
---|
| 27 |
|
---|
| 28 | namespace HeuristicLab.Grid {
|
---|
[32] | 29 | [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
|
---|
[2] | 30 | public class EngineStore : IEngineStore {
|
---|
[34] | 31 | private List<Guid> engineList;
|
---|
[2] | 32 | private Dictionary<Guid, byte[]> waitingEngines;
|
---|
[245] | 33 | private Dictionary<Guid, byte[]> runningEngines;
|
---|
[33] | 34 | private Dictionary<Guid, ManualResetEvent> waitHandles;
|
---|
[2] | 35 | private Dictionary<Guid, byte[]> results;
|
---|
[219] | 36 | private Dictionary<Guid, DateTime> resultDate;
|
---|
[245] | 37 | private Dictionary<Guid, DateTime> runningEngineDate;
|
---|
| 38 | private const int RESULT_EXPIRY_TIME_MIN = 10;
|
---|
| 39 | private const int RUNNING_JOB_EXPIRY_TIME_MIN = 10;
|
---|
[2] | 40 | private object bigLock;
|
---|
| 41 | public int WaitingJobs {
|
---|
| 42 | get {
|
---|
| 43 | return waitingEngines.Count;
|
---|
| 44 | }
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | public int RunningJobs {
|
---|
| 48 | get {
|
---|
[250] | 49 | return runningEngines.Count;
|
---|
[2] | 50 | }
|
---|
| 51 | }
|
---|
| 52 |
|
---|
| 53 | public int WaitingResults {
|
---|
| 54 | get {
|
---|
| 55 | return results.Count;
|
---|
| 56 | }
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | public EngineStore() {
|
---|
[34] | 60 | engineList = new List<Guid>();
|
---|
[2] | 61 | waitingEngines = new Dictionary<Guid, byte[]>();
|
---|
[245] | 62 | runningEngines = new Dictionary<Guid, byte[]>();
|
---|
[33] | 63 | waitHandles = new Dictionary<Guid, ManualResetEvent>();
|
---|
[2] | 64 | results = new Dictionary<Guid, byte[]>();
|
---|
[219] | 65 | resultDate = new Dictionary<Guid, DateTime>();
|
---|
[245] | 66 | runningEngineDate = new Dictionary<Guid, DateTime>();
|
---|
[2] | 67 | bigLock = new object();
|
---|
| 68 | }
|
---|
| 69 |
|
---|
[219] | 70 | public bool TryTakeEngine(out Guid guid, out byte[] engine) {
|
---|
[32] | 71 | lock(bigLock) {
|
---|
[34] | 72 | if(engineList.Count == 0) {
|
---|
[2] | 73 | guid = Guid.Empty;
|
---|
| 74 | engine = null;
|
---|
| 75 | return false;
|
---|
| 76 | } else {
|
---|
[34] | 77 | guid = engineList[0];
|
---|
| 78 | engineList.RemoveAt(0);
|
---|
[2] | 79 | engine = waitingEngines[guid];
|
---|
| 80 | waitingEngines.Remove(guid);
|
---|
[245] | 81 | runningEngines[guid] = engine;
|
---|
| 82 | runningEngineDate[guid] = DateTime.Now;
|
---|
[2] | 83 | return true;
|
---|
| 84 | }
|
---|
| 85 | }
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | public void StoreResult(Guid guid, byte[] result) {
|
---|
[32] | 89 | lock(bigLock) {
|
---|
[219] | 90 | // clear old results
|
---|
[245] | 91 | List<Guid> expiredResults = FindExpiredResults(DateTime.Now.AddMinutes(-RESULT_EXPIRY_TIME_MIN));
|
---|
[219] | 92 | foreach(Guid expiredGuid in expiredResults) {
|
---|
| 93 | results.Remove(expiredGuid);
|
---|
| 94 | waitHandles.Remove(expiredGuid);
|
---|
| 95 | resultDate.Remove(expiredGuid);
|
---|
| 96 | }
|
---|
| 97 | // add the new result
|
---|
[245] | 98 | runningEngines.Remove(guid);
|
---|
| 99 | runningEngineDate.Remove(guid);
|
---|
[2] | 100 | results[guid] = result;
|
---|
[219] | 101 | resultDate[guid] = DateTime.Now;
|
---|
[33] | 102 | waitHandles[guid].Set();
|
---|
[2] | 103 | }
|
---|
| 104 | }
|
---|
| 105 |
|
---|
[219] | 106 | private List<Guid> FindExpiredResults(DateTime expirationDate) {
|
---|
| 107 | List<Guid> expiredResults = new List<Guid>();
|
---|
| 108 | foreach(Guid guid in results.Keys) {
|
---|
| 109 | if(resultDate[guid] < expirationDate) {
|
---|
| 110 | expiredResults.Add(guid);
|
---|
| 111 | }
|
---|
| 112 | }
|
---|
| 113 | return expiredResults;
|
---|
| 114 | }
|
---|
[245] | 115 | private List<Guid> FindExpiredJobs(DateTime expirationDate) {
|
---|
| 116 | List<Guid> expiredJobs = new List<Guid>();
|
---|
| 117 | foreach(Guid guid in runningEngines.Keys) {
|
---|
| 118 | if(runningEngineDate[guid] < expirationDate) {
|
---|
| 119 | expiredJobs.Add(guid);
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 | return expiredJobs;
|
---|
| 123 | }
|
---|
[219] | 124 |
|
---|
[2] | 125 | internal void AddEngine(Guid guid, byte[] engine) {
|
---|
[32] | 126 | lock(bigLock) {
|
---|
[34] | 127 | engineList.Add(guid);
|
---|
[2] | 128 | waitingEngines.Add(guid, engine);
|
---|
[33] | 129 | waitHandles.Add(guid, new ManualResetEvent(false));
|
---|
[2] | 130 | }
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | internal byte[] GetResult(Guid guid) {
|
---|
[33] | 134 | return GetResult(guid, System.Threading.Timeout.Infinite);
|
---|
| 135 | }
|
---|
[219] | 136 |
|
---|
[33] | 137 | internal byte[] GetResult(Guid guid, int timeout) {
|
---|
[32] | 138 | lock(bigLock) {
|
---|
[219] | 139 | // result already available
|
---|
| 140 | if(results.ContainsKey(guid)) {
|
---|
| 141 | // if the wait-handle for this result is still alive then close and remove it
|
---|
| 142 | if(waitHandles.ContainsKey(guid)) {
|
---|
| 143 | ManualResetEvent waitHandle = waitHandles[guid];
|
---|
| 144 | waitHandle.Close();
|
---|
| 145 | waitHandles.Remove(guid);
|
---|
| 146 | }
|
---|
[254] | 147 | byte[] result = results[guid];
|
---|
| 148 | results.Remove(guid);
|
---|
| 149 | return result;
|
---|
[219] | 150 | } else {
|
---|
| 151 | // 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
|
---|
| 152 | if(!waitHandles.ContainsKey(guid)) return null;
|
---|
| 153 | // otherwise we have a wait-handle and can wait for the result
|
---|
[33] | 154 | ManualResetEvent waitHandle = waitHandles[guid];
|
---|
[219] | 155 | // wait
|
---|
[35] | 156 | if(waitHandle.WaitOne(timeout, true)) {
|
---|
[219] | 157 | // ok got the result in within the wait time => close and remove the wait-hande and return the result
|
---|
[33] | 158 | waitHandle.Close();
|
---|
| 159 | waitHandles.Remove(guid);
|
---|
| 160 | byte[] result = results[guid];
|
---|
| 161 | return result;
|
---|
| 162 | } else {
|
---|
[245] | 163 | // no result yet, check for which jobs we waited too long and requeue those jobs
|
---|
| 164 | List<Guid> expiredJobs = FindExpiredJobs(DateTime.Now.AddMinutes(-RUNNING_JOB_EXPIRY_TIME_MIN));
|
---|
| 165 | foreach(Guid expiredGuid in expiredJobs) {
|
---|
| 166 | engineList.Insert(0, expiredGuid);
|
---|
| 167 | waitingEngines[expiredGuid] = runningEngines[expiredGuid];
|
---|
| 168 | runningEngines.Remove(expiredGuid);
|
---|
| 169 | runningEngineDate.Remove(expiredGuid);
|
---|
| 170 | }
|
---|
[33] | 171 | return null;
|
---|
| 172 | }
|
---|
[2] | 173 | }
|
---|
| 174 | }
|
---|
| 175 | }
|
---|
| 176 |
|
---|
[32] | 177 | internal void AbortEngine(Guid guid) {
|
---|
[245] | 178 | throw new NotImplementedException();
|
---|
[32] | 179 | }
|
---|
[219] | 180 |
|
---|
| 181 | internal JobState JobState(Guid guid) {
|
---|
| 182 | lock(bigLock) {
|
---|
| 183 | if(waitingEngines.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Waiting;
|
---|
| 184 | else if(waitHandles.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Busy;
|
---|
| 185 | else if(results.ContainsKey(guid)) return HeuristicLab.Grid.JobState.Finished;
|
---|
| 186 | else return HeuristicLab.Grid.JobState.Unkown;
|
---|
| 187 | }
|
---|
| 188 | }
|
---|
[2] | 189 | }
|
---|
| 190 | }
|
---|