Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Services.Hive/3.3/HiveDao.cs @ 10439

Last change on this file since 10439 was 9665, checked in by ascheibe, 11 years ago

#2030 merged hive performance branch back into trunk

File size: 41.8 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2013 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.Data.Linq;
25using System.Linq;
26using System.Linq.Expressions;
27using DT = HeuristicLab.Services.Hive.DataTransfer;
28
29namespace HeuristicLab.Services.Hive.DataAccess {
30  public class HiveDao : IHiveDao {
31    public static HiveDataContext CreateContext(bool longRunning = false) {
32      var context = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString);
33      if (longRunning) context.CommandTimeout = (int)Settings.Default.LongRunningDatabaseCommandTimeout.TotalSeconds;
34      return context;
35    }
36
37    #region Task Methods
38    public DT.Task GetTask(Guid id) {
39      using (var db = CreateContext()) {
40        return DT.Convert.ToDto(db.Tasks.SingleOrDefault(x => x.TaskId == id));
41      }
42    }
43
44    public IEnumerable<DT.Task> GetTasks(Expression<Func<Task, bool>> predicate) {
45      using (var db = CreateContext()) {
46        return db.Tasks.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
47      }
48    }
49
50    public IEnumerable<DT.LightweightTask> GetLightweightTasks(Expression<Func<Task, bool>> predicate) {
51      List<DT.LightweightTask> tasks = new List<DT.LightweightTask>();
52
53      using (var db = CreateContext()) {
54        var tasksQuery = db.Tasks.Where(predicate).Select(task => new { task.TaskId, task.ExecutionTimeMs, task.ParentTaskId, task.StateLogs, task.State, task.Command });
55        var taskDatasQuery = db.Tasks.Where(predicate).Where(task => task.JobData != null).Select(task => new { task.TaskId, task.JobData.LastUpdate });
56
57        foreach (var task in tasksQuery) {
58          DT.LightweightTask t = new DT.LightweightTask();
59          t.Id = task.TaskId;
60          t.ExecutionTime = TimeSpan.FromMilliseconds(task.ExecutionTimeMs);
61          t.ParentTaskId = task.ParentTaskId;
62          t.StateLog = task.StateLogs == null ? new List<DT.StateLog>() : task.StateLogs.Select(x => DataTransfer.Convert.ToDto(x)).OrderBy(x => x.DateTime).ToList();
63          t.State = DataTransfer.Convert.ToDto(task.State);
64          t.Command = DataTransfer.Convert.ToDto(task.Command);
65          t.LastTaskDataUpdate = taskDatasQuery.Where(x => x.TaskId == task.TaskId).Count() > 0 ? taskDatasQuery.Select(x => x.LastUpdate).First() : DateTime.MinValue;
66          tasks.Add(t);
67        }
68      }
69      return tasks;
70    }
71
72    public IEnumerable<DT.LightweightTask> GetLightweightTasksWithoutStateLog(Expression<Func<Task, bool>> predicate) {
73      List<DT.LightweightTask> tasks = new List<DT.LightweightTask>();
74
75      using (var db = CreateContext()) {
76        var tasksQuery = db.Tasks.Where(predicate).Select(task => new { task.TaskId, task.ExecutionTimeMs, task.ParentTaskId, task.State, task.Command });
77        var taskDatasQuery = db.Tasks.Where(predicate).Where(task => task.JobData != null).Select(task => new { task.TaskId, task.JobData.LastUpdate });
78
79        foreach (var task in tasksQuery) {
80          DT.LightweightTask t = new DT.LightweightTask();
81          t.Id = task.TaskId;
82          t.ExecutionTime = TimeSpan.FromMilliseconds(task.ExecutionTimeMs);
83          t.ParentTaskId = task.ParentTaskId;
84          t.StateLog = new List<DT.StateLog>();
85          t.State = DataTransfer.Convert.ToDto(task.State);
86          t.Command = DataTransfer.Convert.ToDto(task.Command);
87          t.LastTaskDataUpdate = taskDatasQuery.Where(x => x.TaskId == task.TaskId).Count() > 0 ? taskDatasQuery.Select(x => x.LastUpdate).First() : DateTime.MinValue;
88          tasks.Add(t);
89        }
90      }
91      return tasks;
92    }
93
94    public Guid AddTask(DT.Task dto) {
95      using (var db = CreateContext()) {
96        var entity = DT.Convert.ToEntity(dto);
97        db.Tasks.InsertOnSubmit(entity);
98        db.SubmitChanges();
99        foreach (Guid pluginId in dto.PluginsNeededIds) {
100          db.RequiredPlugins.InsertOnSubmit(new RequiredPlugin() { TaskId = entity.TaskId, PluginId = pluginId });
101        }
102        db.SubmitChanges();
103        return entity.TaskId;
104      }
105    }
106
107    public void UpdateTaskAndPlugins(DT.Task dto) {
108      using (var db = CreateContext()) {
109        var entity = db.Tasks.FirstOrDefault(x => x.TaskId == dto.Id);
110        if (entity == null) db.Tasks.InsertOnSubmit(DT.Convert.ToEntity(dto));
111        else DT.Convert.ToEntity(dto, entity);
112        foreach (Guid pluginId in dto.PluginsNeededIds) {
113          if (db.RequiredPlugins.Count(p => p.PluginId == pluginId) == 0) {
114            db.RequiredPlugins.InsertOnSubmit(new RequiredPlugin() { TaskId = entity.TaskId, PluginId = pluginId });
115          }
116        }
117        db.SubmitChanges();
118      }
119    }
120
121    public void UpdateTaskAndStateLogs(DT.Task dto) {
122      using (var db = CreateContext()) {
123        DataLoadOptions dlo = new DataLoadOptions();
124        dlo.LoadWith<Task>(x => x.StateLogs);
125        db.LoadOptions = dlo;
126
127        var entity = db.Tasks.FirstOrDefault(x => x.TaskId == dto.Id);
128        if (entity == null) db.Tasks.InsertOnSubmit(DT.Convert.ToEntity(dto));
129        else DT.Convert.ToEntity(dto, entity);
130        db.SubmitChanges();
131      }
132    }
133
134    public void UpdateTask(DT.Task dto) {
135      using (var db = CreateContext()) {
136        db.DeferredLoadingEnabled = false;
137
138        var entity = db.Tasks.FirstOrDefault(x => x.TaskId == dto.Id);
139        if (entity == null) db.Tasks.InsertOnSubmit(DT.Convert.ToEntity(dto));
140        else DT.Convert.ToEntityTaskOnly(dto, entity);
141        db.SubmitChanges();
142      }
143    }
144
145    public void DeleteTask(Guid id) {
146      using (var db = CreateContext()) {
147        var entity = db.Tasks.FirstOrDefault(x => x.TaskId == id);
148        if (entity != null) db.Tasks.DeleteOnSubmit(entity);
149        db.SubmitChanges(); // taskData and child tasks are deleted by db-trigger
150      }
151    }
152
153    /// <summary>
154    /// returns all parent tasks which are waiting for their child tasks to finish
155    /// </summary>
156    /// <param name="resourceIds">list of resourceids which for which the task should be valid</param>
157    /// <param name="count">maximum number of task to return</param>
158    /// <param name="finished">if true, all parent task which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned</param>
159    /// <returns></returns>
160    public IEnumerable<DT.Task> GetParentTasks(IEnumerable<Guid> resourceIds, int count, bool finished) {
161      using (var db = CreateContext()) {
162        var query = from ar in db.AssignedResources
163                    where resourceIds.Contains(ar.ResourceId)
164                       && ar.Task.State == TaskState.Waiting
165                       && ar.Task.IsParentTask
166                       && (finished ? ar.Task.FinishWhenChildJobsFinished : !ar.Task.FinishWhenChildJobsFinished)
167                       && (from child in db.Tasks
168                           where child.ParentTaskId == ar.Task.TaskId
169                           select child.State == TaskState.Finished
170                               || child.State == TaskState.Aborted
171                               || child.State == TaskState.Failed).All(x => x)
172                       && (from child in db.Tasks // avoid returning WaitForChildTasks task where no child-task exist (yet)
173                           where child.ParentTaskId == ar.Task.TaskId
174                           select child).Count() > 0
175                    orderby ar.Task.Priority descending, db.Random()
176                    select DT.Convert.ToDto(ar.Task);
177        return count == 0 ? query.ToArray() : query.Take(count).ToArray();
178      }
179    }
180
181    public IEnumerable<TaskInfoForScheduler> GetWaitingTasks(DT.Slave slave) {
182      using (var db = CreateContext()) {
183        var resourceIds = GetParentResources(slave.Id).Select(r => r.Id);
184        //Originally we checked here if there are parent tasks which should be calculated (with GetParentTasks(resourceIds, count, false);).
185        //Because there is at the moment no case where this makes sense (there don't exist parent tasks which need to be calculated),
186        //we skip this step because it's wasted runtime
187
188        var query = from ar in db.AssignedResources
189                    where resourceIds.Contains(ar.ResourceId)
190                       && !(ar.Task.IsParentTask && ar.Task.FinishWhenChildJobsFinished)
191                       && ar.Task.State == TaskState.Waiting
192                       && ar.Task.CoresNeeded <= slave.FreeCores
193                       && ar.Task.MemoryNeeded <= slave.FreeMemory
194                    select new TaskInfoForScheduler() { TaskId = ar.Task.TaskId, JobId = ar.Task.JobId, Priority = ar.Task.Priority };
195        var waitingTasks = query.ToArray();
196        return waitingTasks;
197      }
198    }
199
200    public DT.Task UpdateTaskState(Guid taskId, TaskState taskState, Guid? slaveId, Guid? userId, string exception) {
201      using (var db = CreateContext()) {
202        db.DeferredLoadingEnabled = false;
203
204        db.StateLogs.InsertOnSubmit(new StateLog {
205          TaskId = taskId,
206          State = taskState,
207          SlaveId = slaveId,
208          UserId = userId,
209          Exception = exception,
210          DateTime = DateTime.Now
211        });
212
213        var task = db.Tasks.SingleOrDefault(x => x.TaskId == taskId);
214        task.State = taskState;
215        db.SubmitChanges();
216      }
217
218      using (var db = CreateContext()) {
219        var task = db.Tasks.SingleOrDefault(x => x.TaskId == taskId);
220        return DT.Convert.ToDto(task);
221      }
222    }
223    #endregion
224
225    #region TaskData Methods
226    public DT.TaskData GetTaskData(Guid id) {
227      using (var db = CreateContext(true)) {
228        return DT.Convert.ToDto(db.TaskDatas.SingleOrDefault(x => x.TaskId == id));
229      }
230    }
231
232    public IEnumerable<DT.TaskData> GetTaskDatas(Expression<Func<TaskData, bool>> predicate) {
233      using (var db = CreateContext(true)) {
234        return db.TaskDatas.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
235      }
236    }
237
238    public Guid AddTaskData(DT.TaskData dto) {
239      using (var db = CreateContext(true)) {
240        var entity = DT.Convert.ToEntity(dto);
241        db.TaskDatas.InsertOnSubmit(entity);
242        db.SubmitChanges();
243        return entity.TaskId;
244      }
245    }
246
247    public void UpdateTaskData(DT.TaskData dto) {
248      using (var db = CreateContext(true)) {
249        var entity = db.TaskDatas.FirstOrDefault(x => x.TaskId == dto.TaskId);
250        if (entity == null) db.TaskDatas.InsertOnSubmit(DT.Convert.ToEntity(dto));
251        else DT.Convert.ToEntity(dto, entity);
252        db.SubmitChanges();
253      }
254    }
255
256    public void DeleteTaskData(Guid id) {
257      using (var db = CreateContext()) {
258        var entity = db.TaskDatas.FirstOrDefault(x => x.TaskId == id); // check if all the byte[] is loaded into memory here. otherwise work around to delete without loading it
259        if (entity != null) db.TaskDatas.DeleteOnSubmit(entity);
260        db.SubmitChanges();
261      }
262    }
263    #endregion
264
265    #region StateLog Methods
266    public DT.StateLog GetStateLog(Guid id) {
267      using (var db = CreateContext()) {
268        return DT.Convert.ToDto(db.StateLogs.SingleOrDefault(x => x.StateLogId == id));
269      }
270    }
271
272    public IEnumerable<DT.StateLog> GetStateLogs(Expression<Func<StateLog, bool>> predicate) {
273      using (var db = CreateContext()) {
274        return db.StateLogs.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
275      }
276    }
277
278    public Guid AddStateLog(DT.StateLog dto) {
279      using (var db = CreateContext()) {
280        var entity = DT.Convert.ToEntity(dto);
281        db.StateLogs.InsertOnSubmit(entity);
282        db.SubmitChanges();
283        return entity.StateLogId;
284      }
285    }
286
287    public void UpdateStateLog(DT.StateLog dto) {
288      using (var db = CreateContext()) {
289        var entity = db.StateLogs.FirstOrDefault(x => x.StateLogId == dto.Id);
290        if (entity == null) db.StateLogs.InsertOnSubmit(DT.Convert.ToEntity(dto));
291        else DT.Convert.ToEntity(dto, entity);
292        db.SubmitChanges();
293      }
294    }
295
296    public void DeleteStateLog(Guid id) {
297      using (var db = CreateContext()) {
298        var entity = db.StateLogs.FirstOrDefault(x => x.StateLogId == id);
299        if (entity != null) db.StateLogs.DeleteOnSubmit(entity);
300        db.SubmitChanges();
301      }
302    }
303    #endregion
304
305    #region Job Methods
306    public DT.Job GetJob(Guid id) {
307      using (var db = CreateContext()) {
308        return AddStatsToJob(db, DT.Convert.ToDto(db.Jobs.SingleOrDefault(x => x.JobId == id)));
309      }
310    }
311
312    private DT.Job AddStatsToJob(HiveDataContext db, DT.Job exp) {
313      if (exp == null)
314        return null;
315
316      var jobs = db.Tasks.Where(j => j.JobId == exp.Id);
317      exp.JobCount = jobs.Count();
318      exp.CalculatingCount = jobs.Count(j => j.State == TaskState.Calculating);
319      exp.FinishedCount = jobs.Count(j => j.State == TaskState.Finished);
320      return exp;
321    }
322
323    public IEnumerable<DT.Job> GetJobs(Expression<Func<Job, bool>> predicate) {
324      using (var db = CreateContext()) {
325        return db.Jobs.Where(predicate).Select(x => AddStatsToJob(db, DT.Convert.ToDto(x))).ToArray();
326      }
327    }
328
329    public IEnumerable<JobInfoForScheduler> GetJobInfoForScheduler(Expression<Func<Job, bool>> predicate) {
330      using (var db = CreateContext()) {
331        return db.Jobs.Where(predicate).Select(x => new JobInfoForScheduler() { Id = x.JobId, DateCreated = x.DateCreated, OwnerUserId = x.OwnerUserId }).ToArray();
332      }
333    }
334
335    public Guid AddJob(DT.Job dto) {
336      using (var db = CreateContext()) {
337        var entity = DT.Convert.ToEntity(dto);
338        db.Jobs.InsertOnSubmit(entity);
339        if (!db.UserPriorities.Any(x => x.UserId == dto.OwnerUserId))
340          EnqueueUserPriority(new DT.UserPriority { Id = dto.OwnerUserId, DateEnqueued = dto.DateCreated });
341        db.SubmitChanges();
342        return entity.JobId;
343      }
344    }
345
346    public void UpdateJob(DT.Job dto) {
347      using (var db = CreateContext()) {
348        var entity = db.Jobs.FirstOrDefault(x => x.JobId == dto.Id);
349        if (entity == null) db.Jobs.InsertOnSubmit(DT.Convert.ToEntity(dto));
350        else DT.Convert.ToEntity(dto, entity);
351        db.SubmitChanges();
352      }
353    }
354
355    public void DeleteJob(Guid id) {
356      using (var db = CreateContext()) {
357        var entity = db.Jobs.FirstOrDefault(x => x.JobId == id);
358        if (entity != null) db.Jobs.DeleteOnSubmit(entity);
359        db.SubmitChanges();
360      }
361    }
362    #endregion
363
364    #region JobPermission Methods
365    public DT.JobPermission GetJobPermission(Guid jobId, Guid grantedUserId) {
366      using (var db = CreateContext()) {
367        return DT.Convert.ToDto(db.JobPermissions.SingleOrDefault(x => x.JobId == jobId && x.GrantedUserId == grantedUserId));
368      }
369    }
370
371    public IEnumerable<DT.JobPermission> GetJobPermissions(Expression<Func<JobPermission, bool>> predicate) {
372      using (var db = CreateContext()) {
373        return db.JobPermissions.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
374      }
375    }
376
377    public void AddJobPermission(DT.JobPermission dto) {
378      using (var db = CreateContext()) {
379        var entity = DT.Convert.ToEntity(dto);
380        db.JobPermissions.InsertOnSubmit(entity);
381        db.SubmitChanges();
382      }
383    }
384
385    public void UpdateJobPermission(DT.JobPermission dto) {
386      using (var db = CreateContext()) {
387        var entity = db.JobPermissions.FirstOrDefault(x => x.JobId == dto.JobId && x.GrantedUserId == dto.GrantedUserId);
388        if (entity == null) db.JobPermissions.InsertOnSubmit(DT.Convert.ToEntity(dto));
389        else DT.Convert.ToEntity(dto, entity);
390        db.SubmitChanges();
391      }
392    }
393
394    public void DeleteJobPermission(Guid jobId, Guid grantedUserId) {
395      using (var db = CreateContext()) {
396        var entity = db.JobPermissions.FirstOrDefault(x => x.JobId == jobId && x.GrantedUserId == grantedUserId);
397        if (entity != null) db.JobPermissions.DeleteOnSubmit(entity);
398        db.SubmitChanges();
399      }
400    }
401
402    /// <summary>
403    /// Sets the permissions for a experiment. makes sure that only one permission per user exists.
404    /// </summary>
405    public void SetJobPermission(Guid jobId, Guid grantedByUserId, Guid grantedUserId, Permission permission) {
406      using (var db = CreateContext()) {
407        JobPermission jobPermission = db.JobPermissions.SingleOrDefault(x => x.JobId == jobId && x.GrantedUserId == grantedUserId);
408        if (jobPermission != null) {
409          if (permission == Permission.NotAllowed) {
410            // not allowed, delete
411            db.JobPermissions.DeleteOnSubmit(jobPermission);
412          } else {
413            // update
414            jobPermission.Permission = permission;
415            jobPermission.GrantedByUserId = grantedByUserId; // update grantedByUserId, always the last "granter" is stored
416          }
417        } else {
418          // insert
419          if (permission != Permission.NotAllowed) {
420            jobPermission = new JobPermission() { JobId = jobId, GrantedByUserId = grantedByUserId, GrantedUserId = grantedUserId, Permission = permission };
421            db.JobPermissions.InsertOnSubmit(jobPermission);
422          }
423        }
424        db.SubmitChanges();
425      }
426    }
427    #endregion
428
429    #region Plugin Methods
430    public DT.Plugin GetPlugin(Guid id) {
431      using (var db = CreateContext()) {
432        return DT.Convert.ToDto(db.Plugins.SingleOrDefault(x => x.PluginId == id));
433      }
434    }
435
436    public IEnumerable<DT.Plugin> GetPlugins(Expression<Func<Plugin, bool>> predicate) {
437      using (var db = CreateContext()) {
438        return db.Plugins.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
439      }
440    }
441
442    public Guid AddPlugin(DT.Plugin dto) {
443      using (var db = CreateContext()) {
444        var entity = DT.Convert.ToEntity(dto);
445        db.Plugins.InsertOnSubmit(entity);
446        db.SubmitChanges();
447        return entity.PluginId;
448      }
449    }
450
451    public void UpdatePlugin(DT.Plugin dto) {
452      using (var db = CreateContext()) {
453        var entity = db.Plugins.FirstOrDefault(x => x.PluginId == dto.Id);
454        if (entity == null) db.Plugins.InsertOnSubmit(DT.Convert.ToEntity(dto));
455        else DT.Convert.ToEntity(dto, entity);
456        db.SubmitChanges();
457      }
458    }
459
460    public void DeletePlugin(Guid id) {
461      using (var db = CreateContext()) {
462        var entity = db.Plugins.FirstOrDefault(x => x.PluginId == id);
463        if (entity != null) db.Plugins.DeleteOnSubmit(entity);
464        db.SubmitChanges();
465      }
466    }
467    #endregion
468
469    #region PluginData Methods
470    public DT.PluginData GetPluginData(Guid id) {
471      using (var db = CreateContext()) {
472        return DT.Convert.ToDto(db.PluginDatas.SingleOrDefault(x => x.PluginDataId == id));
473      }
474    }
475
476    public IEnumerable<DT.PluginData> GetPluginDatas(Expression<Func<PluginData, bool>> predicate) {
477      using (var db = CreateContext()) {
478        return db.PluginDatas.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
479      }
480    }
481
482    public Guid AddPluginData(DT.PluginData dto) {
483      using (var db = CreateContext()) {
484        var entity = DT.Convert.ToEntity(dto);
485        db.PluginDatas.InsertOnSubmit(entity);
486        db.SubmitChanges();
487        return entity.PluginDataId;
488      }
489    }
490
491    public void UpdatePluginData(DT.PluginData dto) {
492      using (var db = CreateContext()) {
493        var entity = db.PluginDatas.FirstOrDefault(x => x.PluginId == dto.PluginId);
494        if (entity == null) db.PluginDatas.InsertOnSubmit(DT.Convert.ToEntity(dto));
495        else DT.Convert.ToEntity(dto, entity);
496        db.SubmitChanges();
497      }
498    }
499
500    public void DeletePluginData(Guid id) {
501      using (var db = CreateContext()) {
502        var entity = db.PluginDatas.FirstOrDefault(x => x.PluginDataId == id);
503        if (entity != null) db.PluginDatas.DeleteOnSubmit(entity);
504        db.SubmitChanges();
505      }
506    }
507    #endregion
508
509    #region Slave Methods
510    public DT.Slave GetSlave(Guid id) {
511      using (var db = CreateContext()) {
512        return DT.Convert.ToDto(db.Resources.OfType<Slave>().SingleOrDefault(x => x.ResourceId == id));
513      }
514    }
515
516    public IEnumerable<DT.Slave> GetSlaves(Expression<Func<Slave, bool>> predicate) {
517      using (var db = CreateContext()) {
518        return db.Resources.OfType<Slave>().Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
519      }
520    }
521
522    public Guid AddSlave(DT.Slave dto) {
523      using (var db = CreateContext()) {
524        var entity = DT.Convert.ToEntity(dto);
525        db.Resources.InsertOnSubmit(entity);
526        db.SubmitChanges();
527        return entity.ResourceId;
528      }
529    }
530
531    public void UpdateSlave(DT.Slave dto) {
532      using (var db = CreateContext()) {
533        var entity = db.Resources.OfType<Slave>().FirstOrDefault(x => x.ResourceId == dto.Id);
534        if (entity == null) db.Resources.InsertOnSubmit(DT.Convert.ToEntity(dto));
535        else DT.Convert.ToEntity(dto, entity);
536        db.SubmitChanges();
537      }
538    }
539
540    public void DeleteSlave(Guid id) {
541      using (var db = CreateContext()) {
542        var entity = db.Resources.OfType<Slave>().FirstOrDefault(x => x.ResourceId == id);
543        if (entity != null) db.Resources.DeleteOnSubmit(entity);
544        db.SubmitChanges();
545      }
546    }
547    #endregion
548
549    #region SlaveGroup Methods
550    public DT.SlaveGroup GetSlaveGroup(Guid id) {
551      using (var db = CreateContext()) {
552        return DT.Convert.ToDto(db.Resources.OfType<SlaveGroup>().SingleOrDefault(x => x.ResourceId == id));
553      }
554    }
555
556    public IEnumerable<DT.SlaveGroup> GetSlaveGroups(Expression<Func<SlaveGroup, bool>> predicate) {
557      using (var db = CreateContext()) {
558        return db.Resources.OfType<SlaveGroup>().Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
559      }
560    }
561
562    public Guid AddSlaveGroup(DT.SlaveGroup dto) {
563      using (var db = CreateContext()) {
564        if (dto.Id == Guid.Empty)
565          dto.Id = Guid.NewGuid();
566        var entity = DT.Convert.ToEntity(dto);
567        db.Resources.InsertOnSubmit(entity);
568        db.SubmitChanges();
569        return entity.ResourceId;
570      }
571    }
572
573    public void UpdateSlaveGroup(DT.SlaveGroup dto) {
574      using (var db = CreateContext()) {
575        var entity = db.Resources.OfType<SlaveGroup>().FirstOrDefault(x => x.ResourceId == dto.Id);
576        if (entity == null) db.Resources.InsertOnSubmit(DT.Convert.ToEntity(dto));
577        else DT.Convert.ToEntity(dto, entity);
578        db.SubmitChanges();
579      }
580    }
581
582    public void DeleteSlaveGroup(Guid id) {
583      using (var db = CreateContext()) {
584        var entity = db.Resources.OfType<SlaveGroup>().FirstOrDefault(x => x.ResourceId == id);
585        if (entity != null) {
586          if (db.Resources.Where(r => r.ParentResourceId == id).Count() > 0) {
587            throw new InvalidOperationException("Cannot delete SlaveGroup as long as there are Slaves in the group");
588          }
589          db.Resources.DeleteOnSubmit(entity);
590        }
591        db.SubmitChanges();
592      }
593    }
594    #endregion
595
596    #region Resource Methods
597    public DT.Resource GetResource(Guid id) {
598      using (var db = CreateContext()) {
599        return DT.Convert.ToDto(db.Resources.SingleOrDefault(x => x.ResourceId == id));
600      }
601    }
602
603    public IEnumerable<DT.Resource> GetResources(Expression<Func<Resource, bool>> predicate) {
604      using (var db = CreateContext()) {
605        return db.Resources.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
606      }
607    }
608
609    public Guid AddResource(DT.Resource dto) {
610      using (var db = CreateContext()) {
611        var entity = DT.Convert.ToEntity(dto);
612        db.Resources.InsertOnSubmit(entity);
613        db.SubmitChanges();
614        return entity.ResourceId;
615      }
616    }
617
618    public void UpdateResource(DT.Resource dto) {
619      using (var db = CreateContext()) {
620        var entity = db.Resources.FirstOrDefault(x => x.ResourceId == dto.Id);
621        if (entity == null) db.Resources.InsertOnSubmit(DT.Convert.ToEntity(dto));
622        else DT.Convert.ToEntity(dto, entity);
623        db.SubmitChanges();
624      }
625    }
626
627    public void DeleteResource(Guid id) {
628      using (var db = CreateContext()) {
629        var entity = db.Resources.FirstOrDefault(x => x.ResourceId == id);
630        if (entity != null) db.Resources.DeleteOnSubmit(entity);
631        db.SubmitChanges();
632      }
633    }
634
635    public void AssignJobToResource(Guid taskId, IEnumerable<Guid> resourceIds) {
636      using (var db = CreateContext()) {
637        db.DeferredLoadingEnabled = false;
638
639        List<AssignedResource> assignedResources = new List<AssignedResource>();
640        foreach (Guid rId in resourceIds) {
641          assignedResources.Add(new AssignedResource() { TaskId = taskId, ResourceId = rId });
642        }
643        db.AssignedResources.InsertAllOnSubmit(assignedResources);
644        db.SubmitChanges();
645      }
646    }
647
648    public IEnumerable<DT.Resource> GetAssignedResources(Guid jobId) {
649      using (var db = CreateContext()) {
650        var job = db.Tasks.Where(x => x.TaskId == jobId).Single();
651        return job.AssignedResources.Select(x => DT.Convert.ToDto(x.Resource)).ToArray();
652      }
653    }
654
655    /// <summary>
656    /// Returns all parent resources of a resource (the given resource is also added)
657    /// </summary>
658    public IEnumerable<DT.Resource> GetParentResources(Guid resourceId) {
659      using (var db = CreateContext()) {
660        var resources = new List<Resource>();
661        CollectParentResources(resources, db.Resources.Where(r => r.ResourceId == resourceId).Single());
662        return resources.Select(r => DT.Convert.ToDto(r)).ToArray();
663      }
664    }
665
666    private static void CollectParentResources(ICollection<Resource> resources, Resource resource) {
667      if (resource == null) return;
668      resources.Add(resource);
669      CollectParentResources(resources, resource.ParentResource);
670    }
671
672    /// <summary>
673    /// Returns all child resources of a resource (without the given resource)
674    /// </summary>
675    public IEnumerable<DT.Resource> GetChildResources(Guid resourceId) {
676      using (var db = CreateContext()) {
677        return CollectChildResources(resourceId, db);
678      }
679    }
680
681    public IEnumerable<DT.Resource> CollectChildResources(Guid resourceId, HiveDataContext db) {
682      var childs = new List<DT.Resource>();
683      foreach (var child in db.Resources.Where(x => x.ParentResourceId == resourceId)) {
684        childs.Add(DT.Convert.ToDto(child));
685        childs.AddRange(CollectChildResources(child.ResourceId, db));
686      }
687      return childs;
688    }
689
690    public IEnumerable<DT.Task> GetJobsByResourceId(Guid resourceId) {
691      using (var db = CreateContext()) {
692        var resources = GetChildResources(resourceId).Select(x => x.Id).ToList();
693        resources.Add(resourceId);
694
695        var jobs = db.Tasks.Where(j =>
696          j.State == TaskState.Calculating &&
697          j.StateLogs.OrderByDescending(x => x.DateTime).First().SlaveId.HasValue &&
698          resources.Contains(j.StateLogs.OrderByDescending(x => x.DateTime).First().SlaveId.Value));
699        return jobs.Select(j => DT.Convert.ToDto(j)).ToArray();
700      }
701    }
702    #endregion
703
704    #region ResourcePermission Methods
705    public DT.ResourcePermission GetResourcePermission(Guid resourceId, Guid grantedUserId) {
706      using (var db = CreateContext()) {
707        return DT.Convert.ToDto(db.ResourcePermissions.SingleOrDefault(x => x.ResourceId == resourceId && x.GrantedUserId == grantedUserId));
708      }
709    }
710
711    public IEnumerable<DT.ResourcePermission> GetResourcePermissions(Expression<Func<ResourcePermission, bool>> predicate) {
712      using (var db = CreateContext()) {
713        return db.ResourcePermissions.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
714      }
715    }
716
717    public void AddResourcePermission(DT.ResourcePermission dto) {
718      using (var db = CreateContext()) {
719        var entity = db.ResourcePermissions.SingleOrDefault(x => x.ResourceId == dto.ResourceId && x.GrantedUserId == dto.GrantedUserId);
720        if (entity == null) { db.ResourcePermissions.InsertOnSubmit(DT.Convert.ToEntity(dto)); db.SubmitChanges(); }
721      }
722    }
723
724    public void UpdateResourcePermission(DT.ResourcePermission dto) {
725      using (var db = CreateContext()) {
726        var entity = db.ResourcePermissions.FirstOrDefault(x => x.ResourceId == dto.ResourceId && x.GrantedUserId == dto.GrantedUserId);
727        if (entity == null) db.ResourcePermissions.InsertOnSubmit(DT.Convert.ToEntity(dto));
728        else DT.Convert.ToEntity(dto, entity);
729        db.SubmitChanges();
730      }
731    }
732
733    public void DeleteResourcePermission(Guid resourceId, Guid grantedUserId) {
734      using (var db = CreateContext()) {
735        var entity = db.ResourcePermissions.FirstOrDefault(x => x.ResourceId == resourceId && x.GrantedUserId == grantedUserId);
736        if (entity != null) db.ResourcePermissions.DeleteOnSubmit(entity);
737        db.SubmitChanges();
738      }
739    }
740    #endregion
741
742    #region Authorization Methods
743    public Permission GetPermissionForTask(Guid taskId, Guid userId) {
744      using (var db = CreateContext()) {
745        return GetPermissionForJob(GetJobForTask(taskId), userId);
746      }
747    }
748
749    public Permission GetPermissionForJob(Guid jobId, Guid userId) {
750      using (var db = CreateContext()) {
751        Job job = db.Jobs.SingleOrDefault(x => x.JobId == jobId);
752        if (job == null) return Permission.NotAllowed;
753        if (job.OwnerUserId == userId) return Permission.Full;
754        JobPermission permission = db.JobPermissions.SingleOrDefault(p => p.JobId == jobId && p.GrantedUserId == userId);
755        return permission != null ? permission.Permission : Permission.NotAllowed;
756      }
757    }
758
759    public Guid GetJobForTask(Guid taskId) {
760      using (var db = CreateContext()) {
761        return db.Tasks.Single(j => j.TaskId == taskId).JobId;
762      }
763    }
764    #endregion
765
766    #region Lifecycle Methods
767    public DateTime GetLastCleanup() {
768      using (var db = CreateContext()) {
769        var entity = db.Lifecycles.SingleOrDefault();
770        return entity != null ? entity.LastCleanup : DateTime.MinValue;
771      }
772    }
773
774    public void SetLastCleanup(DateTime datetime) {
775      using (var db = CreateContext()) {
776        var entity = db.Lifecycles.SingleOrDefault();
777        if (entity != null) {
778          entity.LastCleanup = datetime;
779        } else {
780          entity = new Lifecycle();
781          entity.LifecycleId = 0; // always only one entry with ID:0
782          entity.LastCleanup = datetime;
783          db.Lifecycles.InsertOnSubmit(entity);
784        }
785        db.SubmitChanges();
786      }
787    }
788    #endregion
789
790    #region Downtime Methods
791    public DT.Downtime GetDowntime(Guid id) {
792      using (var db = CreateContext()) {
793        return DT.Convert.ToDto(db.Downtimes.SingleOrDefault(x => x.DowntimeId == id));
794      }
795    }
796
797    public IEnumerable<DT.Downtime> GetDowntimes(Expression<Func<Downtime, bool>> predicate) {
798      using (var db = CreateContext()) {
799        return db.Downtimes.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
800      }
801    }
802
803    public Guid AddDowntime(DT.Downtime dto) {
804      using (var db = CreateContext()) {
805        var entity = DT.Convert.ToEntity(dto);
806        db.Downtimes.InsertOnSubmit(entity);
807        db.SubmitChanges();
808        return entity.DowntimeId;
809      }
810    }
811
812    public void UpdateDowntime(DT.Downtime dto) {
813      using (var db = CreateContext()) {
814        var entity = db.Downtimes.FirstOrDefault(x => x.DowntimeId == dto.Id);
815        if (entity == null) db.Downtimes.InsertOnSubmit(DT.Convert.ToEntity(dto));
816        else DT.Convert.ToEntity(dto, entity);
817        db.SubmitChanges();
818      }
819    }
820
821    public void DeleteDowntime(Guid id) {
822      using (var db = CreateContext()) {
823        var entity = db.Downtimes.FirstOrDefault(x => x.DowntimeId == id);
824        if (entity != null) db.Downtimes.DeleteOnSubmit(entity);
825        db.SubmitChanges();
826      }
827    }
828    #endregion
829
830    #region Statistics Methods
831    public DT.Statistics GetStatistic(Guid id) {
832      using (var db = CreateContext()) {
833        return DT.Convert.ToDto(db.Statistics.SingleOrDefault(x => x.StatisticsId == id));
834      }
835    }
836
837    public IEnumerable<DT.Statistics> GetStatistics(Expression<Func<Statistics, bool>> predicate) {
838      using (var db = CreateContext()) {
839        return db.Statistics.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
840      }
841    }
842
843    public Guid AddStatistics(DT.Statistics dto) {
844      using (var db = CreateContext()) {
845        var entity = DT.Convert.ToEntity(dto);
846        db.Statistics.InsertOnSubmit(entity);
847        db.SubmitChanges();
848        foreach (var slaveStat in dto.SlaveStatistics) {
849          slaveStat.Id = entity.StatisticsId;
850          db.SlaveStatistics.InsertOnSubmit(DT.Convert.ToEntity(slaveStat));
851        }
852        if (dto.UserStatistics != null) {
853          foreach (var userStat in dto.UserStatistics) {
854            userStat.Id = entity.StatisticsId;
855            db.UserStatistics.InsertOnSubmit(DT.Convert.ToEntity(userStat));
856          }
857        }
858        db.SubmitChanges();
859        return entity.StatisticsId;
860      }
861    }
862
863    public void DeleteStatistics(Guid id) {
864      using (var db = CreateContext()) {
865        var entity = db.Statistics.FirstOrDefault(x => x.StatisticsId == id);
866        if (entity != null) db.Statistics.DeleteOnSubmit(entity);
867        db.SubmitChanges();
868      }
869    }
870
871    public Dictionary<Guid, int> GetWaitingTasksByUser() {
872      using (var db = CreateContext()) {
873        var waitingTasksByUser = from task in db.Tasks
874                                 where task.State == TaskState.Waiting
875                                 group task by task.Job.OwnerUserId into g
876                                 select new { UserId = g.Key, UsedCores = g.Count() };
877        return waitingTasksByUser.ToDictionary(x => x.UserId, x => x.UsedCores);
878      }
879    }
880
881    public Dictionary<Guid, int> GetWaitingTasksByUserForResources(List<Guid> resourceIds) {
882      using (var db = CreateContext()) {
883        var waitingTasksByUser = from task in db.Tasks
884                                 where task.State == TaskState.Waiting && task.AssignedResources.Any(x => resourceIds.Contains(x.ResourceId))
885                                 group task by task.Job.OwnerUserId into g
886                                 select new { UserId = g.Key, UsedCores = g.Count() };
887        return waitingTasksByUser.ToDictionary(x => x.UserId, x => x.UsedCores);
888      }
889    }
890
891    public Dictionary<Guid, int> GetCalculatingTasksByUser() {
892      using (var db = CreateContext()) {
893        var calculatingTasksByUser = from task in db.Tasks
894                                     where task.State == TaskState.Calculating
895                                     group task by task.Job.OwnerUserId into g
896                                     select new { UserId = g.Key, UsedCores = g.Count() };
897        return calculatingTasksByUser.ToDictionary(x => x.UserId, x => x.UsedCores);
898      }
899    }
900
901    public Dictionary<Guid, int> GetCalculatingTasksByUserForResources(List<Guid> resourceIds) {
902      using (var db = CreateContext()) {
903        var calculatingTasksByUser = from task in db.Tasks
904                                     where task.State == TaskState.Calculating && task.AssignedResources.Any(x => resourceIds.Contains(x.ResourceId))
905                                     group task by task.Job.OwnerUserId into g
906                                     select new { UserId = g.Key, UsedCores = g.Count() };
907        return calculatingTasksByUser.ToDictionary(x => x.UserId, x => x.UsedCores);
908      }
909    }
910
911    public List<DT.UserStatistics> GetUserStatistics() {
912      using (var db = CreateContext()) {
913        var userStats = new Dictionary<Guid, DT.UserStatistics>();
914
915        var usedCoresByUser = from job in db.Tasks
916                              where job.State == TaskState.Calculating
917                              group job by job.Job.OwnerUserId into g
918                              select new { UserId = g.Key, UsedCores = g.Count() };
919
920        foreach (var item in usedCoresByUser) {
921          if (!userStats.ContainsKey(item.UserId)) {
922            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
923          }
924          userStats[item.UserId].UsedCores += item.UsedCores;
925        }
926
927        var executionTimesByUser = from task in db.Tasks
928                                   group task by task.Job.OwnerUserId into g
929                                   select new { UserId = g.Key, ExecutionTime = TimeSpan.FromMilliseconds(g.Select(x => x.ExecutionTimeMs).Sum()) };
930        foreach (var item in executionTimesByUser) {
931          if (!userStats.ContainsKey(item.UserId)) {
932            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
933          }
934          userStats[item.UserId].ExecutionTime += item.ExecutionTime;
935        }
936
937        // execution times only of finished task - necessary to compute efficieny
938        var executionTimesFinishedJobs = from job in db.Tasks
939                                         where job.State == TaskState.Finished
940                                         group job by job.Job.OwnerUserId into g
941                                         select new { UserId = g.Key, ExecutionTimeFinishedJobs = TimeSpan.FromMilliseconds(g.Select(x => x.ExecutionTimeMs).Sum()) };
942
943        foreach (var item in executionTimesFinishedJobs) {
944          if (!userStats.ContainsKey(item.UserId)) {
945            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
946          }
947          userStats[item.UserId].ExecutionTimeFinishedJobs += item.ExecutionTimeFinishedJobs;
948        }
949
950        // start to end times only of finished task - necessary to compute efficiency
951        var startToEndTimesFinishedJobs = from job in db.Tasks
952                                          where job.State == TaskState.Finished
953                                          group job by job.Job.OwnerUserId into g
954                                          select new {
955                                            UserId = g.Key,
956                                            StartToEndTime = new TimeSpan(g.Select(x => x.StateLogs.OrderByDescending(sl => sl.DateTime).First().DateTime - x.StateLogs.OrderBy(sl => sl.DateTime).First().DateTime).Sum(ts => ts.Ticks))
957                                          };
958        foreach (var item in startToEndTimesFinishedJobs) {
959          if (!userStats.ContainsKey(item.UserId)) {
960            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
961          }
962          userStats[item.UserId].StartToEndTime += item.StartToEndTime;
963        }
964
965        // also consider executiontimes of DeletedJobStats
966        var deletedJobsExecutionTimesByUsers = from del in db.DeletedJobStatistics
967                                               group del by del.UserId into g
968                                               select new {
969                                                 UserId = g.Key,
970                                                 ExecutionTime = TimeSpan.FromSeconds(g.Select(x => x.ExecutionTimeS).Sum()),
971                                                 ExecutionTimeFinishedJobs = TimeSpan.FromSeconds(g.Select(x => x.ExecutionTimeSFinishedJobs).Sum()),
972                                                 StartToEndTime = TimeSpan.FromSeconds(g.Select(x => x.StartToEndTimeS).Sum())
973                                               };
974        foreach (var item in deletedJobsExecutionTimesByUsers) {
975          if (!userStats.ContainsKey(item.UserId)) {
976            userStats.Add(item.UserId, new DT.UserStatistics() { UserId = item.UserId });
977          }
978          userStats[item.UserId].ExecutionTime += item.ExecutionTime;
979          userStats[item.UserId].ExecutionTimeFinishedJobs += item.ExecutionTimeFinishedJobs;
980          userStats[item.UserId].StartToEndTime += item.StartToEndTime;
981        }
982
983        return userStats.Values.ToList();
984      }
985    }
986    #endregion
987
988    #region UserPriority Methods
989    public IEnumerable<DT.UserPriority> GetUserPriorities(Expression<Func<UserPriority, bool>> predicate) {
990      using (var db = CreateContext()) {
991        return db.UserPriorities.Where(predicate).Select(x => DT.Convert.ToDto(x)).ToArray();
992      }
993    }
994
995    public void EnqueueUserPriority(DT.UserPriority dto) {
996      using (var db = CreateContext()) {
997        var entity = db.UserPriorities.FirstOrDefault(x => x.UserId == dto.Id);
998        if (entity == null) db.UserPriorities.InsertOnSubmit(DT.Convert.ToEntity(dto));
999        else DT.Convert.ToEntity(dto, entity);
1000        db.SubmitChanges();
1001      }
1002    }
1003    #endregion
1004
1005    #region Helpers
1006    private void CollectChildTasks(HiveDataContext db, Guid parentTaskId, List<Task> collection) {
1007      var tasks = db.Tasks.Where(j => j.ParentTaskId == parentTaskId);
1008      foreach (var task in tasks) {
1009        collection.Add(task);
1010        if (task.IsParentTask)
1011          CollectChildTasks(db, task.TaskId, collection);
1012      }
1013    }
1014    #endregion
1015  }
1016}
Note: See TracBrowser for help on using the repository browser.