Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Hive-3.4/sources/HeuristicLab.Clients.Hive/3.4/HiveClient.cs @ 6373

Last change on this file since 6373 was 6373, checked in by cneumuel, 13 years ago

#1233

  • moved ExperimentManager into separate plugin
  • moved Administration into separate plugin
File size: 16.0 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.Configuration;
25using System.IO;
26using System.Linq;
27using System.Threading;
28using HeuristicLab.Common;
29using HeuristicLab.Core;
30using HeuristicLab.PluginInfrastructure;
31
32namespace HeuristicLab.Clients.Hive {
33  [Item("HiveClient", "Hive client.")]
34  public sealed class HiveClient : IContent {
35    private static HiveClient instance;
36    public static HiveClient Instance {
37      get {
38        if (instance == null) instance = new HiveClient();
39        return instance;
40      }
41    }
42
43    #region Properties
44    private ItemCollection<RefreshableHiveExperiment> hiveExperiments;
45    public ItemCollection<RefreshableHiveExperiment> HiveExperiments {
46      get { return hiveExperiments; }
47      set {
48        if (value != hiveExperiments) {
49          hiveExperiments = value;
50          OnHiveExperimentsChanged();
51        }
52      }
53    }
54
55    private List<Plugin> onlinePlugins;
56    public List<Plugin> OnlinePlugins {
57      get { return onlinePlugins; }
58      set { onlinePlugins = value; }
59    }
60
61    private List<Plugin> alreadyUploadedPlugins;
62    public List<Plugin> AlreadyUploadedPlugins {
63      get { return alreadyUploadedPlugins; }
64      set { alreadyUploadedPlugins = value; }
65    }
66    #endregion
67
68    public HiveClient() { }
69
70    #region Refresh
71    public void Refresh() {
72      OnRefreshing();
73
74      try {
75        hiveExperiments = new HiveItemCollection<RefreshableHiveExperiment>();
76        var he = ServiceLocator.Instance.CallHiveService<IEnumerable<HiveExperiment>>(s => s.GetHiveExperiments());
77        hiveExperiments.AddRange(he.Select(x => new RefreshableHiveExperiment(x)).OrderBy(x => x.HiveExperiment.Name));
78      }
79      catch {
80        hiveExperiments = null;
81        throw;
82      }
83      finally {
84        OnRefreshed();
85      }
86    }
87    public void RefreshAsync(Action<Exception> exceptionCallback) {
88      var call = new Func<Exception>(delegate() {
89        try {
90          Refresh();
91        }
92        catch (Exception ex) {
93          return ex;
94        }
95        return null;
96      });
97      call.BeginInvoke(delegate(IAsyncResult result) {
98        Exception ex = call.EndInvoke(result);
99        if (ex != null) exceptionCallback(ex);
100      }, null);
101    }
102    #endregion
103
104    #region Store
105    public static void Store(IHiveItem item) {
106      if (item.Id == Guid.Empty) {
107        if (item is RefreshableHiveExperiment) {
108          HiveClient.Instance.UploadExperiment((RefreshableHiveExperiment)item);
109        }
110      } else {
111        if (item is HiveExperiment)
112          ServiceLocator.Instance.CallHiveService(s => s.UpdateHiveExperiment((HiveExperiment)item));
113      }
114    }
115    public static void StoreAsync(Action<Exception> exceptionCallback, IHiveItem item) {
116      var call = new Func<Exception>(delegate() {
117        try {
118          Store(item);
119        }
120        catch (Exception ex) {
121          return ex;
122        }
123        return null;
124      });
125      call.BeginInvoke(delegate(IAsyncResult result) {
126        Exception ex = call.EndInvoke(result);
127        if (ex != null) exceptionCallback(ex);
128      }, null);
129    }
130    #endregion
131
132    #region Delete
133    public static void Delete(IHiveItem item) {
134      if (item is HiveExperiment)
135        ServiceLocator.Instance.CallHiveService(s => s.DeleteHiveExperiment(item.Id));
136      if (item is RefreshableHiveExperiment)
137        ServiceLocator.Instance.CallHiveService(s => s.DeleteHiveExperiment(item.Id));
138      item.Id = Guid.Empty;
139    }
140    #endregion
141
142    #region Events
143    public event EventHandler Refreshing;
144    private void OnRefreshing() {
145      EventHandler handler = Refreshing;
146      if (handler != null) handler(this, EventArgs.Empty);
147    }
148    public event EventHandler Refreshed;
149    private void OnRefreshed() {
150      var handler = Refreshed;
151      if (handler != null) handler(this, EventArgs.Empty);
152    }
153    public event EventHandler HiveExperimentsChanged;
154    private void OnHiveExperimentsChanged() {
155      var handler = HiveExperimentsChanged;
156      if (handler != null) handler(this, EventArgs.Empty);
157    }
158    #endregion
159
160    public static void StartExperiment(Action<Exception> exceptionCallback, RefreshableHiveExperiment refreshableHiveExperiment) {
161      HiveClient.StoreAsync(
162        new Action<Exception>((Exception ex) => {
163          refreshableHiveExperiment.HiveExperiment.ExecutionState = ExecutionState.Prepared;
164          exceptionCallback(ex);
165        }), refreshableHiveExperiment);
166      refreshableHiveExperiment.HiveExperiment.ExecutionState = ExecutionState.Started;
167    }
168
169    public static void PauseExperiment(HiveExperiment hiveExperiment) {
170      ServiceLocator.Instance.CallHiveService(service => {
171        foreach (HiveJob job in hiveExperiment.GetAllHiveJobs()) {
172          if (job.Job.State != JobState.Finished && job.Job.State != JobState.Aborted && job.Job.State != JobState.Failed)
173            service.PauseJob(job.Job.Id);
174        }
175      });
176      hiveExperiment.ExecutionState = ExecutionState.Paused;
177    }
178
179    public static void StopExperiment(HiveExperiment hiveExperiment) {
180      ServiceLocator.Instance.CallHiveService(service => {
181        foreach (HiveJob job in hiveExperiment.GetAllHiveJobs()) {
182          if (job.Job.State != JobState.Finished && job.Job.State != JobState.Aborted && job.Job.State != JobState.Failed)
183            service.StopJob(job.Job.Id);
184        }
185      });
186      // execution state does not need to be set. it will be set to Stopped, when all jobs have been downloaded
187    }
188
189    #region Upload Experiment
190    private void UploadExperiment(RefreshableHiveExperiment refreshableHiveExperiment) {
191      try {
192        refreshableHiveExperiment.HiveExperiment.Progress = new Progress("Connecting to server...");
193        refreshableHiveExperiment.HiveExperiment.IsProgressing = true;
194        ServiceLocator.Instance.CallHiveService(service => {
195          IEnumerable<string> resourceNames = ToResourceNameList(refreshableHiveExperiment.HiveExperiment.ResourceNames);
196          var resourceIds = new List<Guid>();
197          foreach (var resourceName in resourceNames) {
198            Guid resourceId = service.GetResourceId(resourceName);
199            if (resourceId == Guid.Empty) {
200              throw new ResourceNotFoundException(string.Format("Could not find the resource '{0}'", resourceName));
201            }
202            resourceIds.Add(resourceId);
203          }
204
205          foreach (OptimizerHiveJob hiveJob in refreshableHiveExperiment.HiveExperiment.HiveJobs.OfType<OptimizerHiveJob>()) {
206            hiveJob.SetIndexInParentOptimizerList(null);
207          }
208
209          // upload HiveExperiment
210          refreshableHiveExperiment.HiveExperiment.Progress.Status = "Uploading HiveExperiment...";
211          refreshableHiveExperiment.HiveExperiment.Id = service.AddHiveExperiment(refreshableHiveExperiment.HiveExperiment);
212
213          int totalJobCount = refreshableHiveExperiment.HiveExperiment.GetAllHiveJobs().Count();
214          int jobCount = 0;
215
216          // upload plugins
217          refreshableHiveExperiment.HiveExperiment.Progress.Status = "Uploading plugins...";
218          this.OnlinePlugins = service.GetPlugins();
219          this.AlreadyUploadedPlugins = new List<Plugin>();
220          Plugin configFilePlugin = UploadConfigurationFile(service);
221          this.alreadyUploadedPlugins.Add(configFilePlugin);
222
223          // upload jobs
224          refreshableHiveExperiment.HiveExperiment.Progress.Status = "Uploading jobs...";
225
226          foreach (HiveJob hiveJob in refreshableHiveExperiment.HiveExperiment.HiveJobs) {
227            UploadJobWithChildren(refreshableHiveExperiment.HiveExperiment.Progress, service, hiveJob, null, resourceIds, ref jobCount, totalJobCount, configFilePlugin.Id, refreshableHiveExperiment.HiveExperiment.UseLocalPlugins, refreshableHiveExperiment.HiveExperiment.Id, refreshableHiveExperiment.Log);
228          }
229
230          if (refreshableHiveExperiment.RefreshAutomatically) refreshableHiveExperiment.StartResultPolling();
231        });
232      }
233      finally {
234        refreshableHiveExperiment.HiveExperiment.IsProgressing = false;
235      }
236    }
237
238    /// <summary>
239    /// Uploads the local configuration file as plugin
240    /// </summary>
241    private static Plugin UploadConfigurationFile(IHiveService service) {
242      string exeFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "HeuristicLab 3.3.exe");
243      string configFileName = Path.GetFileName(ConfigurationManager.OpenExeConfiguration(exeFilePath).FilePath);
244      string configFilePath = ConfigurationManager.OpenExeConfiguration(exeFilePath).FilePath;
245
246      Plugin configPlugin = new Plugin() { Name = "Configuration", IsLocal = true, Version = new Version() };
247      PluginData configFile = new PluginData() { FileName = configFileName, Data = File.ReadAllBytes(configFilePath) };
248      configPlugin.Id = service.AddPlugin(configPlugin, new List<PluginData> { configFile });
249      return configPlugin;
250    }
251
252    /// <summary>
253    /// Uploads the given job and all its child-jobs while setting the proper parentJobId values for the childs
254    /// </summary>
255    /// <param name="service"></param>
256    /// <param name="hiveJob"></param>
257    /// <param name="parentHiveJob">shall be null if its the root job</param>
258    /// <param name="groups"></param>
259    private void UploadJobWithChildren(IProgress progress, IHiveService service, HiveJob hiveJob, HiveJob parentHiveJob, IEnumerable<Guid> groups, ref int jobCount, int totalJobCount, Guid configPluginId, bool useLocalPlugins, Guid hiveExperimentId, ILog log) {
260      jobCount++;
261      progress.Status = string.Format("Serializing job {0} of {1}", jobCount, totalJobCount);
262      JobData jobData;
263      List<IPluginDescription> plugins;
264
265      if (hiveJob.ItemJob.ComputeInParallel &&
266        (hiveJob.ItemJob.Item is Optimization.Experiment || hiveJob.ItemJob.Item is Optimization.BatchRun)) {
267        hiveJob.Job.IsParentJob = true;
268        hiveJob.Job.FinishWhenChildJobsFinished = true;
269        jobData = hiveJob.GetAsJobData(true, out plugins);
270      } else {
271        hiveJob.Job.IsParentJob = false;
272        hiveJob.Job.FinishWhenChildJobsFinished = false;
273        jobData = hiveJob.GetAsJobData(false, out plugins);
274      }
275
276      TryAndRepeat(() => {
277        hiveJob.Job.PluginsNeededIds = PluginUtil.GetPluginDependencies(service, this.onlinePlugins, this.alreadyUploadedPlugins, plugins, useLocalPlugins);
278      }, -1, "Failed to upload plugins");
279      hiveJob.Job.PluginsNeededIds.Add(configPluginId);
280      hiveJob.Job.HiveExperimentId = hiveExperimentId;
281
282      progress.Status = string.Format("Uploading job {0} of {1} ({2} kb, {3} objects)", jobCount, totalJobCount, jobData.Data.Count() / 1024, hiveJob.ItemJob.GetObjectGraphObjects().Count());
283      progress.ProgressValue = (double)jobCount / totalJobCount;
284
285      log.LogMessage(progress.Status);
286      TryAndRepeat(() => {
287        if (parentHiveJob != null) {
288          hiveJob.Job.Id = service.AddChildJob(parentHiveJob.Job.Id, hiveJob.Job, jobData);
289        } else {
290          hiveJob.Job.Id = service.AddJob(hiveJob.Job, jobData, groups.ToList());
291        }
292      }, -1, "Failed to add job");
293
294      foreach (HiveJob child in hiveJob.ChildHiveJobs) {
295        UploadJobWithChildren(progress, service, child, hiveJob, groups, ref jobCount, totalJobCount, configPluginId, useLocalPlugins, hiveExperimentId, log);
296      }
297    }
298    #endregion
299
300    #region Download Experiment
301    public static void LoadExperiment(HiveExperiment hiveExperiment) {
302      hiveExperiment.Progress = new Progress();
303      try {
304        hiveExperiment.IsProgressing = true;
305        int totalJobCount = 0;
306        IEnumerable<LightweightJob> allJobs;
307
308        hiveExperiment.Progress.Status = "Connecting to Server...";
309        // fetch all Job objects to create the full tree of tree of HiveJob objects
310        hiveExperiment.Progress.Status = "Downloading list of jobs...";
311        allJobs = ServiceLocator.Instance.CallHiveService(s => s.GetLightweightExperimentJobs(hiveExperiment.Id));
312        totalJobCount = allJobs.Count();
313
314        HiveJobDownloader downloader = new HiveJobDownloader(allJobs.Select(x => x.Id));
315        downloader.StartAsync();
316
317        while (!downloader.IsFinished) {
318          hiveExperiment.Progress.ProgressValue = downloader.FinishedCount / (double)totalJobCount;
319          hiveExperiment.Progress.Status = string.Format("Downloading/deserializing jobs... ({0}/{1} finished)", downloader.FinishedCount, totalJobCount);
320          Thread.Sleep(500);
321
322          if (downloader.IsFaulted) {
323            throw downloader.Exception;
324          }
325        }
326        IDictionary<Guid, HiveJob> allHiveJobs = downloader.Results;
327
328        hiveExperiment.HiveJobs = new ItemCollection<HiveJob>(allHiveJobs.Values.Where(x => !x.Job.ParentJobId.HasValue));
329
330        if (hiveExperiment.IsFinished()) {
331          hiveExperiment.ExecutionState = Core.ExecutionState.Stopped;
332        } else {
333          hiveExperiment.ExecutionState = Core.ExecutionState.Started;
334        }
335
336        // build child-job tree
337        foreach (HiveJob hiveJob in hiveExperiment.HiveJobs) {
338          BuildHiveJobTree(hiveJob, allJobs, allHiveJobs);
339        }
340
341        hiveExperiment.OnLoaded();
342      }
343      finally {
344        hiveExperiment.IsProgressing = false;
345      }
346    }
347
348    private static void BuildHiveJobTree(HiveJob parentHiveJob, IEnumerable<LightweightJob> allJobs, IDictionary<Guid, HiveJob> allHiveJobs) {
349      IEnumerable<LightweightJob> childJobs = from job in allJobs
350                                              where job.ParentJobId.HasValue && job.ParentJobId.Value == parentHiveJob.Job.Id
351                                              orderby job.DateCreated ascending
352                                              select job;
353      foreach (LightweightJob job in childJobs) {
354        HiveJob childHiveJob = allHiveJobs[job.Id];
355        parentHiveJob.AddChildHiveJob(childHiveJob);
356        BuildHiveJobTree(childHiveJob, allJobs, allHiveJobs);
357      }
358    }
359    #endregion
360
361    /// <summary>
362    /// Converts a string which can contain Ids separated by ';' to a enumerable
363    /// </summary>
364    private static IEnumerable<string> ToResourceNameList(string resourceNames) {
365      if (!string.IsNullOrEmpty(resourceNames)) {
366        return resourceNames.Split(';');
367      } else {
368        return new List<string>();
369      }
370    }
371
372    public static ItemJob LoadItemJob(Guid jobId) {
373      JobData jobData = ServiceLocator.Instance.CallHiveService(s => s.GetJobData(jobId));
374      try {
375        return PersistenceUtil.Deserialize<ItemJob>(jobData.Data);
376      }
377      catch {
378        return null;
379      }
380    }
381
382    /// <summary>
383    /// Executes the action. If it throws an exception it is repeated until repetition-count is reached.
384    /// If repetitions is -1, it is repeated infinitely.
385    /// </summary>
386    public static void TryAndRepeat(Action action, int repetitions, string errorMessage) {
387      while (true) {
388        try { action(); return; }
389        catch (Exception e) {
390          if (repetitions == 0)
391            throw new HiveException(errorMessage, e);
392          repetitions--;
393        }
394      }
395    }
396  }
397}
Note: See TracBrowser for help on using the repository browser.