Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2388:

HeuristicLab.Services.Hive.DataAccess-3.3:

  • updated daos
  • changed statistics database schema
  • updated HiveStatisticsGenerator

HeuristicLab.Services.WebApp.Statistics-3.3:

  • added jobs, client and user page
File size: 14.9 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    private static readonly TaskState[] CompletedStates = { TaskState.Finished, TaskState.Aborted, TaskState.Failed };
35
36    public void GenerateStatistics() {
37      using (var pm = new PersistenceManager()) {
38        pm.UseTransaction(() => {
39          UpdateDimUserTable(pm);
40          UpdateDimJobTable(pm);
41          UpdateDimClientsTable(pm);
42          pm.SubmitChanges();
43        });
44
45        DimTime time = null;
46        pm.UseTransaction(() => {
47          time = UpdateDimTimeTable(pm);
48          pm.SubmitChanges();
49        });
50
51        if (time != null) {
52          pm.UseTransaction(() => {
53            UpdateFactClientInfoTable(time, pm);
54            pm.SubmitChanges();
55          });
56
57          pm.UseTransaction(() => {
58            UpdateTaskFactsTable(time, pm);
59            try {
60              pm.SubmitChanges();
61              UpdateExistingDimJobs(pm);
62              pm.SubmitChanges();
63            }
64            catch (DuplicateKeyException e) {
65              var logger = LogFactory.GetLogger(typeof(HiveStatisticsGenerator).Namespace);
66              logger.Log(string.Format(
67                @"Propable change from summertime to wintertime, resulting in overlapping times.
68                          On wintertime to summertime change, slave timeouts and a fact gap will occur.
69                          Exception Details: {0}", e));
70            }
71          });
72        }
73      }
74    }
75
76    private DimTime UpdateDimTimeTable(PersistenceManager pm) {
77      var dimTimeDao = pm.DimTimeDao;
78      var now = DateTime.Now;
79      var timeEntry = new DimTime {
80        Time = now,
81        Minute = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0),
82        Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
83        Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
84        Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
85        Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
86      };
87      return dimTimeDao.Save(timeEntry);
88    }
89
90    private void UpdateDimUserTable(PersistenceManager pm) {
91      var dimUserDao = pm.DimUserDao;
92      var resourceDao = pm.ResourceDao;
93      var jobDao = pm.JobDao;
94      var existingUserIds = dimUserDao.GetAll().Select(x => x.UserId);
95      var vaildResourceOwnerIds = resourceDao.GetResourcesWithValidOwner().Select(x => x.OwnerUserId.Value);
96      var jobOwnerIds = jobDao.GetAll().Select(x => x.OwnerUserId);
97      var newUserIds = vaildResourceOwnerIds
98        .Union(jobOwnerIds)
99        .Where(id => !existingUserIds.Contains(id))
100        .ToList();
101      dimUserDao.Save(newUserIds.Select(x => new DimUser {
102        UserId = x,
103        Name = GetUserName(x)
104      }));
105    }
106
107    private void UpdateDimJobTable(PersistenceManager pm) {
108      var dimJobDao = pm.DimJobDao;
109      var jobDao = pm.JobDao;
110      var taskDao = pm.TaskDao;
111      var dimJobIds = dimJobDao.GetAll().Select(x => x.JobId);
112      var newJobs = jobDao.GetAll()
113        .Where(x => !dimJobIds.Contains(x.JobId))
114        .Select(x => new {
115          JobId = x.JobId,
116          UserId = x.OwnerUserId,
117          JobName = x.Name ?? string.Empty,
118          DateCreated = x.DateCreated,
119          TotalTasks = taskDao.GetAll().Count(y => y.JobId == x.JobId)
120        })
121        .ToList();
122      dimJobDao.Save(newJobs.Select(x => new DimJob {
123        JobId = x.JobId,
124        JobName = x.JobName,
125        UserId = x.UserId,
126        UserName = GetUserName(x.UserId),
127        DateCreated = x.DateCreated,
128        TotalTasks = x.TotalTasks,
129        CompletedTasks = 0,
130        DateCompleted = null
131      }));
132    }
133
134    private void UpdateExistingDimJobs(PersistenceManager pm) {
135      var dimJobDao = pm.DimJobDao;
136      var factTaskDao = pm.FactTaskDao;
137      foreach (var dimJob in dimJobDao.GetNotCompletedJobs()) {
138        var taskStates = factTaskDao.GetByJobId(dimJob.JobId)
139            .GroupBy(x => x.TaskState)
140            .Select(x => new {
141              State = x.Key,
142              Count = x.Count()
143            }).ToList();
144        int totalTasks = 0, completedTasks = 0;
145        foreach (var state in taskStates) {
146          totalTasks += state.Count;
147          if (CompletedStates.Contains(state.State)) {
148            completedTasks += state.Count;
149          }
150        }
151        if (totalTasks == completedTasks) {
152          dimJob.DateCompleted = factTaskDao.GetLastCompletedTaskFromJob(dimJob.JobId);
153        }
154        dimJob.TotalTasks = totalTasks;
155        dimJob.CompletedTasks = completedTasks;
156      }
157    }
158
159    private void UpdateDimClientsTable(PersistenceManager pm) {
160      var dimClientDao = pm.DimClientDao;
161      var slaveDao = pm.SlaveDao;
162      var slaves = slaveDao.GetAll();
163      var recentlyAddedClients = dimClientDao.GetActiveClients();
164      var slaveIds = slaves.Select(x => x.ResourceId);
165
166      var removedClientIds = recentlyAddedClients
167        .Where(x => !slaveIds.Contains(x.ResourceId))
168        .Select(x => x.Id);
169      var modifiedClients =
170        from slave in slaves
171        join client in recentlyAddedClients on slave.ResourceId equals client.ResourceId
172        where (slave.Name != client.Name
173               || slave.ParentResourceId != client.ResourceGroupId
174               || slave.ParentResource.ParentResourceId != client.ResourceGroup2Id)
175        select new {
176          SlaveId = slave.ResourceId,
177          ClientId = client.Id
178        };
179      var clientIds = dimClientDao.GetActiveClients().Select(x => x.ResourceId);
180      var modifiedClientIds = modifiedClients.Select(x => x.SlaveId);
181      var newClients = slaves
182        .Where(x => !clientIds.Contains(x.ResourceId)
183                    || modifiedClientIds.Contains(x.ResourceId))
184        .Select(x => new {
185          x.ResourceId,
186          x.Name,
187          ResourceGroupId = x.ParentResourceId,
188          GroupName = x.ParentResource.Name,
189          ResourceGroup2Id = x.ParentResource.ParentResourceId,
190          GroupName2 = x.ParentResource.ParentResource.Name
191        })
192        .ToList();
193
194      var clientsToUpdate = removedClientIds.Union(modifiedClients.Select(x => x.ClientId));
195      dimClientDao.UpdateExpirationTime(clientsToUpdate, DateTime.Now);
196      dimClientDao.Save(newClients.Select(x => new DimClient {
197        ResourceId = x.ResourceId,
198        Name = x.Name,
199        ExpirationTime = null,
200        ResourceGroupId = x.ResourceGroupId,
201        GroupName = x.GroupName,
202        ResourceGroup2Id = x.ResourceGroup2Id,
203        GroupName2 = x.GroupName2
204      }));
205    }
206
207    private void UpdateFactClientInfoTable(DimTime newTime, PersistenceManager pm) {
208      var factClientInfoDao = pm.FactClientInfoDao;
209      var slaveDao = pm.SlaveDao;
210      var dimClientDao = pm.DimClientDao;
211
212      var newRawFactInfos =
213        from s in slaveDao.GetAll()
214        join c in dimClientDao.GetActiveClients() on s.ResourceId equals c.ResourceId
215        join lcf in factClientInfoDao.GetLastUpdateTimestamps() on c.ResourceId equals lcf.ResourceId into joinCf
216        from cf in joinCf.DefaultIfEmpty()
217        select new {
218          ClientId = c.Id,
219          UserId = s.OwnerUserId ?? Guid.Empty,
220          TotalCores = s.Cores ?? 0,
221          FreeCores = s.FreeCores ?? 0,
222          TotalMemory = s.Memory ?? 0,
223          FreeMemory = s.FreeMemory ?? 0,
224          CpuUtilization = s.CpuUtilization,
225          SlaveState = s.SlaveState,
226          IsAllowedToCalculate = s.IsAllowedToCalculate,
227          LastFactTimestamp = cf.Timestamp
228        };
229
230      factClientInfoDao.Save(
231        from x in newRawFactInfos.ToList()
232        let duration = x.LastFactTimestamp != null
233                       ? (int)(newTime.Time - (DateTime)x.LastFactTimestamp).TotalSeconds
234                       : (int)SmallestTimeSpan.TotalSeconds
235        select new FactClientInfo {
236          ClientId = x.ClientId,
237          DimTime = newTime,
238          UserId = x.UserId,
239          NumUsedCores = x.TotalCores - x.FreeCores,
240          NumTotalCores = x.TotalCores,
241          UsedMemory = x.TotalMemory - x.FreeMemory,
242          TotalMemory = x.TotalMemory,
243          CpuUtilization = x.CpuUtilization,
244          SlaveState = x.SlaveState,
245          TotalTimeIdle = x.SlaveState == SlaveState.Idle && x.IsAllowedToCalculate ? duration : 0.0,
246          TotalTimeUnavailable = x.SlaveState == SlaveState.Idle && !x.IsAllowedToCalculate ? duration : 0.0,
247          TotalTimeOffline = x.SlaveState == SlaveState.Offline ? duration : 0.0
248        }
249      );
250    }
251
252    private void UpdateTaskFactsTable(DimTime newTime, PersistenceManager pm) {
253      var factTaskDao = pm.FactTaskDao;
254      var taskDao = pm.TaskDao;
255      var dimClientDao = pm.DimClientDao;
256      var stateLogDao = pm.StateLogDao;
257
258      var factTaskIds = factTaskDao.GetAll().Select(x => x.TaskId);
259      var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks().Select(x => new {
260        x.TaskId,
261        x.LastClientId
262      });
263
264      var newTasks =
265        from task in taskDao.GetAllChildTasks()
266        let stateLogs = task.StateLogs.OrderByDescending(x => x.DateTime)
267        let lastSlaveId = stateLogs.First(x => x.SlaveId != null).SlaveId
268        where (!factTaskIds.Contains(task.TaskId)
269               || notFinishedFactTasks.Select(x => x.TaskId).Contains(task.TaskId))
270        join lastFactTask in notFinishedFactTasks on task.TaskId equals lastFactTask.TaskId into lastFactPerTask
271        from lastFact in lastFactPerTask.DefaultIfEmpty()
272        join client in dimClientDao.GetActiveClients() on lastSlaveId equals client.ResourceId into clientsPerSlaveId
273        from client in clientsPerSlaveId.DefaultIfEmpty()
274        select new {
275          TaskId = task.TaskId,
276          JobId = task.JobId,
277          Priority = task.Priority,
278          CoresRequired = task.CoresNeeded,
279          MemoryRequired = task.MemoryNeeded,
280          State = task.State,
281          StateLogs = stateLogs.OrderBy(x => x.DateTime),
282          LastClientId = client != null
283                         ? client.Id : lastFact != null
284                         ? lastFact.LastClientId : (Guid?)null
285        };
286      factTaskDao.Save(
287        from x in newTasks.ToList()
288        let taskData = CalculateFactTaskData(x.StateLogs)
289        select new FactTask {
290          TaskId = x.TaskId,
291          JobId = x.JobId,
292          StartTime = taskData.StartTime,
293          EndTime = taskData.EndTime,
294          LastClientId = x.LastClientId,
295          Priority = x.Priority,
296          CoresRequired = x.CoresRequired,
297          MemoryRequired = x.MemoryRequired,
298          NumCalculationRuns = taskData.CalculationRuns,
299          NumRetries = taskData.Retries,
300          WaitingTime = taskData.WaitingTime,
301          CalculatingTime = taskData.CalculatingTime,
302          TransferTime = taskData.TransferTime,
303          TaskState = x.State,
304          Exception = taskData.Exception,
305          InitialWaitingTime = taskData.InitialWaitingTime
306        });
307      factTaskDao.Delete(notFinishedFactTasks.Select(x => x.TaskId));
308    }
309
310    private string GetUserName(Guid userId) {
311      try {
312        var userManager = ServiceLocator.Instance.UserManager;
313        var user = userManager.GetUserById(userId);
314        return user != null ? user.UserName : UnknownUserName;
315      }
316      catch (Exception) {
317        return UnknownUserName;
318      }
319    }
320
321    private class FactTaskData {
322      public int CalculationRuns { get; set; }
323      public int Retries { get; set; }
324      public double CalculatingTime { get; set; }
325      public double WaitingTime { get; set; }
326      public double TransferTime { get; set; }
327      public double InitialWaitingTime { get; set; }
328      public string Exception { get; set; }
329      public DateTime? StartTime { get; set; }
330      public DateTime? EndTime { get; set; }
331    }
332
333    private FactTaskData CalculateFactTaskData(IEnumerable<StateLog> stateLogs) {
334      var factTaskData = new FactTaskData();
335      var enumerator = stateLogs.GetEnumerator();
336      if (enumerator.MoveNext()) {
337        StateLog current = enumerator.Current, first = current, prev = null;
338        while (current != null) {
339          var next = enumerator.MoveNext() ? enumerator.Current : null;
340          int timeSpanInSeconds;
341          if (next != null) {
342            timeSpanInSeconds = (int)(next.DateTime - current.DateTime).TotalSeconds;
343          } else {
344            timeSpanInSeconds = (int)(DateTime.Now - current.DateTime).TotalSeconds;
345            factTaskData.Exception = current.Exception;
346          }
347          switch (current.State) {
348            case TaskState.Calculating:
349              factTaskData.CalculatingTime += timeSpanInSeconds;
350              factTaskData.CalculationRuns++;
351              if (factTaskData.CalculationRuns == 1) {
352                factTaskData.StartTime = current.DateTime;
353                factTaskData.InitialWaitingTime = (int)(current.DateTime - first.DateTime).TotalSeconds;
354              }
355              if (prev != null && prev.State != TaskState.Transferring) {
356                factTaskData.Retries++;
357              }
358              break;
359
360            case TaskState.Waiting:
361              factTaskData.WaitingTime += timeSpanInSeconds;
362              break;
363
364            case TaskState.Transferring:
365              factTaskData.TransferTime += timeSpanInSeconds;
366              break;
367
368            case TaskState.Finished:
369            case TaskState.Failed:
370            case TaskState.Aborted:
371              factTaskData.EndTime = current.DateTime;
372              break;
373          }
374          prev = current;
375          current = next;
376        }
377      }
378      return factTaskData;
379    }
380  }
381}
Note: See TracBrowser for help on using the repository browser.