Free cookie consent management tool by TermsFeed Policy Generator

source: branches/OaaS/HeuristicLab.Services.Hive/3.3/HiveDao.cs @ 8384

Last change on this file since 8384 was 8326, checked in by fschoepp, 12 years ago

#1888:

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