source: branches/HeuristicLab.Hive-3.4/sources/HeuristicLab.Clients.Hive/3.4/HiveJobs/HiveJob.cs @ 6419

Last change on this file since 6419 was 6419, checked in by cneumuel, 8 years ago

#1233

  • created events when statelog changed
  • fixed memory leak in hiveengine
  • extended timeout for long running transactions and database contexts (when jobdata is stored)
  • replaced random guids in database with sequential guids for performance reasons
  • minor fixes and cleanups
File size: 17.5 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.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Threading;
28using HeuristicLab.Collections;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
32using HeuristicLab.PluginInfrastructure;
33
34namespace HeuristicLab.Clients.Hive {
35
36  [Item("Hive Job", "Represents a hive job.")]
37  [StorableClass]
38  public class HiveJob : NamedItem, IItemTree<HiveJob> {
39    protected static object locker = new object();
40    protected ReaderWriterLockSlim childHiveJobsLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
41
42    public override Image ItemImage {
43      get {
44        if (job.Id == Guid.Empty) { // not yet uploaded
45          return HeuristicLab.Common.Resources.VSImageLibrary.Event;
46        } else {
47          if (job.State == JobState.Waiting) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutablePrepared;
48          else if (job.State == JobState.Calculating) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStarted;
49          else if (job.State == JobState.Transferring) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStarted;
50          else if (job.State == JobState.Paused) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutablePaused;
51          else if (job.State == JobState.Aborted) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStopped;
52          else if (job.State == JobState.Failed) return HeuristicLab.Common.Resources.VSImageLibrary.Error;
53          else if (job.State == JobState.Finished) return HeuristicLab.Common.Resources.VSImageLibrary.ExecutableStopped;
54          else return HeuristicLab.Common.Resources.VSImageLibrary.Event;
55        }
56      }
57    }
58
59    [Storable]
60    protected Job job;
61    public Job Job {
62      get { return job; }
63      set {
64        if (job != value) {
65          DeregisterJobEvents();
66          job = value;
67          RegisterJobEvents();
68          IsFinishedJobDownloaded = false;
69          OnJobChanged();
70          OnToStringChanged();
71          OnItemImageChanged();
72        }
73
74      }
75    }
76
77    [Storable]
78    protected ItemJob itemJob;
79    public ItemJob ItemJob {
80      get { return itemJob; }
81      set {
82        if (itemJob != null && syncJobsWithOptimizers) {
83          this.childHiveJobs.Clear();
84        }
85        if (itemJob != value) {
86          DergisterItemJobEvents();
87          itemJob = value;
88          RegisterItemJobEvents();
89          OnItemJobChanged();
90          IsFinishedJobDownloaded = true;
91        }
92      }
93    }
94
95    // job downloaded since last status change
96    [Storable]
97    private bool isFinishedJobDownloaded = false;
98    public bool IsFinishedJobDownloaded {
99      get { return isFinishedJobDownloaded; }
100      set {
101        if (value != isFinishedJobDownloaded) {
102          this.isFinishedJobDownloaded = value;
103          OnIsFinishedJobDownloadedChanged();
104        }
105      }
106    }
107
108    public bool IsDownloading { get; set; }
109
110    [Storable]
111    protected ItemList<HiveJob> childHiveJobs;
112    public virtual ReadOnlyItemList<HiveJob> ChildHiveJobs {
113      get {
114        childHiveJobsLock.EnterReadLock();
115        try {
116          return childHiveJobs.AsReadOnly();
117        }
118        finally { childHiveJobsLock.ExitReadLock(); }
119      }
120    }
121
122    [Storable]
123    protected bool syncJobsWithOptimizers = true;
124
125    public StateLogList StateLog {
126      get { return new StateLogList(this.job.StateLog); }
127    }
128
129    public StateLogListList ChildStateLogList {
130      get { return new StateLogListList(this.childHiveJobs.Select(x => x.StateLog)); }
131    }
132
133    #region Constructors and Cloning
134    public HiveJob() {
135      this.Job = new Job() { CoresNeeded = 1, MemoryNeeded = 0 };
136      job.State = JobState.Offline;
137      this.childHiveJobs = new ItemList<HiveJob>();
138      syncJobsWithOptimizers = true;
139      RegisterChildHiveJobEvents();
140    }
141
142    public HiveJob(ItemJob itemJob, bool autoCreateChildHiveJobs)
143      : this() {
144      this.syncJobsWithOptimizers = autoCreateChildHiveJobs;
145      this.ItemJob = itemJob;
146      this.syncJobsWithOptimizers = true;
147    }
148
149    public HiveJob(Job job, JobData jobData, bool autoCreateChildHiveJobs) {
150      this.syncJobsWithOptimizers = autoCreateChildHiveJobs;
151      this.Job = job;
152      try {
153        this.ItemJob = PersistenceUtil.Deserialize<ItemJob>(jobData.Data);
154      }
155      catch {
156        this.ItemJob = null;
157      }
158      this.childHiveJobs = new ItemList<HiveJob>();
159      this.syncJobsWithOptimizers = true;
160      RegisterChildHiveJobEvents();
161    }
162
163    protected HiveJob(HiveJob original, Cloner cloner)
164      : base(original, cloner) {
165      this.Job = cloner.Clone(original.job);
166      this.ItemJob = cloner.Clone(original.ItemJob);
167      original.childHiveJobsLock.EnterReadLock();
168      try {
169        this.childHiveJobs = cloner.Clone(original.childHiveJobs);
170      }
171      finally { original.childHiveJobsLock.ExitReadLock(); }
172      this.syncJobsWithOptimizers = original.syncJobsWithOptimizers;
173      this.isFinishedJobDownloaded = original.isFinishedJobDownloaded;
174    }
175    public override IDeepCloneable Clone(Cloner cloner) {
176      return new HiveJob(this, cloner);
177    }
178    #endregion
179
180    protected virtual void UpdateChildHiveJobs() { }
181
182    protected virtual void RegisterItemJobEvents() {
183      if (ItemJob != null) {
184        ItemJob.ComputeInParallelChanged += new EventHandler(ItemJob_ComputeInParallelChanged);
185        ItemJob.ToStringChanged += new EventHandler(ItemJob_ToStringChanged);
186      }
187    }
188    protected virtual void DergisterItemJobEvents() {
189      if (ItemJob != null) {
190        ItemJob.ComputeInParallelChanged -= new EventHandler(ItemJob_ComputeInParallelChanged);
191        ItemJob.ToStringChanged -= new EventHandler(ItemJob_ToStringChanged);
192      }
193    }
194
195    protected virtual void RegisterChildHiveJobEvents() {
196      this.childHiveJobs.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<HiveJob>>(OnItemsAdded);
197      this.childHiveJobs.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<HiveJob>>(OnItemsRemoved);
198      this.childHiveJobs.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<HiveJob>>(OnCollectionReset);
199    }
200    protected virtual void DeregisterChildHiveJobEvents() {
201      this.childHiveJobs.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<HiveJob>>(OnItemsAdded);
202      this.childHiveJobs.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<HiveJob>>(OnItemsRemoved);
203      this.childHiveJobs.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<HiveJob>>(OnCollectionReset);
204    }
205
206    protected virtual void ItemJob_ToStringChanged(object sender, EventArgs e) {
207      this.OnToStringChanged();
208    }
209
210    protected virtual void ItemJob_ComputeInParallelChanged(object sender, EventArgs e) {
211      if (ItemJob != null && syncJobsWithOptimizers) {
212        this.UpdateChildHiveJobs();
213      }
214    }
215
216    public virtual void AddChildHiveJob(HiveJob hiveJob) {
217      childHiveJobsLock.EnterWriteLock();
218      try {
219        this.childHiveJobs.Add(hiveJob);
220      }
221      finally { childHiveJobsLock.ExitWriteLock(); }
222    }
223
224    public override string ToString() {
225      if (itemJob != null && itemJob.Item != null) {
226        return itemJob.ToString();
227      } else {
228        return Job.Id.ToString();
229      }
230    }
231
232    public virtual void UpdateFromLightweightJob(LightweightJob lightweightJob) {
233      if (lightweightJob != null) {
234        job.Id = lightweightJob.Id;
235        job.ParentJobId = lightweightJob.ParentJobId;
236        job.ExecutionTime = lightweightJob.ExecutionTime;
237        job.State = lightweightJob.State;
238        job.StateLog = new List<StateLog>(lightweightJob.StateLog);
239        job.Command = lightweightJob.Command;
240
241        OnJobStateChanged();
242        OnToStringChanged();
243        OnItemImageChanged();
244        OnStateLogChanged();
245      }
246    }
247
248    /// <summary>
249    /// Creates a JobData object containing the Job and the IJob-Object as byte[]
250    /// </summary>
251    /// <param name="withoutChildOptimizers">
252    ///   if true the Child-Optimizers will not be serialized (if the job contains an Experiment)
253    /// </param>
254    public virtual JobData GetAsJobData(bool withoutChildOptimizers, out List<IPluginDescription> plugins) {
255      plugins = new List<IPluginDescription>();
256      if (this.itemJob == null)
257        return null;
258
259      IEnumerable<Type> usedTypes;
260      byte[] jobByteArray = PersistenceUtil.Serialize(this.ItemJob, out usedTypes);
261      JobData jobData = new JobData() { JobId = job.Id, Data = jobByteArray };
262      PluginUtil.CollectDeclaringPlugins(plugins, usedTypes);
263      return jobData;
264    }
265
266    #region Event Handler
267    public event EventHandler JobChanged;
268    private void OnJobChanged() {
269      EventHandler handler = JobChanged;
270      if (handler != null) handler(this, EventArgs.Empty);
271    }
272
273    public event EventHandler JobStateChanged;
274    private void OnJobStateChanged() {
275      EventHandler handler = JobStateChanged;
276      if (handler != null) handler(this, EventArgs.Empty);
277    }
278
279    public event EventHandler ItemJobChanged;
280    private void OnItemJobChanged() {
281      ItemJob_ComputeInParallelChanged(this, EventArgs.Empty);
282      var handler = ItemJobChanged;
283      if (handler != null) handler(this, EventArgs.Empty);
284    }
285
286    public event EventHandler IsFinishedJobDownloadedChanged;
287    private void OnIsFinishedJobDownloadedChanged() {
288      var handler = IsFinishedJobDownloadedChanged;
289      if (handler != null) handler(this, EventArgs.Empty);
290    }
291
292    public event EventHandler StateLogChanged;
293    private void OnStateLogChanged() {
294      var handler = StateLogChanged;
295      if (handler != null) handler(this, EventArgs.Empty);
296    }
297
298    private void RegisterJobEvents() {
299      if (job != null)
300        job.PropertyChanged += new PropertyChangedEventHandler(job_PropertyChanged);
301    }
302
303    private void DeregisterJobEvents() {
304      if (job != null)
305        job.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(job_PropertyChanged);
306    }
307
308    private void job_PropertyChanged(object sender, PropertyChangedEventArgs e) {
309      if (e.PropertyName == "State") {
310        IsFinishedJobDownloaded = false;
311      }
312    }
313    #endregion
314
315    /// <summary>
316    /// Returns a list of HiveJobs including this and all its child-jobs recursively
317    /// </summary>
318    public IEnumerable<HiveJob> GetAllHiveJobs() {
319      childHiveJobsLock.EnterReadLock();
320      try {
321        var jobs = new List<HiveJob>();
322        jobs.Add(this);
323        foreach (HiveJob child in this.childHiveJobs) {
324          jobs.AddRange(child.GetAllHiveJobs());
325        }
326        return jobs;
327      }
328      finally { childHiveJobsLock.ExitReadLock(); }
329    }
330
331    public HiveJob GetParentByJobId(Guid jobId) {
332      childHiveJobsLock.EnterReadLock();
333      try {
334        if (this.ChildHiveJobs.SingleOrDefault(j => j.job.Id == jobId) != null)
335          return this;
336        foreach (HiveJob child in this.childHiveJobs) {
337          HiveJob result = child.GetParentByJobId(jobId);
338          if (result != null)
339            return result;
340        }
341        return null;
342      }
343      finally { childHiveJobsLock.ExitWriteLock(); }
344    }
345
346    /// <summary>
347    /// Searches for an HiveJob object with the correct jobId recursively
348    /// </summary>
349    public HiveJob GetHiveJobByJobId(Guid jobId) {
350      if (this.Job.Id == jobId) {
351        return this;
352      } else {
353        childHiveJobsLock.EnterReadLock();
354        try {
355          foreach (HiveJob child in this.childHiveJobs) {
356            HiveJob result = child.GetHiveJobByJobId(jobId);
357            if (result != null)
358              return result;
359          }
360        }
361        finally { childHiveJobsLock.ExitReadLock(); }
362      }
363      return null;
364    }
365
366    public void RemoveByJobId(Guid jobId) {
367      childHiveJobsLock.EnterWriteLock();
368      try {
369        IEnumerable<HiveJob> jobs = childHiveJobs.Where(j => j.Job.Id == jobId).ToList();
370        foreach (HiveJob j in jobs) {
371          this.childHiveJobs.Remove(j);
372        }
373        foreach (HiveJob child in childHiveJobs) {
374          child.RemoveByJobId(jobId);
375        }
376      }
377      finally { childHiveJobsLock.ExitWriteLock(); }
378    }
379
380    public IEnumerable<IItemTree<HiveJob>> GetChildItems() {
381      return this.ChildHiveJobs;
382    }
383
384    #region INotifyObservableCollectionItemsChanged<IItemTree> Members
385
386    public event CollectionItemsChangedEventHandler<IItemTree<HiveJob>> CollectionReset;
387    private void OnCollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<HiveJob>> e) {
388      foreach (var item in e.Items) {
389        item.Value.StateLogChanged -= new EventHandler(ChildHiveJob_StateLogChanged);
390      }
391      var handler = CollectionReset;
392      if (handler != null) handler(this, ToCollectionItemsChangedEventArgs(e));
393    }
394
395    public event CollectionItemsChangedEventHandler<IItemTree<HiveJob>> ItemsAdded;
396    private void OnItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<HiveJob>> e) {
397      foreach (var item in e.Items) {
398        item.Value.StateLogChanged += new EventHandler(ChildHiveJob_StateLogChanged);
399      }
400      var handler = ItemsAdded;
401      if (handler != null) handler(this, ToCollectionItemsChangedEventArgs(e));
402    }
403
404    public event CollectionItemsChangedEventHandler<IItemTree<HiveJob>> ItemsRemoved;
405    private void OnItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<HiveJob>> e) {
406      foreach (var item in e.Items) {
407        item.Value.StateLogChanged -= new EventHandler(ChildHiveJob_StateLogChanged);
408      }
409      var handler = ItemsRemoved;
410      if (handler != null) handler(this, ToCollectionItemsChangedEventArgs(e));
411    }
412
413    private static CollectionItemsChangedEventArgs<IItemTree<HiveJob>> ToCollectionItemsChangedEventArgs(CollectionItemsChangedEventArgs<IndexedItem<HiveJob>> e) {
414      return new CollectionItemsChangedEventArgs<IItemTree<HiveJob>>(e.Items.Select(x => x.Value), e.OldItems == null ? null : e.OldItems.Select(x => x.Value));
415    }
416
417    private void ChildHiveJob_StateLogChanged(object sender, EventArgs e) {
418      OnStateLogChanged();
419    }
420    #endregion
421
422    public void Pause() {
423      if (this.Job.IsParentJob) {
424        childHiveJobsLock.EnterReadLock();
425        try {
426          foreach (var child in childHiveJobs) {
427            ServiceLocator.Instance.CallHiveService(s => s.PauseJob(child.job.Id));
428          }
429        }
430        finally { childHiveJobsLock.ExitReadLock(); }
431      } else {
432        ServiceLocator.Instance.CallHiveService(s => s.PauseJob(this.job.Id));
433      }
434    }
435
436    public void Stop() {
437      if (this.Job.IsParentJob) {
438        childHiveJobsLock.EnterReadLock();
439        try {
440          foreach (var child in childHiveJobs) {
441            ServiceLocator.Instance.CallHiveService(s => s.StopJob(child.job.Id));
442          }
443        }
444        finally { childHiveJobsLock.ExitReadLock(); }
445      } else {
446        ServiceLocator.Instance.CallHiveService(s => s.StopJob(this.job.Id));
447      }
448    }
449
450    public void Restart() {
451      ServiceLocator.Instance.CallHiveService(service => {
452        JobData jobData = new JobData();
453        jobData.JobId = this.job.Id;
454        jobData.Data = PersistenceUtil.Serialize(this.itemJob);
455        service.UpdateJobData(this.Job, jobData);
456        service.RestartJob(this.job.Id);
457        Job job = service.GetJob(this.job.Id);
458        this.job.LastJobDataUpdate = job.LastJobDataUpdate;
459      });
460    }
461
462    public ICollection<IItemTreeNodeAction<HiveJob>> Actions {
463      get {
464        return new List<IItemTreeNodeAction<HiveJob>>();
465      }
466    }
467
468    public virtual void IntegrateChild(ItemJob job, Guid childJobId) { }
469
470    /// <summary>
471    /// Delete ItemJob
472    /// </summary>
473    public virtual void ClearData() {
474      this.ItemJob.Item = null;
475    }
476  }
477
478  [Item("Hive Job", "Represents a hive job.")]
479  [StorableClass]
480  public class HiveJob<T> : HiveJob where T : ItemJob {
481
482    public new T ItemJob {
483      get { return (T)base.ItemJob; }
484      internal set { base.ItemJob = value; }
485    }
486
487    #region Constructors and Cloning
488    public HiveJob() : base() { }
489    public HiveJob(T itemJob) : base(itemJob, true) { }
490    protected HiveJob(HiveJob original, Cloner cloner)
491      : base(original, cloner) {
492    }
493    public override IDeepCloneable Clone(Cloner cloner) {
494      return new HiveJob<T>(this, cloner);
495    }
496    #endregion
497  }
498}
Note: See TracBrowser for help on using the repository browser.