Free cookie consent management tool by TermsFeed Policy Generator

source: branches/ScatterSearch (trunk integration)/HeuristicLab.Clients.Hive/3.3/RefreshableJob.cs @ 7955

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

#1722 fixed a NullReferenceException in Hive JobManager

File size: 22.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2012 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 HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.MainForm;
31
32namespace HeuristicLab.Clients.Hive {
33  public class RefreshableJob : IHiveItem, IDeepCloneable, IContent, IProgressReporter, IComparable<RefreshableJob> {
34    private JobResultPoller jobResultPoller;
35    private ConcurrentTaskDownloader<ItemTask> jobDownloader;
36    private static object locker = new object();
37
38    private Job job;
39    public Job Job {
40      get { return job; }
41      set {
42        if (value != job) {
43          if (value == null)
44            throw new ArgumentNullException();
45
46          if (job != null) DergisterJobEvents();
47          job = value;
48          if (job != null) {
49            RegisterJobEvents();
50            job_PropertyChanged(job, new PropertyChangedEventArgs("Id"));
51          }
52          OnJobChanged();
53          OnToStringChanged(this, EventArgs.Empty);
54          job_ItemImageChanged(this, EventArgs.Empty);
55        }
56      }
57    }
58
59    private ItemCollection<HiveTask> hiveTasks;
60    public ItemCollection<HiveTask> HiveTasks {
61      get { return hiveTasks; }
62      set {
63        if (hiveTasks != value) {
64          if (hiveTasks != null) DeregisterHiveJobsEvents();
65          hiveTasks = value;
66          if (hiveTasks != null) RegisterHiveJobsEvents();
67          OnHiveTasksChanged();
68        }
69      }
70    }
71
72    private ExecutionState executionState;
73    public ExecutionState ExecutionState {
74      get { return executionState; }
75      internal set {
76        if (executionState != value) {
77          executionState = value;
78          OnExecutionStateChanged();
79        }
80      }
81    }
82
83    private TimeSpan executionTime;
84    public TimeSpan ExecutionTime {
85      get { return executionTime; }
86      internal set {
87        if (executionTime != value) {
88          executionTime = value;
89          OnExecutionTimeChanged();
90        }
91      }
92    }
93
94    private bool refreshAutomatically;
95    public bool RefreshAutomatically {
96      get { return refreshAutomatically; }
97      set {
98        lock (locker) {
99          if (refreshAutomatically != value) {
100            refreshAutomatically = value;
101            OnRefreshAutomaticallyChanged();
102          }
103          if (RefreshAutomatically) {
104            if (this.HiveTasks != null && this.HiveTasks.Count > 0 && (jobResultPoller == null || !jobResultPoller.IsPolling)) {
105              StartResultPolling();
106            }
107          } else {
108            StopResultPolling();
109          }
110        }
111      }
112    }
113
114    // indicates if download button is enabled
115    private bool isDownloadable = true;
116    public bool IsDownloadable {
117      get { return isDownloadable; }
118      set {
119        if (value != isDownloadable) {
120          isDownloadable = value;
121          OnIsDownloadableChanged();
122        }
123      }
124    }
125
126    // if true, all control buttons should be enabled. otherwise disabled
127    private bool isControllable = true;
128    public bool IsControllable {
129      get { return isControllable; }
130      private set {
131        if (value != isControllable) {
132          isControllable = value;
133          OnIsControllableChanged();
134          if (this.hiveTasks != null) {
135            foreach (var hiveJob in this.hiveTasks) {
136              hiveJob.IsControllable = value;
137            }
138          }
139        }
140      }
141    }
142
143    // indicates if a user is allowed to share this experiment
144    private bool isSharable = true;
145    public bool IsSharable {
146      get { return isSharable; }
147      private set {
148        if (value != isSharable) {
149          isSharable = value;
150          OnIsSharableChanged();
151        }
152      }
153    }
154
155    // may execute jobs with privileged permissions on slaves
156    private bool isAllowedPrivileged = true;
157    public bool IsAllowedPrivileged {
158      get { return isAllowedPrivileged; }
159      set {
160        if (value != isAllowedPrivileged) {
161          isAllowedPrivileged = value;
162          OnIsAllowedPrivilegedChanged();
163        }
164      }
165    }
166
167    private bool isProgressing;
168    public bool IsProgressing {
169      get { return isProgressing; }
170      set {
171        if (isProgressing != value) {
172          isProgressing = value;
173          OnIsProgressingChanged();
174        }
175      }
176    }
177
178    private IProgress progress;
179    public IProgress Progress {
180      get { return progress; }
181      set { this.progress = value; }
182    }
183
184    private ThreadSafeLog log;
185    public ILog Log {
186      get { return log; }
187    }
188
189    public StateLogListList StateLogList {
190      get { return new StateLogListList(this.GetAllHiveTasks().Select(x => x.StateLog)); }
191    }
192
193    #region Constructors and Cloning
194    public RefreshableJob() {
195      this.refreshAutomatically = true;
196      this.Job = new Job();
197      this.log = new ThreadSafeLog();
198      this.jobDownloader = new ConcurrentTaskDownloader<ItemTask>(Settings.Default.MaxParallelDownloads, Settings.Default.MaxParallelDownloads);
199      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
200      this.HiveTasks = new ItemCollection<HiveTask>();
201    }
202    public RefreshableJob(Job hiveExperiment) {
203      this.refreshAutomatically = true;
204      this.Job = hiveExperiment;
205      this.log = new ThreadSafeLog();
206      this.jobDownloader = new ConcurrentTaskDownloader<ItemTask>(Settings.Default.MaxParallelDownloads, Settings.Default.MaxParallelDownloads);
207      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
208      this.HiveTasks = new ItemCollection<HiveTask>();
209    }
210    protected RefreshableJob(RefreshableJob original, Cloner cloner) {
211      cloner.RegisterClonedObject(original, this);
212      this.Job = cloner.Clone(original.Job);
213      this.IsControllable = original.IsControllable;
214      this.log = cloner.Clone(original.log);
215      this.RefreshAutomatically = false; // do not start results polling automatically
216      this.jobDownloader = new ConcurrentTaskDownloader<ItemTask>(Settings.Default.MaxParallelDownloads, Settings.Default.MaxParallelDownloads);
217      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
218      this.HiveTasks = cloner.Clone(original.HiveTasks);
219      this.ExecutionTime = original.ExecutionTime;
220      this.ExecutionState = original.ExecutionState;
221    }
222    public IDeepCloneable Clone(Cloner cloner) {
223      return new RefreshableJob(this, cloner);
224    }
225    public object Clone() {
226      return this.Clone(new Cloner());
227    }
228    #endregion
229
230    #region JobResultPoller Events
231
232    public void StartResultPolling() {
233      if (jobResultPoller == null) {
234        jobResultPoller = new JobResultPoller(job.Id, Settings.Default.ResultPollingInterval);
235        RegisterResultPollingEvents();
236        jobResultPoller.AutoResumeOnException = true;
237      }
238
239      if (!jobResultPoller.IsPolling) {
240        jobResultPoller.Start();
241      }
242    }
243
244    public void StopResultPolling() {
245      if (jobResultPoller != null && jobResultPoller.IsPolling) {
246        jobResultPoller.Stop();
247      }
248    }
249
250    private void RegisterResultPollingEvents() {
251      jobResultPoller.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobResultPoller_ExceptionOccured);
252      jobResultPoller.JobResultsReceived += new EventHandler<EventArgs<IEnumerable<LightweightTask>>>(jobResultPoller_JobResultReceived);
253      jobResultPoller.IsPollingChanged += new EventHandler(jobResultPoller_IsPollingChanged);
254    }
255    private void DeregisterResultPollingEvents() {
256      jobResultPoller.ExceptionOccured -= new EventHandler<EventArgs<Exception>>(jobResultPoller_ExceptionOccured);
257      jobResultPoller.JobResultsReceived -= new EventHandler<EventArgs<IEnumerable<LightweightTask>>>(jobResultPoller_JobResultReceived);
258      jobResultPoller.IsPollingChanged -= new EventHandler(jobResultPoller_IsPollingChanged);
259    }
260    private void jobResultPoller_IsPollingChanged(object sender, EventArgs e) {
261      if (this.refreshAutomatically != jobResultPoller.IsPolling) {
262        this.refreshAutomatically = jobResultPoller.IsPolling;
263        OnRefreshAutomaticallyChanged();
264      }
265    }
266    private void jobResultPoller_JobResultReceived(object sender, EventArgs<IEnumerable<LightweightTask>> e) {
267      foreach (LightweightTask lightweightTask in e.Value) {
268        HiveTask hiveTask = GetHiveTaskById(lightweightTask.Id);
269        if (hiveTask != null) {
270          // lastJobDataUpdate equals DateTime.MinValue right after it was uploaded. When the first results are polled, this value is updated
271          if (hiveTask.Task.State == TaskState.Offline && lightweightTask.State != TaskState.Finished && lightweightTask.State != TaskState.Failed && lightweightTask.State != TaskState.Aborted) {
272            hiveTask.Task.LastTaskDataUpdate = lightweightTask.LastTaskDataUpdate;
273          }
274
275          hiveTask.UpdateFromLightweightJob(lightweightTask);
276
277          if (!hiveTask.IsFinishedTaskDownloaded && !hiveTask.IsDownloading && hiveTask.Task.LastTaskDataUpdate < lightweightTask.LastTaskDataUpdate) {
278            log.LogMessage(string.Format("Downloading task {0}", lightweightTask.Id));
279            hiveTask.IsDownloading = true;
280            jobDownloader.DownloadTaskData(hiveTask.Task, (localJob, itemJob) => {
281              log.LogMessage(string.Format("Finished downloading task {0}", localJob.Id));
282              HiveTask localHiveTask = GetHiveTaskById(localJob.Id);
283
284              if (itemJob == null) {
285                localHiveTask.IsDownloading = false;
286              }
287
288              if (itemJob == null) {
289                // something bad happened to this task. bad task, BAAAD task!
290              } else {
291                // if the task is paused, download but don't integrate into parent optimizer (to avoid Prepare)
292
293                if (localJob.State == TaskState.Paused) {
294                  localHiveTask.ItemTask = itemJob;
295                } else {
296                  if (localJob.ParentTaskId.HasValue) {
297                    HiveTask parentHiveTask = GetHiveTaskById(localJob.ParentTaskId.Value);
298                    parentHiveTask.IntegrateChild(itemJob, localJob.Id);
299                  } else {
300                    localHiveTask.ItemTask = itemJob;
301                  }
302                }
303                localHiveTask.IsDownloading = false;
304                localHiveTask.Task.LastTaskDataUpdate = localJob.LastTaskDataUpdate;
305              }
306            });
307          }
308        }
309      }
310      GC.Collect(); // force GC, because .NET is too lazy here (deserialization takes a lot of memory)
311      if (AllJobsFinished()) {
312        this.ExecutionState = Core.ExecutionState.Stopped;
313        StopResultPolling();
314      }
315      UpdateTotalExecutionTime();
316      UpdateStatistics();
317      OnStateLogListChanged();
318      OnTaskReceived();
319    }
320
321    public HiveTask GetHiveTaskById(Guid jobId) {
322      foreach (HiveTask t in this.HiveTasks) {
323        var hj = t.GetHiveTaskByTaskId(jobId);
324        if (hj != null)
325          return hj;
326      }
327      return null;
328    }
329
330    private void UpdateStatistics() {
331      var jobs = this.GetAllHiveTasks();
332      job.JobCount = jobs.Count();
333      job.CalculatingCount = jobs.Count(j => j.Task.State == TaskState.Calculating);
334      job.FinishedCount = jobs.Count(j => j.Task.State == TaskState.Finished);
335      OnJobStatisticsChanged();
336    }
337
338    public bool AllJobsFinished() {
339      return this.GetAllHiveTasks().All(j => (j.Task.State == TaskState.Finished
340                                                   || j.Task.State == TaskState.Aborted
341                                                   || j.Task.State == TaskState.Failed)
342                                                   && j.IsFinishedTaskDownloaded);
343    }
344
345    private void jobResultPoller_ExceptionOccured(object sender, EventArgs<Exception> e) {
346      OnExceptionOccured(sender, e.Value);
347    }
348    private void jobDownloader_ExceptionOccured(object sender, EventArgs<Exception> e) {
349      OnExceptionOccured(sender, e.Value);
350    }
351    public void UpdateTotalExecutionTime() {
352      this.ExecutionTime = TimeSpan.FromMilliseconds(this.GetAllHiveTasks().Sum(x => x.Task.ExecutionTime.TotalMilliseconds));
353    }
354    #endregion
355
356    #region Job Events
357    private void RegisterJobEvents() {
358      job.ToStringChanged += new EventHandler(OnToStringChanged);
359      job.PropertyChanged += new PropertyChangedEventHandler(job_PropertyChanged);
360      job.ItemImageChanged += new EventHandler(job_ItemImageChanged);
361      job.ModifiedChanged += new EventHandler(job_ModifiedChanged);
362    }
363
364    private void DergisterJobEvents() {
365      job.ToStringChanged -= new EventHandler(OnToStringChanged);
366      job.PropertyChanged -= new PropertyChangedEventHandler(job_PropertyChanged);
367      job.ItemImageChanged -= new EventHandler(job_ItemImageChanged);
368      job.ModifiedChanged -= new EventHandler(job_ModifiedChanged);
369    }
370    #endregion
371
372    #region Event Handler
373    public event EventHandler RefreshAutomaticallyChanged;
374    private void OnRefreshAutomaticallyChanged() {
375      var handler = RefreshAutomaticallyChanged;
376      if (handler != null) handler(this, EventArgs.Empty);
377    }
378
379    public event EventHandler JobChanged;
380    private void OnJobChanged() {
381      var handler = JobChanged;
382      if (handler != null) handler(this, EventArgs.Empty);
383    }
384
385    public event EventHandler ModifiedChanged;
386    private void job_ModifiedChanged(object sender, EventArgs e) {
387      var handler = ModifiedChanged;
388      if (handler != null) handler(sender, e);
389    }
390
391    public event EventHandler ItemImageChanged;
392    private void job_ItemImageChanged(object sender, EventArgs e) {
393      var handler = ItemImageChanged;
394      if (handler != null) handler(this, e);
395    }
396
397    public event PropertyChangedEventHandler PropertyChanged;
398    private void job_PropertyChanged(object sender, PropertyChangedEventArgs e) {
399      this.IsSharable = job.Permission == Permission.Full;
400      this.IsControllable = job.Permission == Permission.Full;
401
402      var handler = PropertyChanged;
403      if (handler != null) handler(sender, e);
404    }
405
406    public event EventHandler ToStringChanged;
407    private void OnToStringChanged(object sender, EventArgs e) {
408      var handler = ToStringChanged;
409      if (handler != null) handler(this, e);
410    }
411
412    public event EventHandler IsProgressingChanged;
413    protected virtual void OnIsProgressingChanged() {
414      var handler = IsProgressingChanged;
415      if (handler != null) handler(this, EventArgs.Empty);
416    }
417
418    public event EventHandler IsDownloadableChanged;
419    private void OnIsDownloadableChanged() {
420      var handler = IsDownloadableChanged;
421      if (handler != null) handler(this, EventArgs.Empty);
422    }
423
424    public event EventHandler IsControllableChanged;
425    private void OnIsControllableChanged() {
426      var handler = IsControllableChanged;
427      if (handler != null) handler(this, EventArgs.Empty);
428    }
429
430    public event EventHandler IsSharableChanged;
431    private void OnIsSharableChanged() {
432      var handler = IsSharableChanged;
433      if (handler != null) handler(this, EventArgs.Empty);
434    }
435
436    public event EventHandler IsAllowedPrivilegedChanged;
437    private void OnIsAllowedPrivilegedChanged() {
438      var handler = IsAllowedPrivilegedChanged;
439      if (handler != null) handler(this, EventArgs.Empty);
440    }
441
442    public event EventHandler JobStatisticsChanged;
443    private void OnJobStatisticsChanged() {
444      var handler = JobStatisticsChanged;
445      if (handler != null) handler(this, EventArgs.Empty);
446    }
447
448    public event EventHandler<EventArgs<Exception>> ExceptionOccured;
449    private void OnExceptionOccured(object sender, Exception exception) {
450      log.LogException(exception);
451      var handler = ExceptionOccured;
452      if (handler != null) handler(sender, new EventArgs<Exception>(exception));
453    }
454
455    public event EventHandler StateLogListChanged;
456    private void OnStateLogListChanged() {
457      var handler = StateLogListChanged;
458      if (handler != null) handler(this, EventArgs.Empty);
459    }
460
461    public event EventHandler ExecutionTimeChanged;
462    protected virtual void OnExecutionTimeChanged() {
463      var handler = ExecutionTimeChanged;
464      if (handler != null) handler(this, EventArgs.Empty);
465    }
466
467    public event EventHandler ExecutionStateChanged;
468    protected virtual void OnExecutionStateChanged() {
469      var handler = ExecutionStateChanged;
470      if (handler != null) handler(this, EventArgs.Empty);
471    }
472    public event EventHandler TaskReceived;
473    protected virtual void OnTaskReceived() {
474      var handler = TaskReceived;
475      if (handler != null) handler(this, EventArgs.Empty);
476    }
477    #endregion
478
479    #region HiveTasks Events
480    private void RegisterHiveJobsEvents() {
481      this.hiveTasks.ItemsAdded += new CollectionItemsChangedEventHandler<HiveTask>(hivetasks_ItemsAdded);
482      this.hiveTasks.ItemsRemoved += new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_ItemsRemoved);
483      this.hiveTasks.CollectionReset += new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_CollectionReset);
484    }
485
486    private void DeregisterHiveJobsEvents() {
487      this.hiveTasks.ItemsAdded -= new CollectionItemsChangedEventHandler<HiveTask>(hivetasks_ItemsAdded);
488      this.hiveTasks.ItemsRemoved -= new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_ItemsRemoved);
489      this.hiveTasks.CollectionReset -= new CollectionItemsChangedEventHandler<HiveTask>(hiveTasks_CollectionReset);
490    }
491
492    private void hiveTasks_CollectionReset(object sender, CollectionItemsChangedEventArgs<HiveTask> e) {
493      foreach (var item in e.Items) {
494        item.StateLogChanged -= new EventHandler(item_StateLogChanged);
495      }
496      OnHiveTasksReset(e);
497    }
498
499    private void hiveTasks_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<HiveTask> e) {
500      foreach (var item in e.Items) {
501        item.StateLogChanged -= new EventHandler(item_StateLogChanged);
502      }
503      OnHiveTasksRemoved(e);
504    }
505
506    private void hivetasks_ItemsAdded(object sender, CollectionItemsChangedEventArgs<HiveTask> e) {
507      foreach (var item in e.Items) {
508        item.StateLogChanged += new EventHandler(item_StateLogChanged);
509        item.IsControllable = this.IsControllable;
510      }
511      OnHiveTasksAdded(e);
512    }
513
514    private void item_StateLogChanged(object sender, EventArgs e) {
515      OnStateLogListChanged();
516    }
517    #endregion
518
519    public event EventHandler HiveTasksChanged;
520    protected virtual void OnHiveTasksChanged() {
521      if (jobResultPoller != null && jobResultPoller.IsPolling) {
522        jobResultPoller.Stop();
523        DeregisterResultPollingEvents();
524      }
525      if (this.HiveTasks != null && this.HiveTasks.Count > 0 && this.GetAllHiveTasks().All(x => x.Task.Id != Guid.Empty)) {
526        if (IsFinished()) {
527          this.ExecutionState = Core.ExecutionState.Stopped;
528          this.RefreshAutomatically = false;
529        }
530
531        if (this.RefreshAutomatically) {
532          StartResultPolling();
533        }
534      }
535
536      var handler = HiveTasksChanged;
537      if (handler != null) handler(this, EventArgs.Empty);
538    }
539
540    public event EventHandler Loaded;
541    public virtual void OnLoaded() {
542      this.UpdateTotalExecutionTime();
543      this.OnStateLogListChanged();
544
545      if (this.ExecutionState != ExecutionState.Stopped) {
546        this.RefreshAutomatically = true;
547      }
548
549      var handler = Loaded;
550      if (handler != null) handler(this, EventArgs.Empty);
551    }
552
553    public event EventHandler<CollectionItemsChangedEventArgs<HiveTask>> HiveTasksAdded;
554    private void OnHiveTasksAdded(CollectionItemsChangedEventArgs<HiveTask> e) {
555      var handler = HiveTasksAdded;
556      if (handler != null) handler(this, e);
557    }
558
559    public event EventHandler<CollectionItemsChangedEventArgs<HiveTask>> HiveTasksRemoved;
560    private void OnHiveTasksRemoved(CollectionItemsChangedEventArgs<HiveTask> e) {
561      var handler = HiveTasksRemoved;
562      if (handler != null) handler(this, e);
563    }
564
565    public event EventHandler<CollectionItemsChangedEventArgs<HiveTask>> HiveTasksReset;
566    private void OnHiveTasksReset(CollectionItemsChangedEventArgs<HiveTask> e) {
567      var handler = HiveTasksReset;
568      if (handler != null) handler(this, e);
569    }
570
571    public Guid Id {
572      get { return job.Id; }
573      set { job.Id = value; }
574    }
575    public bool Modified {
576      get { return job.Modified; }
577    }
578    public void Store() {
579      job.Store();
580    }
581    public string ItemDescription {
582      get { return job.ItemDescription; }
583    }
584    public Image ItemImage {
585      get { return job.ItemImage; }
586    }
587    public string ItemName {
588      get { return job.ItemName; }
589    }
590    public Version ItemVersion {
591      get { return job.ItemVersion; }
592    }
593
594    public override string ToString() {
595      return string.Format("{0} {1}", Job.DateCreated.ToString("MM.dd.yyyy HH:mm"), Job.ToString());
596    }
597
598    public bool IsFinished() {
599      return HiveTasks != null
600        && HiveTasks.All(x => x.Task.DateFinished.HasValue && x.Task.DateCreated.HasValue);
601    }
602
603    public IEnumerable<HiveTask> GetAllHiveTasks() {
604      if (hiveTasks == null) return Enumerable.Empty<HiveTask>();
605
606      var tasks = new List<HiveTask>();
607      foreach (HiveTask task in HiveTasks) {
608        tasks.AddRange(task.GetAllHiveTasks());
609      }
610      return tasks;
611    }
612
613    public int CompareTo(RefreshableJob other) {
614      return this.ToString().CompareTo(other.ToString());
615    }
616  }
617}
Note: See TracBrowser for help on using the repository browser.