Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2388:

HeuristicLab.Services.Hive.DataAccess-3.3:

  • updated database schema
  • updated sql scripts
  • updated HiveStatisticsGenerator

HeuristicLab.Services.WebApp-3.3:

  • merged from trunk

HeuristicLab.Services.WebApp.Status-3.3:

  • updated data api controller

HeuristicLab.Services.WebApp.Statistics-3.3:

  • added exception page
  • improved jobs, clients, users and groups 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 = Math.Round(x.CpuUtilization, 2),
244          SlaveState = x.SlaveState,
245          IdleTime = x.SlaveState == SlaveState.Idle && x.IsAllowedToCalculate ? duration : 0,
246          UnavailableTime = x.SlaveState == SlaveState.Idle && !x.IsAllowedToCalculate ? duration : 0,
247          OfflineTime = x.SlaveState == SlaveState.Offline ? duration : 0,
248          IsAllowedToCalculate = x.IsAllowedToCalculate
249        }
250      );
251    }
252
253    private void UpdateTaskFactsTable(DimTime newTime, PersistenceManager pm) {
254      var factTaskDao = pm.FactTaskDao;
255      var taskDao = pm.TaskDao;
256      var dimClientDao = pm.DimClientDao;
257      var stateLogDao = pm.StateLogDao;
258
259      var factTaskIds = factTaskDao.GetAll().Select(x => x.TaskId);
260      var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks().Select(x => new {
261        x.TaskId,
262        x.LastClientId
263      });
264
265      var newTasks =
266        from task in taskDao.GetAllChildTasks()
267        let stateLogs = task.StateLogs.OrderByDescending(x => x.DateTime)
268        let lastSlaveId = stateLogs.First(x => x.SlaveId != null).SlaveId
269        where (!factTaskIds.Contains(task.TaskId)
270               || notFinishedFactTasks.Select(x => x.TaskId).Contains(task.TaskId))
271        join lastFactTask in notFinishedFactTasks on task.TaskId equals lastFactTask.TaskId into lastFactPerTask
272        from lastFact in lastFactPerTask.DefaultIfEmpty()
273        join client in dimClientDao.GetActiveClients() on lastSlaveId equals client.ResourceId into clientsPerSlaveId
274        from client in clientsPerSlaveId.DefaultIfEmpty()
275        select new {
276          TaskId = task.TaskId,
277          JobId = task.JobId,
278          Priority = task.Priority,
279          CoresRequired = task.CoresNeeded,
280          MemoryRequired = task.MemoryNeeded,
281          State = task.State,
282          StateLogs = stateLogs.OrderBy(x => x.DateTime),
283          LastClientId = client != null
284                         ? client.Id : lastFact != null
285                         ? lastFact.LastClientId : (Guid?)null
286        };
287      factTaskDao.Save(
288        from x in newTasks.ToList()
289        let taskData = CalculateFactTaskData(x.StateLogs)
290        select new FactTask {
291          TaskId = x.TaskId,
292          JobId = x.JobId,
293          StartTime = taskData.StartTime,
294          EndTime = taskData.EndTime,
295          LastClientId = x.LastClientId,
296          Priority = x.Priority,
297          CoresRequired = x.CoresRequired,
298          MemoryRequired = x.MemoryRequired,
299          NumCalculationRuns = taskData.CalculationRuns,
300          NumRetries = taskData.Retries,
301          WaitingTime = taskData.WaitingTime,
302          CalculatingTime = taskData.CalculatingTime,
303          TransferTime = taskData.TransferTime,
304          TaskState = x.State,
305          Exception = taskData.Exception,
306          InitialWaitingTime = taskData.InitialWaitingTime
307        });
308      factTaskDao.Delete(notFinishedFactTasks.Select(x => x.TaskId));
309    }
310
311    private string GetUserName(Guid userId) {
312      try {
313        var userManager = ServiceLocator.Instance.UserManager;
314        var user = userManager.GetUserById(userId);
315        return user != null ? user.UserName : UnknownUserName;
316      }
317      catch (Exception) {
318        return UnknownUserName;
319      }
320    }
321
322    private class FactTaskData {
323      public int CalculationRuns { get; set; }
324      public int Retries { get; set; }
325      public long CalculatingTime { get; set; }
326      public long WaitingTime { get; set; }
327      public long TransferTime { get; set; }
328      public long InitialWaitingTime { get; set; }
329      public string Exception { get; set; }
330      public DateTime? StartTime { get; set; }
331      public DateTime? EndTime { get; set; }
332    }
333
334    private FactTaskData CalculateFactTaskData(IEnumerable<StateLog> stateLogs) {
335      var factTaskData = new FactTaskData();
336      var enumerator = stateLogs.GetEnumerator();
337      if (enumerator.MoveNext()) {
338        StateLog current = enumerator.Current, first = current, prev = null;
339        while (current != null) {
340          var next = enumerator.MoveNext() ? enumerator.Current : null;
341          int timeSpanInSeconds;
342          if (next != null) {
343            timeSpanInSeconds = (int)(next.DateTime - current.DateTime).TotalSeconds;
344          } else {
345            timeSpanInSeconds = (int)(DateTime.Now - current.DateTime).TotalSeconds;
346            factTaskData.Exception = current.Exception;
347          }
348          switch (current.State) {
349            case TaskState.Calculating:
350              factTaskData.CalculatingTime += timeSpanInSeconds;
351              factTaskData.CalculationRuns++;
352              if (factTaskData.CalculationRuns == 1) {
353                factTaskData.StartTime = current.DateTime;
354                factTaskData.InitialWaitingTime = (int)(current.DateTime - first.DateTime).TotalSeconds;
355              }
356              if (prev != null && prev.State != TaskState.Transferring) {
357                factTaskData.Retries++;
358              }
359              break;
360
361            case TaskState.Waiting:
362              factTaskData.WaitingTime += timeSpanInSeconds;
363              break;
364
365            case TaskState.Transferring:
366              factTaskData.TransferTime += timeSpanInSeconds;
367              break;
368
369            case TaskState.Finished:
370            case TaskState.Failed:
371            case TaskState.Aborted:
372              factTaskData.EndTime = current.DateTime;
373              break;
374          }
375          prev = current;
376          current = next;
377        }
378      }
379      return factTaskData;
380    }
381  }
382}
Note: See TracBrowser for help on using the repository browser.