source: trunk/sources/HeuristicLab.Clients.Hive/3.3/RefreshableJob.cs @ 6994

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

#1672

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