Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2388:

HeuristicLab.Services.WebApp-3.3:

  • Fixed a bug which caused the PluginManager to not reload an existing plugin
  • Changed Path.PathSeparator to Path.DirectorySeparatorChar

HeuristicLab.Services.Hive-3.3:

  • HiveStatisticsGenerator.cs: When moving a client to another group is now recognized properly
  • Fixed the 'unknown user' problem

Installers/HiveJanitorServiceInstaller.nsi:

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