Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 11316 was 11259, checked in by mroscoe, 10 years ago
File size: 12.2 KB
RevLine 
[9533]1using System;
[9571]2using System.Collections.Generic;
[9646]3using System.Data.Linq;
[9533]4using System.Linq;
5using System.Transactions;
[9545]6using HeuristicLab.Services.Access;
[9533]7using HeuristicLab.Services.Hive.DataAccess;
8
9namespace HeuristicLab.Services.Hive {
[9526]10  public class HiveStatisticsGenerator : IStatisticsGenerator {
[9545]11    private IUserManager userManager { get { return ServiceLocator.Instance.UserManager; } }
12
[9541]13    private static readonly TimeSpan SmallestTimeSpan = new TimeSpan(0, 5, 0);
[11223]14    private static readonly string UnknownUserName = "Unknown";
[9533]15
[9526]16    public void GenerateStatistics() {
[9533]17      using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
[9557]18      using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) {
19
[9541]20        var newTime = UpdateDimensionTables(db);
21        db.SubmitChanges();
[9533]22
23        if (newTime != null) {
[9541]24          UpdateFactTables(newTime, db);
[9646]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          }
[9533]32        }
33
34        transaction.Complete();
35      }
[9526]36    }
37
[9533]38    private DimTime UpdateDimensionTables(HiveDataContext db) {
39      var newTime = UpdateTime(db);
[9646]40
[9557]41      UpdateUsers(db);
[9533]42      UpdateJobs(db);
[9538]43      UpdateClients(db);
[9526]44
[9533]45      return newTime;
[9526]46    }
47
[9533]48    private DimTime UpdateTime(HiveDataContext db) {
[9557]49      var lastUpdateTime =
[9533]50        (from t in db.DimTimes
51         orderby t.Time descending
52         select t.Time)
53        .FirstOrDefault();
[9526]54
[9533]55      var now = DateTime.Now;
56      DimTime newTime = null;
[9557]57
58      if (lastUpdateTime == default(DateTime) || lastUpdateTime + SmallestTimeSpan < now) {
[9533]59        newTime = new DimTime {
[9541]60          Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute - now.Minute % SmallestTimeSpan.Minutes, 0),
[9533]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;
[9526]70    }
[9533]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
[11223]78
[9533]79      var newDimUsers =
[11223]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     };
[9533]85
86      db.DimUsers.InsertAllOnSubmit(newDimUsers);
[9546]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      }
[9533]92    }
93
[9557]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,
[11223]104          JobName = j.Name == null ? string.Empty : j.Name,
[9557]105          UserId = j.OwnerUserId,
[11223]106          UserName = userManager.GetUserById(j.OwnerUserId) != null ? userManager.GetUserById(j.OwnerUserId).UserName : UnknownUserName
[9557]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
[9538]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)
[9571]139              || modifiedClients.Select(x => x.Slave.ResourceId).Contains(s.ResourceId)
[9538]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
[9541]159    private void UpdateFactTables(DimTime newTime, HiveDataContext db) {
160      UpdateClientInfoFacts(newTime, db);
[9557]161      UpdateTaskFacts(newTime, db);
[9541]162    }
[9533]163
[9541]164    private void UpdateClientInfoFacts(DimTime newTime, HiveDataContext db) {
[9646]165      var time = newTime.Time;
166
[9541]167      var lastFacts =
168        from cf in db.FactClientInfos
[9545]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        };
[9541]175
176      var slaves =
177        from s in db.Resources.OfType<Slave>()
178        join c in db.DimClients on s.ResourceId equals c.ResourceId
[9545]179        join lcf in lastFacts on c.ResourceId equals lcf.ResourceId into joinCf
[9541]180        from cf in joinCf.DefaultIfEmpty()
[9545]181        where c.ExpirationTime == null
[9541]182        select new {
183          Slave = s,
184          Client = c,
[9545]185          LastFact = cf != null ? cf.Fact : null
[9541]186        };
187
188      var clientFacts =
189        from s in slaves.ToList()
[9646]190        let duration = s.LastFact != null ? (time - s.LastFact.Time).TotalMinutes : SmallestTimeSpan.TotalMinutes
[9541]191        select new FactClientInfo {
192          DimClient = s.Client,
193          DimTime = newTime,
[9546]194          UserId = s.Slave.OwnerUserId ?? Guid.Empty,
[9646]195          NumUsedCores = s.Slave.Cores != null && s.Slave.FreeCores != null
196                         ? s.Slave.Cores.Value - s.Slave.FreeCores.Value : 0,
[9541]197          NumTotalCores = s.Slave.Cores ?? 0,
[9646]198          UsedMemory = s.Slave.Memory != null && s.Slave.FreeMemory != null
199                       ? s.Slave.Memory.Value - s.Slave.FreeMemory.Value : 0,
[9541]200          TotalMemory = s.Slave.Memory ?? 0,
201          CpuUtilization = s.Slave.CpuUtilization,
[11259]202          SlaveState = s.Slave.SlaveState,
[9646]203          TotalTimeIdle = s.Slave.SlaveState == SlaveState.Idle && s.Slave.IsAllowedToCalculate
204                                  ? duration : 0.0,
205          TotalTimeCalculating = s.Slave.SlaveState == SlaveState.Calculating
206                                  ? duration : 0.0,
[9541]207          TotalTimeTransferring = 0.0,
[9646]208          TotalTimeUnavailable = s.Slave.SlaveState == SlaveState.Idle && !s.Slave.IsAllowedToCalculate
209                                  ? duration : 0.0,
210          TotalTimeOffline = s.Slave.SlaveState == SlaveState.Offline
211                                  ? duration : 0.0
[9541]212        };
213
214      db.FactClientInfos.InsertAllOnSubmit(clientFacts);
[9533]215    }
[9541]216
[9557]217    private void UpdateTaskFacts(DimTime newTime, HiveDataContext db) {
[9578]218      // old Task facts
219      var oldFacts =
[9561]220        from fact in db.FactTasks
[9578]221        where fact.EndTime == null
222        select fact;
[9557]223
[9578]224      // query Task facts data
225      var newFacts =
226        from task in db.Tasks
227        where !task.IsParentTask
228          && (!db.FactTasks.Select(fact => fact.TaskId).Contains(task.TaskId) || oldFacts.Select(fact => fact.TaskId).Contains(task.TaskId))
229        join lastFact in oldFacts on task.TaskId equals lastFact.TaskId into lastFactPerTask
230        from lastFact in lastFactPerTask.DefaultIfEmpty()
231        let lastSlaveId = task.StateLogs.OrderByDescending(sl => sl.DateTime).First(sl => sl.SlaveId != null).SlaveId
232        join client in db.DimClients.Where(client => client.ExpirationTime == null) on lastSlaveId equals client.ResourceId into clientsPerSlaveId
233        from client in clientsPerSlaveId.DefaultIfEmpty()
[9560]234        select new {
[9561]235          Task = task,
[9578]236          StateLogs = task.StateLogs.OrderBy(sl => sl.DateTime),
237          LastClientId = client != null ? client.Id : default(Guid?),
238          LastFact = lastFact
[9560]239        };
[9557]240
[9578]241      // new Task facts
[9557]242      var newTaskFacts =
[9578]243        from t in newFacts.ToList()
244        let stateLogsLinkedList = new LinkedList<StateLog>(t.StateLogs)
[9557]245        select new FactTask {
246          TaskId = t.Task.TaskId,
247          JobId = t.Task.JobId,
[9560]248          DimTimeStart = t.LastFact != null ? t.LastFact.DimTimeStart : newTime,
[9578]249          DimTimeEnd = new[] { TaskState.Finished, TaskState.Failed, TaskState.Aborted }.Contains(t.Task.State) ? newTime : null,
[9561]250          LastClientId = t.LastClientId ?? (t.LastFact != null ? t.LastFact.LastClientId : Guid.Empty),
[9560]251          Priority = t.Task.Priority,
252          CoresRequired = t.Task.CoresNeeded,
253          MemoryRequired = t.Task.MemoryNeeded,
[9646]254          NumCalculationRuns = stateLogsLinkedList.CountCalculationRuns(),
255          NumRetries = stateLogsLinkedList.CountRetries(),
256          TotalWaitingTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Waiting),
257          TotalRuntime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Calculating && stateLog.NextIs(x => x.State == TaskState.Transferring)),
258          TotalTransferTime = stateLogsLinkedList.SumTotalTimeWhere(stateLog => stateLog.Value.State == TaskState.Transferring),
[11041]259          TaskState = t.Task.State,
[11223]260          Exception = stateLogsLinkedList.FirstOrDefault(sl => sl.Exception != null) == null ? string.Empty : stateLogsLinkedList.FirstOrDefault(sl => sl.Exception != null).Exception
[9557]261        };
262
[9578]263      db.FactTasks.DeleteAllOnSubmit(oldFacts.ToList());
[9557]264      db.FactTasks.InsertAllOnSubmit(newTaskFacts);
265    }
[9646]266  }
[9571]267
[9646]268  public static class StateLogLinkedListExtensions {
269    public static int CountCalculationRuns(this LinkedList<StateLog> stateLogs) {
[9578]270      return stateLogs.EnumerateNodes()
[9646]271                      .Count(sl => sl.Value.State == TaskState.Calculating && sl.NextIs(nsl => nsl.State == TaskState.Transferring));
[9571]272    }
[9646]273
274    public static int CountRetries(this LinkedList<StateLog> stateLogs) {
275      return stateLogs.EnumerateNodes()
276                      .Count(sl => sl.Value.State == TaskState.Calculating && sl.Next != null && sl.NextIs(nsl => nsl.State != TaskState.Transferring));
277    }
278
279    public static double SumTotalTimeWhere(this LinkedList<StateLog> stateLogs, Predicate<LinkedListNode<StateLog>> predicate) {
280      return stateLogs.EnumerateNodes()
281                      .Where(stateLog => predicate(stateLog))
282                      .Sum(stateLog => stateLog.Next != null ? (stateLog.Next.Value.DateTime - stateLog.Value.DateTime).TotalMinutes : 0.0);
283    }
[9526]284  }
[9571]285
[9646]286  public static class LinkedListExtensions {
[9571]287    public static IEnumerable<LinkedListNode<T>> EnumerateNodes<T>(this LinkedList<T> list) {
288      var node = list.First;
289      while (node != null) {
290        yield return node;
291        node = node.Next;
292      }
293    }
294
295    public static bool NextIs<T>(this LinkedListNode<T> node, Predicate<T> predicate) {
296      return node.Next != null && predicate(node.Next.Value);
297    }
298  }
[9526]299}
Note: See TracBrowser for help on using the repository browser.