source: trunk/sources/HeuristicLab.Services.Hive/3.3/OptimizedHiveDao.cs @ 12146

Last change on this file since 12146 was 12146, checked in by ascheibe, 6 years ago

#2353

  • improved performance of status page
  • fixed code formatting and usings
  • simplified some expressions
File size: 11.5 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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 DT = HeuristicLab.Services.Hive.DataTransfer;
27
28namespace HeuristicLab.Services.Hive.DataAccess {
29  public class OptimizedHiveDao : IOptimizedHiveDao {
30    private HiveDataContext Db { get; set; }
31
32    public OptimizedHiveDao(HiveDataContext db) {
33      Db = db;
34    }
35
36    #region Task Methods
37    public Task GetTaskById(Guid taskId) {
38      return GetTaskByIdQuery(Db, taskId).SingleOrDefault();
39    }
40
41    private static readonly Func<HiveDataContext, Guid, IQueryable<Task>> GetTaskByIdQuery = CompiledQuery.Compile((HiveDataContext db, Guid taskId) =>
42      from t in db.Tasks
43      where t.TaskId == taskId
44      select t
45    );
46
47    public Task GetTaskByDto(DT.Task taskDto) {
48      var task = GetTaskById(taskDto.Id);
49      DT.Convert.ToEntity(taskDto, task);
50      return task;
51    }
52
53    public Tuple<Task, Guid?> GetTaskByIdAndLastStateLogSlaveId(Guid taskId) {
54      return GetTaskByIdAndLastStateLogSlaveIdQuery(Db, taskId).SingleOrDefault();
55    }
56
57    private static readonly Func<HiveDataContext, Guid, IQueryable<Tuple<Task, Guid?>>> GetTaskByIdAndLastStateLogSlaveIdQuery = CompiledQuery.Compile((HiveDataContext db, Guid taskId) =>
58      from t in db.Tasks
59      let lastStateLog = t.StateLogs.OrderByDescending(sl => sl.DateTime).FirstOrDefault()
60      where t.TaskId == taskId
61      select new Tuple<Task, Guid?>(t, lastStateLog != null ? lastStateLog.SlaveId : null)
62    );
63
64    private const string GetWaitingTasksQueryString = @"
65      WITH pr AS (
66        SELECT ResourceId, ParentResourceId
67        FROM [Resource]
68        WHERE ResourceId = {0}
69        UNION ALL
70        SELECT r.ResourceId, r.ParentResourceId
71        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
72      )
73      SELECT DISTINCT t.TaskId, t.JobId, t.Priority
74      FROM pr JOIN AssignedResources ar ON ar.ResourceId = pr.ResourceId
75          JOIN Task t ON t.TaskId = ar.TaskId
76      WHERE NOT (t.IsParentTask = 1 AND t.FinishWhenChildJobsFinished = 1)
77          AND t.TaskState = {1}
78          AND t.CoresNeeded <= {2}
79          AND t.MemoryNeeded <= {3}
80    ";
81
82    public IEnumerable<TaskInfoForScheduler> GetWaitingTasks(Slave slave) {
83      //Originally we checked here if there are parent tasks which should be calculated (with GetParentTasks(resourceIds, count, false);).
84      //Because there is at the moment no case where this makes sense (there don't exist parent tasks which need to be calculated),
85      //we skip this step because it's wasted runtime
86      return Db.ExecuteQuery<TaskInfoForScheduler>(GetWaitingTasksQueryString, slave.ResourceId, Enum.GetName(typeof(TaskState), TaskState.Waiting), slave.FreeCores, slave.FreeMemory);
87    }
88
89    public IQueryable<DT.LightweightTask> GetLightweightTasks(Guid jobId) {
90      return GetLightweightTasksQuery(Db, jobId);
91    }
92
93    private static readonly Func<HiveDataContext, Guid, IQueryable<DT.LightweightTask>> GetLightweightTasksQuery = CompiledQuery.Compile((HiveDataContext db, Guid jobId) =>
94        from task in db.Tasks
95        where task.JobId == jobId
96        select new DT.LightweightTask {
97          Id = task.TaskId,
98          ExecutionTime = TimeSpan.FromMilliseconds(task.ExecutionTimeMs),
99          ParentTaskId = task.ParentTaskId,
100          StateLog = task.StateLogs.OrderBy(sl => sl.DateTime).Select(sl => ConvertStateLog(sl)).ToList(),
101          State = ConvertTaskState(task.State),
102          Command = ConvertCommand(task.Command),
103          LastTaskDataUpdate = task.JobData.LastUpdate
104        }
105    );
106
107    private static readonly Func<StateLog, DT.StateLog> ConvertStateLog = sl => DT.Convert.ToDto(sl);
108    private static readonly Func<TaskState, DT.TaskState> ConvertTaskState = ts => DT.Convert.ToDto(ts);
109    private static readonly Func<Command?, DT.Command?> ConvertCommand = c => DT.Convert.ToDto(c);
110
111    public void UpdateTask(Task task) {
112      Db.SubmitChanges();
113    }
114
115    public Task UpdateTaskState(Guid taskId, TaskState taskState, Guid? slaveId, Guid? userId, string exception) {
116      Db.StateLogs.InsertOnSubmit(new StateLog {
117        TaskId = taskId,
118        State = taskState,
119        SlaveId = slaveId,
120        UserId = userId,
121        Exception = exception,
122        DateTime = DateTime.Now
123      });
124
125      var task = GetTaskById(taskId);
126      task.State = taskState;
127
128      Db.SubmitChanges();
129
130      return task;
131    }
132
133    public Guid AddTask(Task task) {
134      Db.Tasks.InsertOnSubmit(task);
135      Db.SubmitChanges();
136      return task.TaskId;
137    }
138
139    public void AssignJobToResource(Guid taskId, IEnumerable<Guid> resourceIds) {
140      Db.AssignedResources.InsertAllOnSubmit(resourceIds.Select(resourceId => new AssignedResource { TaskId = taskId, ResourceId = resourceId }));
141      Db.SubmitChanges();
142    }
143
144    private const string TaskIsAllowedToBeCalculatedBySlaveQueryString = @"
145      WITH pr AS (
146        SELECT ResourceId, ParentResourceId
147        FROM [Resource]
148        WHERE ResourceId = {0}
149        UNION ALL
150        SELECT r.ResourceId, r.ParentResourceId
151        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
152      )
153      SELECT COUNT(ar.TaskId)
154      FROM pr JOIN AssignedResources ar ON pr.ResourceId = ar.ResourceId
155      WHERE ar.TaskId = {1}
156    ";
157
158    public bool TaskIsAllowedToBeCalculatedBySlave(Guid taskId, Guid slaveId) {
159      return Db.ExecuteQuery<int>(TaskIsAllowedToBeCalculatedBySlaveQueryString, slaveId, taskId).First() > 0;
160    }
161    #endregion
162
163    #region TaskData Methods
164    public TaskData GetTaskDataById(Guid id) {
165      return GetTaskDataByIdQuery(Db, id).SingleOrDefault();
166    }
167
168    private static readonly Func<HiveDataContext, Guid, IQueryable<TaskData>> GetTaskDataByIdQuery = CompiledQuery.Compile((HiveDataContext db, Guid id) =>
169      from t in db.TaskDatas
170      where t.TaskId == id
171      select t
172    );
173
174    public TaskData GetTaskDataByDto(DT.TaskData dto) {
175      var taskData = GetTaskDataById(dto.TaskId);
176      DT.Convert.ToEntity(dto, taskData);
177      return taskData;
178    }
179
180    public void UpdateTaskData(TaskData taskData) {
181      Db.SubmitChanges();
182    }
183    #endregion
184
185    #region Plugin Methods
186    public Plugin GetPluginById(Guid pluginId) {
187      return GetPluginByIdQuery(Db, pluginId).SingleOrDefault();
188    }
189
190    private static readonly Func<HiveDataContext, Guid, IQueryable<Plugin>> GetPluginByIdQuery = CompiledQuery.Compile((HiveDataContext db, Guid pluginId) =>
191      from p in db.Plugins
192      where p.PluginId == pluginId
193      select p
194    );
195    #endregion
196
197    #region Slave Methods
198    public Slave GetSlaveById(Guid id) {
199      return GetSlaveByIdQuery(Db, id).SingleOrDefault();
200    }
201
202    private static readonly Func<HiveDataContext, Guid, IQueryable<Slave>> GetSlaveByIdQuery = CompiledQuery.Compile((HiveDataContext db, Guid slaveId) =>
203      from s in db.Resources.OfType<Slave>()
204      where s.ResourceId == slaveId
205      select s
206    );
207
208    public void UpdateSlave(Slave slave) {
209      Db.SubmitChanges();
210    }
211
212    private const string DowntimeQueryString = @"
213      WITH pr AS (
214        SELECT ResourceId, ParentResourceId
215        FROM [Resource]
216        WHERE ResourceId = {0}
217        UNION ALL
218        SELECT r.ResourceId, r.ParentResourceId
219        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
220      )
221      SELECT COUNT(dt.DowntimeId)
222      FROM pr JOIN [Downtime] dt ON pr.ResourceId = dt.ResourceId
223      WHERE {1} BETWEEN dt.StartDate AND dt.EndDate
224        AND dt.DowntimeType = {2}
225      ";
226
227    public bool SlaveHasToShutdownComputer(Guid slaveId) {
228      return Db.ExecuteQuery<int>(DowntimeQueryString, slaveId, DateTime.Now, DowntimeType.Shutdown.ToString()).FirstOrDefault() > 0;
229    }
230
231    public bool SlaveIsAllowedToCalculate(Guid slaveId) {
232      return Db.ExecuteQuery<int>(DowntimeQueryString, slaveId, DateTime.Now, DowntimeType.Offline.ToString()).FirstOrDefault() == 0;
233    }
234    #endregion
235
236    #region Resource Methods
237    public IEnumerable<Guid> GetAssignedResourceIds(Guid taskId) {
238      return GetAssignedResourceIdsQuery(Db, taskId);
239    }
240
241    private static readonly Func<HiveDataContext, Guid, IQueryable<Guid>> GetAssignedResourceIdsQuery = CompiledQuery.Compile((HiveDataContext db, Guid taskId) =>
242      from ar in db.AssignedResources
243      where ar.TaskId == taskId
244      select ar.ResourceId
245    );
246    #endregion
247
248
249    #region Website Methods
250    private const string GetAllResourceIdsString = @"SELECT ResourceId FROM [Resource]";
251    public IEnumerable<Guid> GetAllResourceIds() {
252      return Db.ExecuteQuery<Guid>(GetAllResourceIdsString);
253    }
254
255    private const string GetNumberOfWaitingTasksString = @"SELECT COUNT(TaskId)
256                                                           FROM [Task]
257                                                           WHERE TaskState LIKE 'Waiting'";
258    public int GetNumberOfWaitingTasks() {
259      return Db.ExecuteQuery<int>(GetNumberOfWaitingTasksString).Single();
260    }
261
262    private class UserTasks {
263      public Guid OwnerUserId;
264      public int Count;
265    }
266
267    private const string GetCalculatingTasksByUserString = @"SELECT Job.OwnerUserId, COUNT(Task.TaskId) as Count
268                                                             FROM Task, Job
269                                                             WHERE TaskState LIKE 'Calculating' AND Task.JobId = Job.JobId
270                                                             GROUP BY Job.OwnerUserId";
271
272    public Dictionary<Guid, int> GetCalculatingTasksByUser() {
273      var result = Db.ExecuteQuery<UserTasks>(GetCalculatingTasksByUserString);
274      Dictionary<Guid, int> lst = new Dictionary<Guid, int>();
275
276      foreach (var userTask in result) {
277        lst.Add(userTask.OwnerUserId, userTask.Count);
278      }
279      return lst;
280    }
281
282    private const string GetWaitingTasksByUserString = @"SELECT Job.OwnerUserId, COUNT(Task.TaskId) as Count
283                                                         FROM Task, Job
284                                                         WHERE TaskState LIKE 'Waiting' AND Task.JobId = Job.JobId
285                                                         GROUP BY Job.OwnerUserId";
286
287    public Dictionary<Guid, int> GetWaitingTasksByUser() {
288      var result = Db.ExecuteQuery<UserTasks>(GetWaitingTasksByUserString);
289      Dictionary<Guid, int> lst = new Dictionary<Guid, int>();
290
291      foreach (var userTask in result) {
292        lst.Add(userTask.OwnerUserId, userTask.Count);
293      }
294      return lst;
295    }
296    #endregion
297  }
298}
Note: See TracBrowser for help on using the repository browser.