Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveStatisticsGenerator.cs @ 12469

Last change on this file since 12469 was 12468, checked in by dglaser, 9 years ago

#2388:
HeuristicLab.Services.Hive.DataAccess-3.3:

  • Added PersistenceManager with corresponding daos
  • Updated SQL Scripts
  • Fixed folder structure (interfaces, manager)
  • Removed duplicated IHiveDao and HiveDao (the HiveDao/OptimizedHiveDao that is actually used is located in HeuristicLab.Services.Hive)

HeuristicLab.Service.Hive-3.3:

  • Added PersistenceManager to the ServiceLocater
  • Updated and improved the HiveStatisticsGenerator
  • Updated HiveJanitor
File size: 13.2 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 HeuristicLab.Services.Hive.DataAccess;
27using HeuristicLab.Services.Hive.DataAccess.Manager;
28
29namespace HeuristicLab.Services.Hive {
30  public class HiveStatisticsGenerator : IStatisticsGenerator {
31
32    private const string UnknownUserName = "Unknown";
33    private static readonly TimeSpan SmallestTimeSpan = new TimeSpan(0, 5, 0);
34
35    public void GenerateStatistics() {
36      using (var pm = new PersistenceManager()) {
37        pm.UseTransaction(() => {
38          UpdateDimUserTable(pm);
39          UpdateDimJobTable(pm);
40          UpdateDimClients(pm);
41          pm.SubmitChanges();
42        });
43
44        pm.UseTransaction(() => {
45          var newTime = UpdateDimTimeTable(pm);
46          if (newTime != null) {
47            pm.SubmitChanges();
48            UpdateFactClientInfoTable(newTime, pm);
49            UpdateTaskFacts(newTime, pm);
50            try {
51              pm.SubmitChanges();
52            }
53            catch (DuplicateKeyException e) {
54              var logger = LogFactory.GetLogger(typeof(HiveStatisticsGenerator).Namespace);
55              logger.Log(string.Format(
56                @"Propable change from summertime to wintertime, resulting in overlapping times.
57                          On wintertime to summertime change, slave timeouts and a fact gap will occur.
58                          Exception Details: {0}", e));
59            }
60          }
61        });
62      }
63    }
64
65    private DimTime UpdateDimTimeTable(PersistenceManager pm) {
66      var dimTimeDao = pm.DimTimeDao;
67      var now = DateTime.Now;
68      var timeEntry = new DimTime {
69        Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0),
70        Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
71        Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
72        Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
73        Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
74      };
75      // using SaveOrAttach instead of save because the table can only be updated once every minute
76      // (pk restriction) save would cause a duplicate key exception if the method is accidentally
77      // called more than once every minute (e.g. restarting the service within a minute)
78      return dimTimeDao.SaveOrAttach(timeEntry);
79    }
80
81    private void UpdateDimUserTable(PersistenceManager pm) {
82      var dimUserDao = pm.DimUserDao;
83      var resourceDao = pm.ResourceDao;
84      var jobDao = pm.JobDao;
85      var existingUserIds = dimUserDao.GetAll().Select(x => x.UserId);
86      var vaildResourceOwnerIds = resourceDao.GetResourcesWithValidOwner().Select(x => x.OwnerUserId.Value);
87      var jobOwnerIds = jobDao.GetAll().Select(x => x.OwnerUserId);
88      var newUserIds = vaildResourceOwnerIds
89        .Union(jobOwnerIds)
90        .Where(id => !existingUserIds.Contains(id))
91        .ToList();
92      dimUserDao.Save(newUserIds.Select(x => new DimUser {
93        UserId = x,
94        Name = GetUserName(x)
95      }));
96    }
97
98    private void UpdateDimJobTable(PersistenceManager pm) {
99      var dimJobDao = pm.DimJobDao;
100      var jobDao = pm.JobDao;
101      var dimJobIds = dimJobDao.GetAll().Select(x => x.JobId);
102      var newJobs = jobDao.GetAll()
103        .Where(x => !dimJobIds.Contains(x.JobId))
104        .Select(x => new {
105          JobId = x.JobId,
106          UserId = x.OwnerUserId,
107          JobName = x.Name ?? string.Empty,
108        })
109        .ToList();
110      dimJobDao.Save(newJobs.Select(x => new DimJob {
111        JobId = x.JobId,
112        JobName = x.JobName,
113        UserId = x.UserId,
114        UserName = GetUserName(x.UserId)
115      }));
116    }
117
118    private void UpdateDimClients(PersistenceManager pm) {
119      var dimClientDao = pm.DimClientDao;
120      var slaveDao = pm.SlaveDao;
121      var slaves = slaveDao.GetAll();
122      var recentlyAddedClients = dimClientDao.GetRecentlyAddedClients();
123      var slaveIds = slaves.Select(x => x.ResourceId);
124
125      var removedClientIds = recentlyAddedClients
126        .Where(x => !slaveIds.Contains(x.ResourceId))
127        .Select(x => x.Id);
128      var modifiedClients =
129        from slave in slaves
130        join client in recentlyAddedClients on slave.ResourceId equals client.ResourceId
131        where (slave.Name != client.Name
132               || slave.ParentResourceId != client.ResourceGroupId
133               || slave.ParentResource.ParentResourceId != client.ResourceGroup2Id)
134        select new {
135          SlaveId = slave.ResourceId,
136          ClientId = client.Id
137        };
138      var clientIds = dimClientDao.GetAll().Select(x => x.ResourceId);
139      var modifiedClientIds = modifiedClients.Select(x => x.SlaveId);
140      var newClients = slaves
141        .Where(x => !clientIds.Contains(x.ResourceId)
142                    || modifiedClientIds.Contains(x.ResourceId))
143        .Select(x => new {
144          x.ResourceId,
145          x.Name,
146          ResourceGroupId = x.ParentResourceId,
147          ResourceGroup2Id = x.ParentResource.ParentResourceId
148        })
149        .ToList();
150
151      var clientsToUpdate = removedClientIds.Union(modifiedClients.Select(x => x.ClientId));
152      dimClientDao.UpdateExpirationTime(clientsToUpdate, DateTime.Now);
153      dimClientDao.Save(newClients.Select(x => new DimClient {
154        ResourceId = x.ResourceId,
155        Name = x.Name,
156        ExpirationTime = null,
157        ResourceGroupId = x.ResourceGroupId,
158        ResourceGroup2Id = x.ResourceGroup2Id
159      }));
160    }
161
162    private void UpdateFactClientInfoTable(DimTime newTime, PersistenceManager pm) {
163      var factClientInfoDao = pm.FactClientInfoDao;
164      var slaveDao = pm.SlaveDao;
165      var dimClientDao = pm.DimClientDao;
166
167      var newRawFactInfos =
168        from s in slaveDao.GetAll()
169        join c in dimClientDao.GetRecentlyAddedClients() on s.ResourceId equals c.ResourceId
170        join lcf in factClientInfoDao.GetLastUpdateTimestamps() on c.ResourceId equals lcf.ResourceId into joinCf
171        from cf in joinCf.DefaultIfEmpty()
172        select new {
173          ClientId = c.Id,
174          UserId = s.OwnerUserId ?? Guid.Empty,
175          TotalCores = s.Cores ?? 0,
176          FreeCores = s.FreeCores ?? 0,
177          TotalMemory = s.Memory ?? 0,
178          FreeMemory = s.FreeMemory ?? 0,
179          CpuUtilization = s.CpuUtilization,
180          SlaveState = s.SlaveState,
181          IsAllowedToCalculate = s.IsAllowedToCalculate,
182          LastFactTimestamp = cf.Timestamp
183        };
184
185      factClientInfoDao.Save(
186        from x in newRawFactInfos.ToList()
187        let duration = x.LastFactTimestamp != null
188                       ? (newTime.Time - (DateTime)x.LastFactTimestamp).TotalMinutes
189                       : SmallestTimeSpan.TotalMinutes
190        select new FactClientInfo {
191          ClientId = x.ClientId,
192          DimTime = newTime,
193          UserId = x.UserId,
194          NumUsedCores = x.TotalCores - x.FreeCores,
195          NumTotalCores = x.TotalMemory,
196          UsedMemory = x.TotalMemory - x.FreeMemory,
197          TotalMemory = x.TotalMemory,
198          CpuUtilization = x.CpuUtilization,
199          SlaveState = x.SlaveState,
200          TotalTimeIdle = x.SlaveState == SlaveState.Idle && x.IsAllowedToCalculate ? duration : 0.0,
201          TotalTimeCalculating = x.SlaveState == SlaveState.Calculating ? duration : 0.0,
202          TotalTimeUnavailable = x.SlaveState == SlaveState.Idle && !x.IsAllowedToCalculate ? duration : 0.0,
203          TotalTimeOffline = x.SlaveState == SlaveState.Offline ? duration : 0.0
204        }
205      );
206    }
207
208    private void UpdateTaskFacts(DimTime newTime, PersistenceManager pm) {
209      var factTaskDao = pm.FactTaskDao;
210      var taskDao = pm.TaskDao;
211      var dimClientDao = pm.DimClientDao;
212      var stateLogDao = pm.StateLogDao;
213
214      var factTaskIds = factTaskDao.GetAll().Select(x => x.TaskId);
215      var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks().Select(x => new {
216        x.TaskId,
217        x.DimTimeStart,
218        x.LastClientId
219      });
220
221      var newTasks =
222        from task in taskDao.GetAllChildTasks()
223        let stateLogs = task.StateLogs.OrderByDescending(x => x.DateTime)
224        let lastSlaveId = stateLogs.First(x => x.SlaveId != null).SlaveId
225        where (!factTaskIds.Contains(task.TaskId)
226               || notFinishedFactTasks.Select(x => x.TaskId).Contains(task.TaskId))
227        join lastFactTask in notFinishedFactTasks on task.TaskId equals lastFactTask.TaskId into lastFactPerTask
228        from lastFact in lastFactPerTask.DefaultIfEmpty()
229        join client in dimClientDao.GetRecentlyAddedClients() on lastSlaveId equals client.ResourceId into clientsPerSlaveId
230        from client in clientsPerSlaveId.DefaultIfEmpty()
231        select new {
232          TaskId = task.TaskId,
233          JobId = task.JobId,
234          Priority = task.Priority,
235          CoresRequired = task.CoresNeeded,
236          MemoryRequired = task.MemoryNeeded,
237          State = task.State,
238          StateLogs = stateLogs,
239          DimTimeStart = lastFact != null ? lastFact.DimTimeStart : newTime,
240          LastClientId = client != null
241                         ? client.Id : lastFact != null
242                         ? lastFact.LastClientId : (Guid?)null
243        };
244
245      var endStates = new[] { TaskState.Finished, TaskState.Failed, TaskState.Aborted };
246      factTaskDao.Save(
247        from x in newTasks.ToList()
248        let stateLogsLinkedList = new LinkedList<StateLog>(x.StateLogs.OrderBy(y => y.DateTime))
249        let lastStateLog = stateLogsLinkedList.OrderByDescending(y => y.DateTime).FirstOrDefault(sl => sl.Exception != null)
250        select new FactTask {
251          TaskId = x.TaskId,
252          JobId = x.JobId,
253          DimTimeStart = x.DimTimeStart,
254          DimTimeEnd = endStates.Contains(x.State) ? newTime : null,
255          LastClientId = x.LastClientId,
256          Priority = x.Priority,
257          CoresRequired = x.CoresRequired,
258          MemoryRequired = x.MemoryRequired,
259          NumCalculationRuns = stateLogsLinkedList.CountCalculationRuns(),
260          NumRetries = stateLogsLinkedList.CountRetries(),
261          TotalWaitingTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Waiting),
262          TotalRuntime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Calculating && stateLog.NextIs(y => y.State == TaskState.Transferring)),
263          TotalTransferTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Transferring),
264          TaskState = x.State,
265          Exception = lastStateLog == null ? string.Empty : lastStateLog.Exception
266        });
267      factTaskDao.Delete(notFinishedFactTasks.Select(x => x.TaskId));
268    }
269
270    private string GetUserName(Guid userId) {
271      try {
272        var userManager = ServiceLocator.Instance.UserManager;
273        var user = userManager.GetUserById(userId);
274        return user != null ? user.UserName : UnknownUserName;
275      }
276      catch (Exception) {
277        return UnknownUserName;
278      }
279    }
280  }
281
282  public static class StateLogLinkedListExtensions {
283    public static int CountCalculationRuns(this LinkedList<StateLog> stateLogs) {
284      return stateLogs.EnumerateNodes()
285                      .Count(sl => sl.Value.State == TaskState.Calculating && sl.NextIs(nsl => nsl.State == TaskState.Transferring));
286    }
287
288    public static int CountRetries(this LinkedList<StateLog> stateLogs) {
289      return stateLogs.EnumerateNodes()
290                      .Count(sl => sl.Value.State == TaskState.Calculating && sl.Next != null && sl.NextIs(nsl => nsl.State != TaskState.Transferring));
291    }
292
293    public static double SumTotalTimeWhere(this LinkedList<StateLog> stateLogs, Predicate<LinkedListNode<StateLog>> predicate) {
294      return stateLogs.EnumerateNodes()
295                      .Where(stateLog => predicate(stateLog))
296                      .Sum(stateLog => stateLog.Next != null ? (stateLog.Next.Value.DateTime - stateLog.Value.DateTime).TotalMinutes : 0.0);
297    }
298  }
299
300  public static class LinkedListExtensions {
301    public static IEnumerable<LinkedListNode<T>> EnumerateNodes<T>(this LinkedList<T> list) {
302      var node = list.First;
303      while (node != null) {
304        yield return node;
305        node = node.Next;
306      }
307    }
308
309    public static bool NextIs<T>(this LinkedListNode<T> node, Predicate<T> predicate) {
310      return node.Next != null && predicate(node.Next.Value);
311    }
312  }
313}
Note: See TracBrowser for help on using the repository browser.