source: branches/HeuristicLab.Hive-3.4/sources/HeuristicLab.Clients.Hive.Slave/3.4/Executor.cs @ 5826

Last change on this file since 5826 was 5826, checked in by ascheibe, 9 years ago

#1233 slave ui now receives status information and displays it in doughnut chart

File size: 8.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 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
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using System.Threading;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Hive;
29using HeuristicLab.PluginInfrastructure;
30
31
32namespace HeuristicLab.Clients.Hive.SlaveCore {
33  public class Executor : MarshalByRefObject, IDisposable {
34    public Guid JobId { get; set; }
35    public IJob Job { get; set; }
36    private bool wasJobAborted = false;
37    public Core Core { get; set; }
38    private Semaphore pauseStopSem = new Semaphore(0, 1);
39
40    public bool Aborted { get; set; }
41
42    private Exception currentException;
43    public String CurrentException {
44      get {
45        if (currentException != null) {
46          return currentException.ToString();
47        } else {
48          return string.Empty;
49        }
50      }
51    }
52
53    public ExecutionState ExecutionState {
54      get {
55        return Job != null ? Job.ExecutionState : HeuristicLab.Core.ExecutionState.Stopped;
56      }
57    }
58
59    public TimeSpan ExecutionTime {
60      get {
61        return Job != null ? Job.ExecutionTime : new TimeSpan(0, 0, 0);
62      }
63    }
64
65    public DateTime CreationTime { get; set; }
66
67    /// <param name="serializedJob"></param>
68    /// <param name="collectChildJobs">if true, all child-jobs are downloaded and the job will be resumed.</param>
69    public void Start(byte[] serializedJob) {
70      try {
71        CreationTime = DateTime.Now;
72        Aborted = false;
73        Job = PersistenceUtil.Deserialize<IJob>(serializedJob);
74
75        RegisterJobEvents();
76
77        if (Job.CollectChildJobs) {
78          IEnumerable<JobData> childjobs = WcfService.Instance.GetChildJobs(JobId);
79          Job.Resume(childjobs.Select(j => PersistenceUtil.Deserialize<IJob>(j.Data)));
80        } else {
81          // Job.Prepare(); // do NOT prepare here, otherwise paused jobs get restarted
82          Job.Start();
83        }
84      }
85      catch (Exception e) {
86        this.currentException = e;
87        Job_JobFailed(this, new HeuristicLab.Common.EventArgs<Exception>(e));
88      }
89    }
90
91    public void Pause() {
92      if (Job == null) {
93        SlaveClientCom.Instance.ClientCom.LogMessage("Pausing job: Job is null");
94        Core.EnqueueExecutorMessage(Core.KillAppDomain, JobId);
95      }
96
97      if (Job.ExecutionState == HeuristicLab.Core.ExecutionState.Started) {
98        try {
99          Job.Pause();
100          //we need to block the pause...
101          pauseStopSem.WaitOne();
102        }
103        catch (Exception ex) {
104          SlaveClientCom.Instance.ClientCom.LogMessage("Error pausing job:" + ex.ToString());
105        }
106      }
107    }
108
109    public void Stop() {
110      if (Job == null) {
111        SlaveClientCom.Instance.ClientCom.LogMessage("Stopping job: Job is null");
112        Core.EnqueueExecutorMessage(Core.KillAppDomain, JobId);
113      }
114      wasJobAborted = true;
115
116      if ((ExecutionState == ExecutionState.Started) || (ExecutionState == ExecutionState.Paused)) {
117        try {
118          Job.Stop();
119          pauseStopSem.WaitOne();
120        }
121        catch (Exception ex) {
122          SlaveClientCom.Instance.ClientCom.LogMessage("Error stopping job:" + ex.ToString());
123        }
124      }
125    }
126
127    private void RegisterJobEvents() {
128      Job.JobStopped += new EventHandler(Job_JobStopped);
129      Job.JobFailed += new EventHandler(Job_JobFailed);
130      Job.NewChildJob += new EventHandler<EventArgs<IJob>>(Job_NewChildJob);
131      Job.WaitForChildJobs += new EventHandler(Job_WaitForChildJobs);
132      Job.DeleteChildJobs += new EventHandler(Job_DeleteChildJobs);
133      Job.JobPaused += new EventHandler(Job_JobPaused);
134    }
135
136    private void DeregisterJobEvents() {
137      Job.JobStopped -= new EventHandler(Job_JobStopped);
138      Job.JobFailed -= new EventHandler(Job_JobFailed);
139      Job.NewChildJob -= new EventHandler<EventArgs<IJob>>(Job_NewChildJob);
140      Job.WaitForChildJobs -= new EventHandler(Job_WaitForChildJobs);
141      Job.DeleteChildJobs -= new EventHandler(Job_DeleteChildJobs);
142      Job.JobPaused -= new EventHandler(Job_JobPaused);
143    }
144
145    private List<Guid> FindPluginsNeeded(IJob obj) {
146      List<Guid> guids = new List<Guid>();
147      foreach (IPluginDescription desc in PluginUtil.GetDeclaringPlugins(obj)) {
148      }
149      throw new NotImplementedException("FindPluginsNeeded for Job_NewChildJob");
150
151      return guids;
152    }
153
154    private void Job_NewChildJob(object sender, EventArgs<IJob> e) {
155      JobData childJobData = new JobData();
156      childJobData.Data = PersistenceUtil.Serialize(e.Value);
157
158      Job childJob = new Job();
159      childJob.CoresNeeded = 1;
160      childJob.MemoryNeeded = 0;
161      childJob.PluginsNeededIds = FindPluginsNeeded(e.Value);
162
163      //TODO: is return value needed?
164      WcfService.Instance.AddChildJob(this.JobId, childJob, childJobData);
165    }
166
167    private void Job_WaitForChildJobs(object sender, EventArgs e) {
168      // Pause the job and send it back to the hive. The server will awake it when all child-jobs are finished
169      this.Job.CollectChildJobs = true;
170
171      JobData jdata = new JobData();
172      jdata.Data = PersistenceUtil.Serialize(Job);
173      jdata.JobId = this.JobId;
174
175      Core.PauseWaitJob(jdata);
176    }
177
178    private void Job_DeleteChildJobs(object sender, EventArgs e) {
179      WcfService.Instance.DeleteChildJobs(JobId);
180    }
181
182    private void Job_JobFailed(object sender, EventArgs e) {
183      //TODO: get exception to client
184      HeuristicLab.Common.EventArgs<Exception> ex = (HeuristicLab.Common.EventArgs<Exception>)e;
185      currentException = ex.Value;
186      Core.EnqueueExecutorMessage(Core.SendFinishedJob, JobId);
187      Aborted = true;
188    }
189
190    private void Job_JobStopped(object sender, EventArgs e) {
191      if (wasJobAborted) {
192        pauseStopSem.Release();
193        Aborted = true;
194      } else {
195        //it's a clean and finished job, so send it       
196        Core.EnqueueExecutorMessage(Core.SendFinishedJob, JobId);
197      }
198    }
199
200    public JobData GetFinishedJob() {
201      if (Job == null) {
202        SlaveClientCom.Instance.ClientCom.LogMessage("Getting finished job: Job is null");
203        Core.EnqueueExecutorMessage(Core.KillAppDomain, JobId);
204      }
205
206      if (Job.ExecutionState == HeuristicLab.Core.ExecutionState.Started) {
207        try {
208          Job.Stop();
209          wasJobAborted = true;
210          pauseStopSem.WaitOne();
211        }
212        catch (Exception ex) {
213          SlaveClientCom.Instance.ClientCom.LogMessage("Error stopping job:" + ex.ToString());
214        }
215      }
216
217      return GetJob();
218    }
219
220
221    public JobData GetPausedJob() {
222      if (Job.ExecutionState != HeuristicLab.Core.ExecutionState.Paused) {
223        throw new Exception("Executor: Job has to be paused before fetching results.");
224      }
225      return GetJob();
226    }
227
228    private void Job_JobPaused(object sender, EventArgs e) {
229      pauseStopSem.Release();
230    }
231
232    private JobData GetJob() {
233      if (Job.ExecutionState == HeuristicLab.Core.ExecutionState.Started) {
234        throw new InvalidStateException("Job is still running");
235      } else {
236        JobData jdata = new JobData();
237        jdata.Data = PersistenceUtil.Serialize(Job);
238        jdata.JobId = JobId;
239        return jdata;
240      }
241    }
242
243    public Executor() {
244    }
245
246    public void Dispose() {
247      if (Job != null)
248        DeregisterJobEvents();
249      Job = null;
250    }
251  }
252}
Note: See TracBrowser for help on using the repository browser.