Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 11223 was 11223, checked in by ascheibe, 10 years ago

fixed bugs in statistics generator and updated janitor service config

File size: 12.1 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.Data.Linq;
4using System.Linq;
5using System.Transactions;
6using HeuristicLab.Services.Access;
7using HeuristicLab.Services.Hive.DataAccess;
8
9namespace HeuristicLab.Services.Hive {
10  public class HiveStatisticsGenerator : IStatisticsGenerator {
11    private IUserManager userManager { get { return ServiceLocator.Instance.UserManager; } }
12
13    private static readonly TimeSpan SmallestTimeSpan = new TimeSpan(0, 5, 0);
14    private static readonly string UnknownUserName = "Unknown";
15
16    public void GenerateStatistics() {
17      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
18      using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) {
19
20        var newTime = UpdateDimensionTables(db);
21        db.SubmitChanges();
22
23        if (newTime != null) {
24          UpdateFactTables(newTime, db);
25          try {
26            db.SubmitChanges();
27          }
28          catch (DuplicateKeyException) {
29            // Propable change from summertime to wintertime, resulting in overlapping times
30            // On wintertime to summertime change, slave timeouts and a fact gap will occur
31          }
32        }
33
34        transaction.Complete();
35      }
36    }
37
38    private DimTime UpdateDimensionTables(HiveDataContext db) {
39      var newTime = UpdateTime(db);
40
41      UpdateUsers(db);
42      UpdateJobs(db);
43      UpdateClients(db);
44
45      return newTime;
46    }
47
48    private DimTime UpdateTime(HiveDataContext db) {
49      var lastUpdateTime =
50        (from t in db.DimTimes
51         orderby t.Time descending
52         select t.Time)
53        .FirstOrDefault();
54
55      var now = DateTime.Now;
56      DimTime newTime = null;
57
58      if (lastUpdateTime == default(DateTime) || lastUpdateTime + SmallestTimeSpan < now) {
59        newTime = new DimTime {
60          Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute - now.Minute % SmallestTimeSpan.Minutes, 0),
61          Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
62          Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
63          Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
64          Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
65        };
66        db.DimTimes.InsertOnSubmit(newTime);
67      }
68
69      return newTime;
70    }
71
72    private void UpdateUsers(HiveDataContext db) {
73      var newUsers =
74        from u in db.Resources.Where(x => x.OwnerUserId != null).Select(x => x.OwnerUserId.Value).Union(db.Jobs.Select(x => x.OwnerUserId))
75        where !db.DimUsers.Select(x => x.UserId).Contains(u)
76        select u;
77
78
79      var newDimUsers =
80     from u in newUsers.ToList()
81     select new DimUser {
82       UserId = u,
83       Name = userManager.GetUserById(u) != null ? userManager.GetUserById(u).UserName : UnknownUserName
84     };
85
86      db.DimUsers.InsertAllOnSubmit(newDimUsers);
87
88      // insert NULL-User
89      if (!db.DimUsers.Any(x => x.UserId == Guid.Empty)) {
90        db.DimUsers.InsertOnSubmit(new DimUser { UserId = Guid.Empty, Name = "NULL" });
91      }
92    }
93
94    private void UpdateJobs(HiveDataContext db) {
95      var newJobs =
96        from j in db.Jobs
97        where !db.DimJobs.Select(x => x.JobId).Contains(j.JobId)
98        select j;
99
100      var newDimJobs =
101        from j in newJobs.ToList()
102        select new DimJob {
103          JobId = j.JobId,
104          JobName = j.Name == null ? string.Empty : j.Name,
105          UserId = j.OwnerUserId,
106          UserName = userManager.GetUserById(j.OwnerUserId) != null ? userManager.GetUserById(j.OwnerUserId).UserName : UnknownUserName
107        };
108
109      db.DimJobs.InsertAllOnSubmit(newDimJobs);
110
111      // insert NULL-Job
112      if (!db.DimJobs.Any(x => x.JobId == Guid.Empty)) {
113        db.DimJobs.InsertOnSubmit(new DimJob { JobId = Guid.Empty, JobName = "NULL", UserId = Guid.Empty, UserName = "NULL" });
114      }
115    }
116
117    private void UpdateClients(HiveDataContext db) {
118      var removedClients =
119        from c in db.DimClients
120        where c.ExpirationTime == null &&
121              !db.Resources.OfType<Slave>().Select(x => x.ResourceId).Contains(c.ResourceId)
122        select c;
123
124      var modifiedClients =
125        from s in db.Resources.OfType<Slave>()
126        join c in db.DimClients on s.ResourceId equals c.ResourceId
127        where c.ExpirationTime == null
128              && (s.Name != c.Name || s.ParentResourceId != c.ResourceGroupId ||
129                  s.ParentResource.ParentResourceId != c.ResourceGroup2Id)
130        select new { Slave = s, Client = c };
131
132      foreach (var client in removedClients.Union(modifiedClients.Select(x => x.Client))) {
133        client.ExpirationTime = DateTime.Now;
134      }
135
136      var newClients =
137        from s in db.Resources.OfType<Slave>()
138        where !db.DimClients.Select(x => x.ResourceId).Contains(s.ResourceId)
139              || modifiedClients.Select(x => x.Slave.ResourceId).Contains(s.ResourceId)
140        select new {
141          Slave = s,
142          Group = s.ParentResourceId,
143          Group2 = s.ParentResource.ParentResourceId
144        };
145
146      var newDimClients =
147        from s in newClients.ToList()
148        select new DimClient {
149          ResourceId = s.Slave.ResourceId,
150          Name = s.Slave.Name,
151          ExpirationTime = null,
152          ResourceGroupId = s.Group,
153          ResourceGroup2Id = s.Group2
154        };
155
156      db.DimClients.InsertAllOnSubmit(newDimClients);
157    }
158
159    private void UpdateFactTables(DimTime newTime, HiveDataContext db) {
160      UpdateClientInfoFacts(newTime, db);
161      UpdateTaskFacts(newTime, db);
162    }
163
164    private void UpdateClientInfoFacts(DimTime newTime, HiveDataContext db) {
165      var time = newTime.Time;
166
167      var lastFacts =
168        from cf in db.FactClientInfos
169        join r in db.DimClients on cf.ClientId equals r.Id
170        group cf by r.ResourceId into grpFacts
171        select new {
172          ResourceId = grpFacts.Key,
173          Fact = grpFacts.OrderByDescending(x => x.Time).First(),
174        };
175
176      var slaves =
177        from s in db.Resources.OfType<Slave>()
178        join c in db.DimClients on s.ResourceId equals c.ResourceId
179        join lcf in lastFacts on c.ResourceId equals lcf.ResourceId into joinCf
180        from cf in joinCf.DefaultIfEmpty()
181        where c.ExpirationTime == null
182        select new {
183          Slave = s,
184          Client = c,
185          LastFact = cf != null ? cf.Fact : null
186        };
187
188      var clientFacts =
189        from s in slaves.ToList()
190        let duration = s.LastFact != null ? (time - s.LastFact.Time).TotalMinutes : SmallestTimeSpan.TotalMinutes
191        select new FactClientInfo {
192          DimClient = s.Client,
193          DimTime = newTime,
194          UserId = s.Slave.OwnerUserId ?? Guid.Empty,
195          NumUsedCores = s.Slave.Cores != null && s.Slave.FreeCores != null
196                         ? s.Slave.Cores.Value - s.Slave.FreeCores.Value : 0,
197          NumTotalCores = s.Slave.Cores ?? 0,
198          UsedMemory = s.Slave.Memory != null && s.Slave.FreeMemory != null
199                       ? s.Slave.Memory.Value - s.Slave.FreeMemory.Value : 0,
200          TotalMemory = s.Slave.Memory ?? 0,
201          CpuUtilization = s.Slave.CpuUtilization,
202          TotalTimeIdle = s.Slave.SlaveState == SlaveState.Idle && s.Slave.IsAllowedToCalculate
203                                  ? duration : 0.0,
204          TotalTimeCalculating = s.Slave.SlaveState == SlaveState.Calculating
205                                  ? duration : 0.0,
206          TotalTimeTransferring = 0.0,
207          TotalTimeUnavailable = s.Slave.SlaveState == SlaveState.Idle && !s.Slave.IsAllowedToCalculate
208                                  ? duration : 0.0,
209          TotalTimeOffline = s.Slave.SlaveState == SlaveState.Offline
210                                  ? duration : 0.0
211        };
212
213      db.FactClientInfos.InsertAllOnSubmit(clientFacts);
214    }
215
216    private void UpdateTaskFacts(DimTime newTime, HiveDataContext db) {
217      // old Task facts
218      var oldFacts =
219        from fact in db.FactTasks
220        where fact.EndTime == null
221        select fact;
222
223      // query Task facts data
224      var newFacts =
225        from task in db.Tasks
226        where !task.IsParentTask
227          && (!db.FactTasks.Select(fact => fact.TaskId).Contains(task.TaskId) || oldFacts.Select(fact => fact.TaskId).Contains(task.TaskId))
228        join lastFact in oldFacts on task.TaskId equals lastFact.TaskId into lastFactPerTask
229        from lastFact in lastFactPerTask.DefaultIfEmpty()
230        let lastSlaveId = task.StateLogs.OrderByDescending(sl => sl.DateTime).First(sl => sl.SlaveId != null).SlaveId
231        join client in db.DimClients.Where(client => client.ExpirationTime == null) on lastSlaveId equals client.ResourceId into clientsPerSlaveId
232        from client in clientsPerSlaveId.DefaultIfEmpty()
233        select new {
234          Task = task,
235          StateLogs = task.StateLogs.OrderBy(sl => sl.DateTime),
236          LastClientId = client != null ? client.Id : default(Guid?),
237          LastFact = lastFact
238        };
239
240      // new Task facts
241      var newTaskFacts =
242        from t in newFacts.ToList()
243        let stateLogsLinkedList = new LinkedList<StateLog>(t.StateLogs)
244        select new FactTask {
245          TaskId = t.Task.TaskId,
246          JobId = t.Task.JobId,
247          DimTimeStart = t.LastFact != null ? t.LastFact.DimTimeStart : newTime,
248          DimTimeEnd = new[] { TaskState.Finished, TaskState.Failed, TaskState.Aborted }.Contains(t.Task.State) ? newTime : null,
249          LastClientId = t.LastClientId ?? (t.LastFact != null ? t.LastFact.LastClientId : Guid.Empty),
250          Priority = t.Task.Priority,
251          CoresRequired = t.Task.CoresNeeded,
252          MemoryRequired = t.Task.MemoryNeeded,
253          NumCalculationRuns = stateLogsLinkedList.CountCalculationRuns(),
254          NumRetries = stateLogsLinkedList.CountRetries(),
255          TotalWaitingTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Waiting),
256          TotalRuntime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Calculating && stateLog.NextIs(x => x.State == TaskState.Transferring)),
257          TotalTransferTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Transferring),
258          TaskState = t.Task.State,
259          Exception = stateLogsLinkedList.FirstOrDefault(sl => sl.Exception != null) == null ? string.Empty : stateLogsLinkedList.FirstOrDefault(sl => sl.Exception != null).Exception
260        };
261
262      db.FactTasks.DeleteAllOnSubmit(oldFacts.ToList());
263      db.FactTasks.InsertAllOnSubmit(newTaskFacts);
264    }
265  }
266
267  public static class StateLogLinkedListExtensions {
268    public static int CountCalculationRuns(this LinkedList<StateLog> stateLogs) {
269      return stateLogs.EnumerateNodes()
270                      .Count(sl => sl.Value.State == TaskState.Calculating && sl.NextIs(nsl => nsl.State == TaskState.Transferring));
271    }
272
273    public static int CountRetries(this LinkedList<StateLog> stateLogs) {
274      return stateLogs.EnumerateNodes()
275                      .Count(sl => sl.Value.State == TaskState.Calculating && sl.Next != null && sl.NextIs(nsl => nsl.State != TaskState.Transferring));
276    }
277
278    public static double SumTotalTimeWhere(this LinkedList<StateLog> stateLogs, Predicate<LinkedListNode<StateLog>> predicate) {
279      return stateLogs.EnumerateNodes()
280                      .Where(stateLog => predicate(stateLog))
281                      .Sum(stateLog => stateLog.Next != null ? (stateLog.Next.Value.DateTime - stateLog.Value.DateTime).TotalMinutes : 0.0);
282    }
283  }
284
285  public static class LinkedListExtensions {
286    public static IEnumerable<LinkedListNode<T>> EnumerateNodes<T>(this LinkedList<T> list) {
287      var node = list.First;
288      while (node != null) {
289        yield return node;
290        node = node.Next;
291      }
292    }
293
294    public static bool NextIs<T>(this LinkedListNode<T> node, Predicate<T> predicate) {
295      return node.Next != null && predicate(node.Next.Value);
296    }
297  }
298}
Note: See TracBrowser for help on using the repository browser.