source: branches/HeuristicLab.Hive-3.4/sources/HeuristicLab.Clients.Hive/3.4/RefreshableHiveExperiment.cs @ 6479

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

#1233

  • finished experiment sharing
  • added role for executing privileged jobs
  • refreshing experiments in experimentManager does not delete already downloaded jobs
  • moved some properties from HiveExperiment into RefreshableHiveExperiment
File size: 22.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 HeuristicLab.Collections;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30
31namespace HeuristicLab.Clients.Hive {
32  public class RefreshableHiveExperiment : IHiveItem, IDeepCloneable, IContent, IProgressReporter, IComparable<RefreshableHiveExperiment> {
33    private JobResultPoller jobResultPoller;
34    private ConcurrentJobDownloader<ItemJob> jobDownloader;
35    private static object locker = new object();
36
37    private HiveExperiment hiveExperiment;
38    public HiveExperiment HiveExperiment {
39      get { return hiveExperiment; }
40      set {
41        if (value != hiveExperiment) {
42          if (value == null)
43            throw new ArgumentNullException();
44
45          if (hiveExperiment != null) DergisterHiveExperimentEvents();
46          hiveExperiment = value;
47          if (hiveExperiment != null) {
48            RegisterHiveExperimentEvents();
49            hiveExperiment_PropertyChanged(hiveExperiment, new PropertyChangedEventArgs("Id"));
50          }
51          OnHiveExperimentChanged();
52          OnToStringChanged(this, EventArgs.Empty);
53        }
54      }
55    }
56
57    private ItemCollection<HiveJob> hiveJobs;
58    public ItemCollection<HiveJob> HiveJobs {
59      get { return hiveJobs; }
60      set {
61        if (hiveJobs != value) {
62          if (hiveJobs != null) DeregisterHiveJobsEvents();
63          hiveJobs = value;
64          if (hiveJobs != null) RegisterHiveJobsEvents();
65          OnHiveJobsChanged();
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.HiveJobs != null && this.HiveJobs.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.hiveJobs != null) {
133            foreach (var hiveJob in this.hiveJobs) {
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.GetAllHiveJobs().Select(x => x.StateLog)); }
189    }
190
191    #region Constructors and Cloning
192    public RefreshableHiveExperiment() {
193      this.refreshAutomatically = true;
194      this.HiveExperiment = new HiveExperiment();
195      this.log = new ThreadSafeLog(new Log());
196      this.jobDownloader = new ConcurrentJobDownloader<ItemJob>(2, 2);
197      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
198      this.HiveJobs = new ItemCollection<HiveJob>();
199    }
200    public RefreshableHiveExperiment(HiveExperiment hiveExperiment) {
201      this.refreshAutomatically = true;
202      this.HiveExperiment = hiveExperiment;
203      this.log = new ThreadSafeLog(new Log());
204      this.jobDownloader = new ConcurrentJobDownloader<ItemJob>(2, 2);
205      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
206      this.HiveJobs = new ItemCollection<HiveJob>();
207    }
208    protected RefreshableHiveExperiment(RefreshableHiveExperiment original, Cloner cloner) {
209      cloner.RegisterClonedObject(original, this);
210      this.HiveExperiment = original.HiveExperiment;
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 ConcurrentJobDownloader<ItemJob>(2, 2);
215      this.jobDownloader.ExceptionOccured += new EventHandler<EventArgs<Exception>>(jobDownloader_ExceptionOccured);
216      this.HiveJobs = cloner.Clone(original.HiveJobs);
217      this.ExecutionTime = original.ExecutionTime;
218      this.ExecutionState = original.ExecutionState;
219    }
220    public IDeepCloneable Clone(Cloner cloner) {
221      return new RefreshableHiveExperiment(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(hiveExperiment.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<LightweightJob>>>(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<LightweightJob>>>(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<LightweightJob>> e) {
265      foreach (LightweightJob lightweightJob in e.Value) {
266        HiveJob hiveJob = GetHiveJobById(lightweightJob.Id);
267        if (hiveJob != null) {
268          // lastJobDataUpdate equals DateTime.MinValue right after it was uploaded. When the first results are polled, this value is updated
269          if (hiveJob.Job.State == JobState.Offline && lightweightJob.State != JobState.Finished && lightweightJob.State != JobState.Failed && lightweightJob.State != JobState.Aborted) {
270            hiveJob.Job.LastJobDataUpdate = lightweightJob.LastJobDataUpdate;
271          }
272
273          hiveJob.UpdateFromLightweightJob(lightweightJob);
274
275          if (!hiveJob.IsFinishedJobDownloaded && !hiveJob.IsDownloading && hiveJob.Job.LastJobDataUpdate < lightweightJob.LastJobDataUpdate) {
276            log.LogMessage(string.Format("Downloading job {0}", lightweightJob.Id));
277            hiveJob.IsDownloading = true;
278            jobDownloader.DownloadJob(hiveJob.Job, (localJob, itemJob) => {
279              log.LogMessage(string.Format("Finished downloading job {0}", localJob.Id));
280              HiveJob localHiveJob = GetHiveJobById(localJob.Id);
281
282              if (itemJob == null) {
283                localHiveJob.IsDownloading = false;
284              }
285
286              if (itemJob == null) {
287                // something bad happened to this job. bad job, BAAAD job!
288              } else {
289                // if the job is paused, download but don't integrate into parent optimizer (to avoid Prepare)
290
291                if (localJob.State == JobState.Paused) {
292                  localHiveJob.ItemJob = itemJob;
293                } else {
294                  if (localJob.ParentJobId.HasValue) {
295                    HiveJob parentHiveJob = GetHiveJobById(localJob.ParentJobId.Value);
296                    parentHiveJob.IntegrateChild(itemJob, localJob.Id);
297                  } else {
298                    localHiveJob.ItemJob = itemJob;
299                  }
300                }
301                localHiveJob.IsDownloading = false;
302                localHiveJob.Job.LastJobDataUpdate = localJob.LastJobDataUpdate;
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 HiveJob GetHiveJobById(Guid jobId) {
319      foreach (HiveJob job in this.HiveJobs) {
320        var hj = job.GetHiveJobByJobId(jobId);
321        if (hj != null)
322          return hj;
323      }
324      return null;
325    }
326    private void UpdateStatistics() {
327      var jobs = this.GetAllHiveJobs();
328      hiveExperiment.JobCount = jobs.Count();
329      hiveExperiment.CalculatingCount = jobs.Count(j => j.Job.State == JobState.Calculating);
330      hiveExperiment.FinishedCount = jobs.Count(j => j.Job.State == JobState.Finished);
331      OnJobStatisticsChanged();
332    }
333
334    public bool AllJobsFinished() {
335      return this.GetAllHiveJobs().All(j => (j.Job.State == JobState.Finished
336                                                   || j.Job.State == JobState.Aborted
337                                                   || j.Job.State == JobState.Failed)
338                                                   && j.IsFinishedJobDownloaded);
339    }
340
341    private void jobResultPoller_ExceptionOccured(object sender, EventArgs<Exception> e) {
342      OnExceptionOccured(e.Value);
343    }
344    private void jobDownloader_ExceptionOccured(object sender, EventArgs<Exception> e) {
345      OnExceptionOccured(e.Value);
346    }
347    public void UpdateTotalExecutionTime() {
348      this.ExecutionTime = TimeSpan.FromMilliseconds(this.GetAllHiveJobs().Sum(x => x.Job.ExecutionTime.TotalMilliseconds));
349    }
350    #endregion
351
352    #region HiveExperiment Events
353    private void RegisterHiveExperimentEvents() {
354      hiveExperiment.ToStringChanged += new EventHandler(OnToStringChanged);
355      hiveExperiment.PropertyChanged += new PropertyChangedEventHandler(hiveExperiment_PropertyChanged);
356      hiveExperiment.ItemImageChanged += new EventHandler(hiveExperiment_ItemImageChanged);
357      hiveExperiment.ModifiedChanged += new EventHandler(hiveExperiment_ModifiedChanged);
358    }
359
360    private void DergisterHiveExperimentEvents() {
361      hiveExperiment.ToStringChanged -= new EventHandler(OnToStringChanged);
362      hiveExperiment.PropertyChanged -= new PropertyChangedEventHandler(hiveExperiment_PropertyChanged);
363      hiveExperiment.ItemImageChanged -= new EventHandler(hiveExperiment_ItemImageChanged);
364      hiveExperiment.ModifiedChanged -= new EventHandler(hiveExperiment_ModifiedChanged);
365    }
366    #endregion
367
368    #region Event Handler
369    public event EventHandler RefreshAutomaticallyChanged;
370    private void OnRefreshAutomaticallyChanged() {
371      var handler = RefreshAutomaticallyChanged;
372      if (handler != null) handler(this, EventArgs.Empty);
373    }
374
375    public event EventHandler HiveExperimentChanged;
376    private void OnHiveExperimentChanged() {
377      var handler = HiveExperimentChanged;
378      if (handler != null) handler(this, EventArgs.Empty);
379    }
380
381    public event EventHandler ModifiedChanged;
382    private void hiveExperiment_ModifiedChanged(object sender, EventArgs e) {
383      var handler = ModifiedChanged;
384      if (handler != null) handler(sender, e);
385    }
386
387    public event EventHandler ItemImageChanged;
388    private void hiveExperiment_ItemImageChanged(object sender, EventArgs e) {
389      var handler = ItemImageChanged;
390      if (handler != null) handler(this, e);
391    }
392
393    public event PropertyChangedEventHandler PropertyChanged;
394    private void hiveExperiment_PropertyChanged(object sender, PropertyChangedEventArgs e) {
395      this.IsSharable = hiveExperiment.Permission == Permission.Full;
396      this.IsControllable = hiveExperiment.Permission == Permission.Full;
397
398      var handler = PropertyChanged;
399      if (handler != null) handler(sender, e);
400    }
401
402    public event EventHandler ToStringChanged;
403    private void OnToStringChanged(object sender, EventArgs e) {
404      var handler = ToStringChanged;
405      if (handler != null) handler(this, e);
406    }
407
408    public event EventHandler IsProgressingChanged;
409    protected virtual void OnIsProgressingChanged() {
410      var handler = IsProgressingChanged;
411      if (handler != null) handler(this, EventArgs.Empty);
412    }
413
414    public event EventHandler IsDownloadableChanged;
415    private void OnIsDownloadableChanged() {
416      var handler = IsDownloadableChanged;
417      if (handler != null) handler(this, EventArgs.Empty);
418    }
419
420    public event EventHandler IsControllableChanged;
421    private void OnIsControllableChanged() {
422      var handler = IsControllableChanged;
423      if (handler != null) handler(this, EventArgs.Empty);
424    }
425
426    public event EventHandler IsSharableChanged;
427    private void OnIsSharableChanged() {
428      var handler = IsSharableChanged;
429      if (handler != null) handler(this, EventArgs.Empty);
430    }
431
432    public event EventHandler IsAllowedPrivilegedChanged;
433    private void OnIsAllowedPrivilegedChanged() {
434      var handler = IsAllowedPrivilegedChanged;
435      if (handler != null) handler(this, EventArgs.Empty);
436    }
437
438    public event EventHandler JobStatisticsChanged;
439    private void OnJobStatisticsChanged() {
440      var handler = JobStatisticsChanged;
441      if (handler != null) handler(this, EventArgs.Empty);
442    }
443
444    public event EventHandler<EventArgs<Exception>> ExceptionOccured;
445    private void OnExceptionOccured(Exception exception) {
446      log.LogException(exception);
447      var handler = ExceptionOccured;
448      if (handler != null) handler(this, new EventArgs<Exception>(exception));
449    }
450
451    public event EventHandler StateLogListChanged;
452    private void OnStateLogListChanged() {
453      var handler = StateLogListChanged;
454      if (handler != null) handler(this, EventArgs.Empty);
455    }
456
457    public event EventHandler ExecutionTimeChanged;
458    protected virtual void OnExecutionTimeChanged() {
459      var handler = ExecutionTimeChanged;
460      if (handler != null) handler(this, EventArgs.Empty);
461    }
462
463    public event EventHandler ExecutionStateChanged;
464    protected virtual void OnExecutionStateChanged() {
465      var handler = ExecutionStateChanged;
466      if (handler != null) handler(this, EventArgs.Empty);
467    }
468    #endregion
469
470    #region HiveJobs Events
471    private void RegisterHiveJobsEvents() {
472      this.hiveJobs.ItemsAdded += new CollectionItemsChangedEventHandler<HiveJob>(hiveJobs_ItemsAdded);
473      this.hiveJobs.ItemsRemoved += new CollectionItemsChangedEventHandler<HiveJob>(hiveJobs_ItemsRemoved);
474      this.hiveJobs.CollectionReset += new CollectionItemsChangedEventHandler<HiveJob>(hiveJobs_CollectionReset);
475    }
476
477    private void DeregisterHiveJobsEvents() {
478      this.hiveJobs.ItemsAdded -= new CollectionItemsChangedEventHandler<HiveJob>(hiveJobs_ItemsAdded);
479      this.hiveJobs.ItemsRemoved -= new CollectionItemsChangedEventHandler<HiveJob>(hiveJobs_ItemsRemoved);
480      this.hiveJobs.CollectionReset -= new CollectionItemsChangedEventHandler<HiveJob>(hiveJobs_CollectionReset);
481    }
482
483    private void hiveJobs_CollectionReset(object sender, CollectionItemsChangedEventArgs<HiveJob> e) {
484      foreach (var item in e.Items) {
485        item.StateLogChanged -= new EventHandler(item_StateLogChanged);
486      }
487      OnHiveJobsReset(e);
488    }
489
490    private void hiveJobs_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<HiveJob> e) {
491      foreach (var item in e.Items) {
492        item.StateLogChanged -= new EventHandler(item_StateLogChanged);
493      }
494      OnHiveJobsRemoved(e);
495    }
496
497    private void hiveJobs_ItemsAdded(object sender, CollectionItemsChangedEventArgs<HiveJob> e) {
498      foreach (var item in e.Items) {
499        item.StateLogChanged += new EventHandler(item_StateLogChanged);
500        item.IsControllable = this.IsControllable;
501      }
502      OnHiveJobsAdded(e);
503    }
504
505    private void item_StateLogChanged(object sender, EventArgs e) {
506      OnStateLogListChanged();
507    }
508    #endregion
509
510    public event EventHandler HiveJobsChanged;
511    protected virtual void OnHiveJobsChanged() {
512      if (jobResultPoller != null && jobResultPoller.IsPolling) {
513        jobResultPoller.Stop();
514        DeregisterResultPollingEvents();
515      }
516      if (this.HiveJobs != null && this.HiveJobs.Count > 0 && this.GetAllHiveJobs().All(x => x.Job.Id != Guid.Empty)) {
517        if (this.RefreshAutomatically)
518          StartResultPolling();
519      }
520
521      var handler = HiveJobsChanged;
522      if (handler != null) handler(this, EventArgs.Empty);
523    }
524
525    public event EventHandler Loaded;
526    public virtual void OnLoaded() {
527      this.UpdateTotalExecutionTime();
528
529      if (this.ExecutionState != ExecutionState.Stopped) {
530        this.RefreshAutomatically = true;
531      }
532
533      var handler = Loaded;
534      if (handler != null) handler(this, EventArgs.Empty);
535    }
536
537    public event EventHandler<CollectionItemsChangedEventArgs<HiveJob>> HiveJobsAdded;
538    private void OnHiveJobsAdded(CollectionItemsChangedEventArgs<HiveJob> e) {
539      var handler = HiveJobsAdded;
540      if (handler != null) handler(this, e);
541    }
542
543    public event EventHandler<CollectionItemsChangedEventArgs<HiveJob>> HiveJobsRemoved;
544    private void OnHiveJobsRemoved(CollectionItemsChangedEventArgs<HiveJob> e) {
545      var handler = HiveJobsRemoved;
546      if (handler != null) handler(this, e);
547    }
548
549    public event EventHandler<CollectionItemsChangedEventArgs<HiveJob>> HiveJobsReset;
550    private void OnHiveJobsReset(CollectionItemsChangedEventArgs<HiveJob> e) {
551      var handler = HiveJobsReset;
552      if (handler != null) handler(this, e);
553    }
554
555    public Guid Id {
556      get { return hiveExperiment.Id; }
557      set { hiveExperiment.Id = value; }
558    }
559    public bool Modified {
560      get { return hiveExperiment.Modified; }
561    }
562    public void Store() {
563      hiveExperiment.Store();
564    }
565    public string ItemDescription {
566      get { return hiveExperiment.ItemDescription; }
567    }
568    public Image ItemImage {
569      get { return hiveExperiment.ItemImage; }
570    }
571    public string ItemName {
572      get { return hiveExperiment.ItemName; }
573    }
574    public Version ItemVersion {
575      get { return hiveExperiment.ItemVersion; }
576    }
577
578    public override string ToString() {
579      return string.Format("{0} {1}", HiveExperiment.DateCreated.ToString("MM.dd.yyyy HH:mm"), HiveExperiment.ToString());
580    }
581
582    public bool IsFinished() {
583      return HiveJobs != null
584        && HiveJobs.All(x => x.Job.DateFinished.HasValue && x.Job.DateCreated.HasValue);
585    }
586
587    public IEnumerable<HiveJob> GetAllHiveJobs() {
588      if (hiveJobs == null) return Enumerable.Empty<HiveJob>();
589
590      var jobs = new List<HiveJob>();
591      foreach (HiveJob job in HiveJobs) {
592        jobs.AddRange(job.GetAllHiveJobs());
593      }
594      return jobs;
595    }
596
597    public int CompareTo(RefreshableHiveExperiment other) {
598      return this.ToString().CompareTo(other.ToString());
599    }
600  }
601}
Note: See TracBrowser for help on using the repository browser.