#region License Information /* HeuristicLab * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Hive; namespace HeuristicLab.Clients.Hive { public class RefreshableHiveExperiment : IHiveItem, IDeepCloneable, IContent, IProgressReporter { private JobResultPoller jobResultPoller; private ConcurrentJobDownloader jobDownloader; private static object locker = new object(); private HiveExperiment hiveExperiment; public HiveExperiment HiveExperiment { get { return hiveExperiment; } set { if (value != hiveExperiment) { if (value == null) throw new ArgumentNullException(); if (hiveExperiment != null) DergisterHiveExperimentEvents(); hiveExperiment = value; if (hiveExperiment != null) RegisterHiveExperimentEvents(); OnHiveExperimentChanged(); } } } /** include jobs when refreshing **/ private bool includeJobs; public bool IncludeJobs { get { return includeJobs; } set { includeJobs = value; } } private bool refreshAutomatically; public bool RefreshAutomatically { get { return refreshAutomatically; } set { lock (locker) { if (refreshAutomatically != value) { refreshAutomatically = value; OnRefreshAutomaticallyChanged(); } if (RefreshAutomatically) { if (hiveExperiment.HiveJobs != null && hiveExperiment.HiveJobs.Count > 0 && (jobResultPoller == null || !jobResultPoller.IsPolling)) { StartResultPolling(); } } else { StopResultPolling(); } } } } // if true, all control buttons should be enabled. otherwise disabled (used for HiveEngine) private bool isControllable = true; public bool IsControllable { get { return isControllable; } set { if (value != isControllable) { isControllable = value; OnIsControllableChanged(); } } } private ILog log; public ILog Log { get { return log; } set { log = value; } } private static object logLocker = new object(); #region Constructors and Cloning public RefreshableHiveExperiment() { this.includeJobs = true; this.refreshAutomatically = true; this.HiveExperiment = new HiveExperiment(); this.log = new Log(); this.jobDownloader = new ConcurrentJobDownloader(2, 2); this.jobDownloader.ExceptionOccured += new EventHandler>(jobDownloader_ExceptionOccured); } public RefreshableHiveExperiment(HiveExperiment hiveExperiment) { this.includeJobs = true; this.refreshAutomatically = true; this.HiveExperiment = hiveExperiment; this.log = new Log(); this.jobDownloader = new ConcurrentJobDownloader(2, 2); this.jobDownloader.ExceptionOccured += new EventHandler>(jobDownloader_ExceptionOccured); } protected RefreshableHiveExperiment(RefreshableHiveExperiment original, Cloner cloner) { cloner.RegisterClonedObject(original, this); this.HiveExperiment = original.HiveExperiment; this.IncludeJobs = original.IncludeJobs; this.IsControllable = original.IsControllable; this.Log = cloner.Clone(original.Log); this.RefreshAutomatically = false; // do not start results polling automatically this.jobDownloader = new ConcurrentJobDownloader(2, 2); this.jobDownloader.ExceptionOccured += new EventHandler>(jobDownloader_ExceptionOccured); } public IDeepCloneable Clone(Cloner cloner) { return new RefreshableHiveExperiment(this, cloner); } public object Clone() { return this.Clone(new Cloner()); } #endregion private void hiveExperiment_HiveJobsChanged(object sender, EventArgs e) { if (jobResultPoller != null && jobResultPoller.IsPolling) { jobResultPoller.Stop(); DeregisterResultPollingEvents(); } if (hiveExperiment.HiveJobs != null && hiveExperiment.HiveJobs.Count > 0 && hiveExperiment.GetAllHiveJobs().All(x => x.Job.Id != Guid.Empty)) { if (this.RefreshAutomatically) StartResultPolling(); } } #region JobResultPoller Events public void StartResultPolling() { if (jobResultPoller == null) { jobResultPoller = new JobResultPoller(hiveExperiment.Id, /*ApplicationConstants.ResultPollingInterval*/new TimeSpan(0, 0, 5)); //TODO: find a better place for ApplicationConstants RegisterResultPollingEvents(); jobResultPoller.AutoResumeOnException = !IsControllable; } if (!jobResultPoller.IsPolling) { jobResultPoller.Start(); } } public void StopResultPolling() { if (jobResultPoller != null && jobResultPoller.IsPolling) { jobResultPoller.Stop(); } } private void RegisterResultPollingEvents() { jobResultPoller.ExceptionOccured += new EventHandler>(jobResultPoller_ExceptionOccured); jobResultPoller.JobResultsReceived += new EventHandler>>(jobResultPoller_JobResultReceived); jobResultPoller.IsPollingChanged += new EventHandler(jobResultPoller_IsPollingChanged); } private void DeregisterResultPollingEvents() { jobResultPoller.ExceptionOccured -= new EventHandler>(jobResultPoller_ExceptionOccured); jobResultPoller.JobResultsReceived -= new EventHandler>>(jobResultPoller_JobResultReceived); jobResultPoller.IsPollingChanged -= new EventHandler(jobResultPoller_IsPollingChanged); } private void jobResultPoller_IsPollingChanged(object sender, EventArgs e) { this.refreshAutomatically = jobResultPoller.IsPolling; OnRefreshAutomaticallyChanged(); } private void jobResultPoller_JobResultReceived(object sender, EventArgs> e) { foreach (LightweightJob lightweightJob in e.Value) { HiveJob hiveJob = GetHiveJobById(lightweightJob.Id); if (hiveJob != null) { // lastJobDataUpdate equals DateTime.MinValue right after it was uploaded. When the first results are polled, this value is updated if (hiveJob.Job.State == JobState.Offline && lightweightJob.State != JobState.Finished && lightweightJob.State != JobState.Failed && lightweightJob.State != JobState.Aborted) { hiveJob.Job.LastJobDataUpdate = lightweightJob.LastJobDataUpdate; } hiveJob.UpdateFromLightweightJob(lightweightJob); if (!hiveJob.IsFinishedJobDownloaded && !hiveJob.IsDownloading && hiveJob.Job.LastJobDataUpdate < lightweightJob.LastJobDataUpdate) { LogMessage(string.Format("Downloading job {0}", lightweightJob.Id)); hiveJob.IsDownloading = true; jobDownloader.DownloadJob(hiveJob.Job, (localJob, itemJob) => { LogMessage(string.Format("Finished downloading job {0}", localJob.Id)); HiveJob localHiveJob = GetHiveJobById(localJob.Id); if (itemJob == null) { localHiveJob.IsDownloading = false; } if (itemJob == null) { // something bad happened to this job. bad job, BAAAD job! } else { // if the job is paused, download but don't integrate into parent optimizer (to avoid Prepare) if (localJob.State == JobState.Paused) { localHiveJob.ItemJob = itemJob; } else { if (localJob.ParentJobId.HasValue) { HiveJob parentHiveJob = GetHiveJobById(localJob.ParentJobId.Value); parentHiveJob.IntegrateChild(itemJob, localJob.Id); } else { localHiveJob.ItemJob = itemJob; } } localHiveJob.IsDownloading = false; localHiveJob.Job.LastJobDataUpdate = localJob.LastJobDataUpdate; } }); } } } GC.Collect(); // force GC, because .NET is too lazy here (deserialization takes a lot of memory) if (AllJobsFinished()) { hiveExperiment.ExecutionState = Core.ExecutionState.Stopped; StopResultPolling(); } UpdateTotalExecutionTime(); UpdateStatistics(); } // synchronized logging private void LogException(Exception exception) { lock (logLocker) { this.log.LogException(exception); } } // synchronized logging private void LogMessage(string message) { lock (logLocker) { this.log.LogMessage(message); } } public HiveJob GetHiveJobById(Guid jobId) { foreach (HiveJob job in hiveExperiment.HiveJobs) { var hj = job.GetHiveJobByJobId(jobId); if (hj != null) return hj; } return null; } private void UpdateStatistics() { var jobs = hiveExperiment.GetAllHiveJobs(); hiveExperiment.JobCount = jobs.Count(); hiveExperiment.CalculatingCount = jobs.Count(j => j.Job.State == JobState.Calculating); hiveExperiment.FinishedCount = jobs.Count(j => j.Job.State == JobState.Finished); OnJobStatisticsChanged(); } public bool AllJobsFinished() { return hiveExperiment.GetAllHiveJobs().All(j => (j.Job.State == JobState.Finished || j.Job.State == JobState.Aborted || j.Job.State == JobState.Failed) && j.IsFinishedJobDownloaded); } private void jobResultPoller_ExceptionOccured(object sender, EventArgs e) { OnExceptionOccured(e.Value); } private void jobDownloader_ExceptionOccured(object sender, EventArgs e) { OnExceptionOccured(e.Value); } public void UpdateTotalExecutionTime() { hiveExperiment.ExecutionTime = TimeSpan.FromMilliseconds(hiveExperiment.GetAllHiveJobs().Sum(x => x.Job.ExecutionTime.HasValue ? x.Job.ExecutionTime.Value.TotalMilliseconds : 0)); } #endregion private void RegisterHiveExperimentEvents() { hiveExperiment.HiveJobsChanged += new EventHandler(hiveExperiment_HiveJobsChanged); hiveExperiment.ToStringChanged += new EventHandler(hiveExperiment_ToStringChanged); hiveExperiment.PropertyChanged += new PropertyChangedEventHandler(hiveExperiment_PropertyChanged); hiveExperiment.ItemImageChanged += new EventHandler(hiveExperiment_ItemImageChanged); hiveExperiment.ModifiedChanged += new EventHandler(hiveExperiment_ModifiedChanged); hiveExperiment.IsProgressingChanged += new EventHandler(hiveExperiment_IsProgressingChanged); hiveExperiment.Loaded += new EventHandler(hiveExperiment_Loaded); } private void DergisterHiveExperimentEvents() { hiveExperiment.HiveJobsChanged -= new EventHandler(hiveExperiment_HiveJobsChanged); hiveExperiment.ToStringChanged -= new EventHandler(hiveExperiment_ToStringChanged); hiveExperiment.PropertyChanged -= new PropertyChangedEventHandler(hiveExperiment_PropertyChanged); hiveExperiment.ItemImageChanged -= new EventHandler(hiveExperiment_ItemImageChanged); hiveExperiment.ModifiedChanged -= new EventHandler(hiveExperiment_ModifiedChanged); hiveExperiment.IsProgressingChanged -= new EventHandler(hiveExperiment_IsProgressingChanged); hiveExperiment.Loaded -= new EventHandler(hiveExperiment_Loaded); } private void hiveExperiment_Loaded(object sender, EventArgs e) { this.UpdateTotalExecutionTime(); if (hiveExperiment.ExecutionState != ExecutionState.Stopped) { this.RefreshAutomatically = true; } } #region Events public event EventHandler RefreshAutomaticallyChanged; private void OnRefreshAutomaticallyChanged() { var handler = RefreshAutomaticallyChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler HiveExperimentChanged; private void OnHiveExperimentChanged() { var handler = HiveExperimentChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler ModifiedChanged; private void hiveExperiment_ModifiedChanged(object sender, EventArgs e) { var handler = ModifiedChanged; if (handler != null) handler(sender, e); } public event EventHandler ItemImageChanged; private void hiveExperiment_ItemImageChanged(object sender, EventArgs e) { var handler = ItemImageChanged; if (handler != null) handler(this, e); } public event PropertyChangedEventHandler PropertyChanged; private void hiveExperiment_PropertyChanged(object sender, PropertyChangedEventArgs e) { var handler = PropertyChanged; if (handler != null) handler(sender, e); } public event EventHandler ToStringChanged; private void hiveExperiment_ToStringChanged(object sender, EventArgs e) { var handler = ToStringChanged; if (handler != null) handler(this, e); } public event EventHandler IsProgressingChanged; private void hiveExperiment_IsProgressingChanged(object sender, EventArgs e) { var handler = IsProgressingChanged; if (handler != null) handler(sender, e); } public event EventHandler IsControllableChanged; private void OnIsControllableChanged() { var handler = IsControllableChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler JobStatisticsChanged; private void OnJobStatisticsChanged() { var handler = JobStatisticsChanged; if (handler != null) handler(this, EventArgs.Empty); } public event EventHandler> ExceptionOccured; private void OnExceptionOccured(Exception exception) { LogException(exception); var handler = ExceptionOccured; if (handler != null) handler(this, new EventArgs(exception)); } #endregion public Guid Id { get { return hiveExperiment.Id; } set { hiveExperiment.Id = value; } } public bool Modified { get { return hiveExperiment.Modified; } } public void Store() { hiveExperiment.Store(); } public string ItemDescription { get { return hiveExperiment.ItemDescription; } } public Image ItemImage { get { return hiveExperiment.ItemImage; } } public string ItemName { get { return hiveExperiment.ItemName; } } public Version ItemVersion { get { return hiveExperiment.ItemVersion; } } #region IProgressReporter Members public IProgress Progress { get { return HiveExperiment.Progress; } } public bool IsProgressing { get { return HiveExperiment.IsProgressing; } } #endregion public override string ToString() { return HiveExperiment.ToString(); } } }