Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 6371 was 6371, checked in by ascheibe, 13 years ago

#1233

  • code cleanups for slave review
  • added switch between privileged and unprivileged sandbox
  • removed childjob management because it's not used
File size: 6.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 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.Threading;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using HeuristicLab.Hive;
27
28namespace HeuristicLab.Clients.Hive.SlaveCore {
29  /// <summary>
30  /// The executor runs in the appdomain and handles the execution of an Hive job.
31  /// </summary>
32  public class Executor : MarshalByRefObject, IDisposable {
33    public Guid JobId { get; set; }
34    private IJob Job { get; set; }
35    public int CoresNeeded { get; set; }
36    public int MemoryNeeded { get; set; }
37    private bool wasJobAborted = false;
38    private Semaphore pauseStopSem = new Semaphore(0, 1);
39    private Semaphore startJobSem = new Semaphore(0, 1);
40    //make pause or stop wait until start is finished
41    private Semaphore jobStartedSem = new Semaphore(0, 1);
42    private ExecutorQueue executorQueue;
43    public ExecutorQueue ExecutorCommandQueue {
44      get {
45        return executorQueue;
46      }
47    }
48    public bool IsStopping { get; set; }
49    public bool IsPausing { get; set; }
50    private DateTime CreationTime { get; set; }
51    private Exception currentException;
52    public String CurrentException {
53      get {
54        if (currentException != null) {
55          return currentException.ToString();
56        } else {
57          return string.Empty;
58        }
59      }
60    }
61
62    private ExecutionState ExecutionState {
63      get {
64        return Job != null ? Job.ExecutionState : HeuristicLab.Core.ExecutionState.Stopped;
65      }
66    }
67
68    public TimeSpan ExecutionTime {
69      get {
70        return Job != null ? Job.ExecutionTime : new TimeSpan(0, 0, 0);
71      }
72    }
73
74    public Executor() {
75      IsStopping = false;
76      IsPausing = false;
77      executorQueue = new ExecutorQueue();
78    }
79
80    public void Start(byte[] serializedJob) {
81      try {
82        CreationTime = DateTime.Now;
83        Job = PersistenceUtil.Deserialize<IJob>(serializedJob);
84
85        RegisterJobEvents();
86
87        Job.Start();
88        if (!jobStartedSem.WaitOne(TimeSpan.FromSeconds(15))) {
89          throw new TimeoutException("Timeout when starting the job. JobStarted event was not fired.");
90        }
91        jobStartedSem.Release();
92      }
93      catch (Exception e) {
94        this.currentException = e;
95        Job_JobFailed(this, new EventArgs<Exception>(e));
96      }
97    }
98
99    public void Pause() {
100      IsPausing = true;
101      // wait until job is started. if this does not happen, the Job is null an we give up
102      jobStartedSem.WaitOne(TimeSpan.FromSeconds(15));
103      if (Job == null) {
104        currentException = new Exception("Pausing job " + this.JobId + ": Job is null");
105        return;
106      }
107
108      if (Job.ExecutionState == ExecutionState.Started) {
109        try {
110          Job.Pause();
111          //we need to block the pause...
112          pauseStopSem.WaitOne();
113        }
114        catch (Exception ex) {
115          currentException = new Exception("Error pausing job " + this.JobId + ": " + ex.ToString());
116        }
117      }
118    }
119
120    public void Stop() {
121      IsStopping = true;
122      // wait until job is started. if this does not happen, the Job is null an we give up
123      jobStartedSem.WaitOne(TimeSpan.FromSeconds(15));
124      if (Job == null) {
125        currentException = new Exception("Stopping job " + this.JobId + ": Job is null");
126      }
127      wasJobAborted = true;
128
129      if ((ExecutionState == ExecutionState.Started) || (ExecutionState == ExecutionState.Paused)) {
130        try {
131          Job.Stop();
132          pauseStopSem.WaitOne();
133        }
134        catch (Exception ex) {
135          currentException = new Exception("Error stopping job " + this.JobId + ": " + ex.ToString());
136        }
137      }
138    }
139
140    private void RegisterJobEvents() {
141      Job.JobStopped += new EventHandler(Job_JobStopped);
142      Job.JobFailed += new EventHandler(Job_JobFailed);
143      Job.JobPaused += new EventHandler(Job_JobPaused);
144      Job.JobStarted += new EventHandler(Job_JobStarted);
145    }
146
147    private void DeregisterJobEvents() {
148      Job.JobStopped -= new EventHandler(Job_JobStopped);
149      Job.JobFailed -= new EventHandler(Job_JobFailed);
150      Job.JobPaused -= new EventHandler(Job_JobPaused);
151      Job.JobStarted -= new EventHandler(Job_JobStarted);
152    }
153
154    #region Job Events
155    private void Job_JobFailed(object sender, EventArgs e) {
156      EventArgs<Exception> ex = (EventArgs<Exception>)e;
157      currentException = ex.Value;
158
159      executorQueue.AddMessage(ExecutorMessageType.JobFailed);
160    }
161
162    private void Job_JobStopped(object sender, EventArgs e) {
163      if (wasJobAborted)
164        pauseStopSem.Release();
165
166      executorQueue.AddMessage(ExecutorMessageType.JobStopped);
167    }
168
169    private void Job_JobPaused(object sender, EventArgs e) {
170      pauseStopSem.Release();
171      executorQueue.AddMessage(ExecutorMessageType.JobPaused);
172    }
173
174    private void Job_JobStarted(object sender, EventArgs e) {
175      jobStartedSem.Release();
176      executorQueue.AddMessage(ExecutorMessageType.JobStarted);
177    }
178    #endregion
179
180    public JobData GetJobData() {
181      if (Job.ExecutionState == ExecutionState.Started) {
182        throw new InvalidStateException("Job is still running");
183      } else {
184        JobData jobData = new JobData();
185        if (Job == null) {
186          //send empty job and save exception
187          jobData.Data = PersistenceUtil.Serialize(new JobData());
188          if (currentException == null) {
189            currentException = new Exception("Job with id " + this.JobId + " is null, sending empty job");
190          }
191        } else {
192          jobData.Data = PersistenceUtil.Serialize(Job);
193        }
194        jobData.JobId = JobId;
195        return jobData;
196      }
197    }
198
199    public void Dispose() {
200      if (Job != null)
201        DeregisterJobEvents();
202      Job = null;
203    }
204  }
205}
Note: See TracBrowser for help on using the repository browser.