[9533] | 1 | using System;
|
---|
| 2 | using System.Linq;
|
---|
| 3 | using System.Transactions;
|
---|
[9545] | 4 | using HeuristicLab.Services.Access;
|
---|
[9533] | 5 | using HeuristicLab.Services.Hive.DataAccess;
|
---|
| 6 |
|
---|
| 7 | namespace HeuristicLab.Services.Hive {
|
---|
[9526] | 8 | public class HiveStatisticsGenerator : IStatisticsGenerator {
|
---|
[9545] | 9 |
|
---|
| 10 | private IUserManager userManager { get { return ServiceLocator.Instance.UserManager; } }
|
---|
| 11 |
|
---|
[9541] | 12 | private static readonly TimeSpan SmallestTimeSpan = new TimeSpan(0, 5, 0);
|
---|
[9533] | 13 |
|
---|
[9526] | 14 | public void GenerateStatistics() {
|
---|
[9533] | 15 | using (var db = new HiveDataContext(Settings.Default.HeuristicLab_Hive_LinqConnectionString))
|
---|
[9557] | 16 | using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) {
|
---|
| 17 |
|
---|
[9541] | 18 | var newTime = UpdateDimensionTables(db);
|
---|
| 19 | db.SubmitChanges();
|
---|
[9533] | 20 |
|
---|
| 21 | if (newTime != null) {
|
---|
[9541] | 22 | UpdateFactTables(newTime, db);
|
---|
| 23 | db.SubmitChanges();
|
---|
[9533] | 24 | }
|
---|
| 25 |
|
---|
| 26 | transaction.Complete();
|
---|
| 27 | }
|
---|
[9526] | 28 | }
|
---|
| 29 |
|
---|
[9533] | 30 | private DimTime UpdateDimensionTables(HiveDataContext db) {
|
---|
| 31 | var newTime = UpdateTime(db);
|
---|
| 32 | // Update other tables out of sync with time dimension?
|
---|
[9557] | 33 | UpdateUsers(db);
|
---|
[9533] | 34 | UpdateJobs(db);
|
---|
[9538] | 35 | UpdateClients(db);
|
---|
[9526] | 36 |
|
---|
[9533] | 37 | return newTime;
|
---|
[9526] | 38 | }
|
---|
| 39 |
|
---|
[9533] | 40 | private DimTime UpdateTime(HiveDataContext db) {
|
---|
[9557] | 41 | var lastUpdateTime =
|
---|
[9533] | 42 | (from t in db.DimTimes
|
---|
| 43 | orderby t.Time descending
|
---|
| 44 | select t.Time)
|
---|
| 45 | .FirstOrDefault();
|
---|
[9526] | 46 |
|
---|
[9533] | 47 | var now = DateTime.Now;
|
---|
| 48 | DimTime newTime = null;
|
---|
[9557] | 49 |
|
---|
| 50 | if (lastUpdateTime == default(DateTime) || lastUpdateTime + SmallestTimeSpan < now) {
|
---|
[9533] | 51 | newTime = new DimTime {
|
---|
[9541] | 52 | Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute - now.Minute % SmallestTimeSpan.Minutes, 0),
|
---|
[9533] | 53 | Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
|
---|
| 54 | Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
|
---|
| 55 | Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
|
---|
| 56 | Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
|
---|
| 57 | };
|
---|
| 58 | db.DimTimes.InsertOnSubmit(newTime);
|
---|
| 59 | }
|
---|
| 60 |
|
---|
| 61 | return newTime;
|
---|
[9526] | 62 | }
|
---|
[9533] | 63 |
|
---|
| 64 | private void UpdateUsers(HiveDataContext db) {
|
---|
| 65 | var newUsers =
|
---|
| 66 | from u in db.Resources.Where(x => x.OwnerUserId != null).Select(x => x.OwnerUserId.Value).Union(db.Jobs.Select(x => x.OwnerUserId))
|
---|
| 67 | where !db.DimUsers.Select(x => x.UserId).Contains(u)
|
---|
| 68 | select u;
|
---|
| 69 |
|
---|
| 70 | var newDimUsers =
|
---|
| 71 | from u in newUsers.ToList()
|
---|
| 72 | select new DimUser {
|
---|
| 73 | UserId = u,
|
---|
[9545] | 74 | Name = userManager.GetUserById(u).UserName
|
---|
[9533] | 75 | };
|
---|
| 76 |
|
---|
| 77 | db.DimUsers.InsertAllOnSubmit(newDimUsers);
|
---|
[9546] | 78 |
|
---|
| 79 | // insert NULL-User
|
---|
| 80 | if (!db.DimUsers.Any(x => x.UserId == Guid.Empty)) {
|
---|
| 81 | db.DimUsers.InsertOnSubmit(new DimUser { UserId = Guid.Empty, Name = "NULL" });
|
---|
| 82 | }
|
---|
[9533] | 83 | }
|
---|
| 84 |
|
---|
[9557] | 85 | private void UpdateJobs(HiveDataContext db) {
|
---|
| 86 | var newJobs =
|
---|
| 87 | from j in db.Jobs
|
---|
| 88 | where !db.DimJobs.Select(x => x.JobId).Contains(j.JobId)
|
---|
| 89 | select j;
|
---|
| 90 |
|
---|
| 91 | var newDimJobs =
|
---|
| 92 | from j in newJobs.ToList()
|
---|
| 93 | select new DimJob {
|
---|
| 94 | JobId = j.JobId,
|
---|
| 95 | JobName = j.Name,
|
---|
| 96 | UserId = j.OwnerUserId,
|
---|
| 97 | UserName = userManager.GetUserById(j.OwnerUserId).UserName
|
---|
| 98 | };
|
---|
| 99 |
|
---|
| 100 | db.DimJobs.InsertAllOnSubmit(newDimJobs);
|
---|
| 101 |
|
---|
| 102 | // insert NULL-Job
|
---|
| 103 | if (!db.DimJobs.Any(x => x.JobId == Guid.Empty)) {
|
---|
| 104 | db.DimJobs.InsertOnSubmit(new DimJob { JobId = Guid.Empty, JobName = "NULL", UserId = Guid.Empty, UserName = "NULL" });
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 |
|
---|
[9538] | 108 | private void UpdateClients(HiveDataContext db) {
|
---|
| 109 | var removedClients =
|
---|
| 110 | from c in db.DimClients
|
---|
| 111 | where c.ExpirationTime == null &&
|
---|
| 112 | !db.Resources.OfType<Slave>().Select(x => x.ResourceId).Contains(c.ResourceId)
|
---|
| 113 | select c;
|
---|
| 114 |
|
---|
| 115 | var modifiedClients =
|
---|
| 116 | from s in db.Resources.OfType<Slave>()
|
---|
| 117 | join c in db.DimClients on s.ResourceId equals c.ResourceId
|
---|
| 118 | where c.ExpirationTime == null
|
---|
| 119 | && (s.Name != c.Name || s.ParentResourceId != c.ResourceGroupId ||
|
---|
| 120 | s.ParentResource.ParentResourceId != c.ResourceGroup2Id)
|
---|
| 121 | select new { Slave = s, Client = c };
|
---|
| 122 |
|
---|
| 123 | foreach (var client in removedClients.Union(modifiedClients.Select(x => x.Client))) {
|
---|
| 124 | client.ExpirationTime = DateTime.Now;
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | var newClients =
|
---|
| 128 | from s in db.Resources.OfType<Slave>()
|
---|
| 129 | where !db.DimClients.Select(x => x.ResourceId).Contains(s.ResourceId)
|
---|
| 130 | || modifiedClients.Select(x => x.Slave.ResourceId).Contains(s.ResourceId)
|
---|
| 131 | select new {
|
---|
| 132 | Slave = s,
|
---|
| 133 | Group = s.ParentResourceId,
|
---|
| 134 | Group2 = s.ParentResource.ParentResourceId
|
---|
| 135 | };
|
---|
| 136 |
|
---|
| 137 | var newDimClients =
|
---|
| 138 | from s in newClients.ToList()
|
---|
| 139 | select new DimClient {
|
---|
| 140 | ResourceId = s.Slave.ResourceId,
|
---|
| 141 | Name = s.Slave.Name,
|
---|
| 142 | ExpirationTime = null,
|
---|
| 143 | ResourceGroupId = s.Group,
|
---|
| 144 | ResourceGroup2Id = s.Group2
|
---|
| 145 | };
|
---|
| 146 |
|
---|
| 147 | db.DimClients.InsertAllOnSubmit(newDimClients);
|
---|
| 148 | }
|
---|
| 149 |
|
---|
[9541] | 150 | private void UpdateFactTables(DimTime newTime, HiveDataContext db) {
|
---|
| 151 | UpdateClientInfoFacts(newTime, db);
|
---|
[9557] | 152 | UpdateTaskFacts(newTime, db);
|
---|
[9541] | 153 | }
|
---|
[9533] | 154 |
|
---|
[9541] | 155 | private void UpdateClientInfoFacts(DimTime newTime, HiveDataContext db) {
|
---|
| 156 | var lastFacts =
|
---|
| 157 | from cf in db.FactClientInfos
|
---|
[9545] | 158 | join r in db.DimClients on cf.ClientId equals r.Id
|
---|
| 159 | group cf by r.ResourceId into grpFacts
|
---|
| 160 | select new {
|
---|
| 161 | ResourceId = grpFacts.Key,
|
---|
| 162 | Fact = grpFacts.OrderByDescending(x => x.Time).First(),
|
---|
| 163 | };
|
---|
[9541] | 164 |
|
---|
| 165 | var slaves =
|
---|
| 166 | from s in db.Resources.OfType<Slave>()
|
---|
| 167 | join c in db.DimClients on s.ResourceId equals c.ResourceId
|
---|
[9545] | 168 | join lcf in lastFacts on c.ResourceId equals lcf.ResourceId into joinCf
|
---|
[9541] | 169 | from cf in joinCf.DefaultIfEmpty()
|
---|
[9545] | 170 | where c.ExpirationTime == null
|
---|
[9541] | 171 | select new {
|
---|
| 172 | Slave = s,
|
---|
| 173 | Client = c,
|
---|
[9545] | 174 | LastFact = cf != null ? cf.Fact : null
|
---|
[9541] | 175 | };
|
---|
| 176 |
|
---|
| 177 | var clientFacts =
|
---|
| 178 | from s in slaves.ToList()
|
---|
| 179 | select new FactClientInfo {
|
---|
| 180 | DimClient = s.Client,
|
---|
| 181 | DimTime = newTime,
|
---|
[9546] | 182 | UserId = s.Slave.OwnerUserId ?? Guid.Empty,
|
---|
[9541] | 183 | NumUsedCores =
|
---|
| 184 | s.Slave.Cores != null && s.Slave.FreeCores != null
|
---|
| 185 | ? s.Slave.Cores.Value - s.Slave.FreeCores.Value
|
---|
| 186 | : 0,
|
---|
| 187 | NumTotalCores = s.Slave.Cores ?? 0,
|
---|
| 188 | UsedMemory =
|
---|
| 189 | s.Slave.Memory != null && s.Slave.FreeMemory != null
|
---|
| 190 | ? s.Slave.Memory.Value - s.Slave.FreeMemory.Value
|
---|
| 191 | : 0,
|
---|
| 192 | TotalMemory = s.Slave.Memory ?? 0,
|
---|
| 193 | CpuUtilization = s.Slave.CpuUtilization,
|
---|
| 194 | TrafficIn = 0,
|
---|
| 195 | TrafficOut = 0,
|
---|
| 196 | TotalTimeIdle = CalcNewTotalTime(s.LastFact, newTime.Time,
|
---|
| 197 | x => x.TotalTimeIdle,
|
---|
| 198 | () => s.Slave.SlaveState == SlaveState.Idle && s.Slave.IsAllowedToCalculate),
|
---|
| 199 | TotalTimeCalculating = CalcNewTotalTime(s.LastFact, newTime.Time,
|
---|
| 200 | x => x.TotalTimeCalculating,
|
---|
| 201 | () => s.Slave.SlaveState == SlaveState.Calculating),
|
---|
| 202 | TotalTimeTransferring = 0.0,
|
---|
| 203 | TotalTimeUnavailable = CalcNewTotalTime(s.LastFact, newTime.Time,
|
---|
| 204 | x => x.TotalTimeUnavailable,
|
---|
| 205 | () => s.Slave.SlaveState == SlaveState.Idle && !s.Slave.IsAllowedToCalculate),
|
---|
| 206 | TotalTimeOffline = CalcNewTotalTime(s.LastFact, newTime.Time,
|
---|
| 207 | x => x.TotalTimeOffline,
|
---|
| 208 | () => s.Slave.SlaveState == SlaveState.Offline)
|
---|
| 209 | };
|
---|
| 210 |
|
---|
| 211 | db.FactClientInfos.InsertAllOnSubmit(clientFacts);
|
---|
[9533] | 212 | }
|
---|
[9541] | 213 |
|
---|
| 214 | private double CalcNewTotalTime(FactClientInfo lastFact, DateTime newTime, Func<FactClientInfo, double> selector, Func<bool> condition) {
|
---|
| 215 | if (lastFact == null) {
|
---|
| 216 | return 0.0;
|
---|
| 217 | }
|
---|
| 218 | return condition()
|
---|
| 219 | ? selector(lastFact) + (newTime - lastFact.Time).TotalMinutes
|
---|
| 220 | : selector(lastFact);
|
---|
| 221 | }
|
---|
[9557] | 222 |
|
---|
| 223 | private void UpdateTaskFacts(DimTime newTime, HiveDataContext db) {
|
---|
| 224 | var lastFacts =
|
---|
| 225 | from f in db.FactTasks
|
---|
| 226 | group f by f.TaskId into grpFacts
|
---|
| 227 | select grpFacts.OrderByDescending(x => x.EndTime).First();
|
---|
| 228 |
|
---|
| 229 | var tasksWithLastFact =
|
---|
| 230 | from t in db.Tasks
|
---|
| 231 | join lf in lastFacts on t.TaskId equals lf.TaskId into tLfJoin
|
---|
| 232 | from lWithLf in tLfJoin.DefaultIfEmpty()
|
---|
| 233 | where !t.IsParentTask
|
---|
| 234 | select new { Task = t, LastFact = tLfJoin.FirstOrDefault() };
|
---|
| 235 |
|
---|
| 236 | var tasksWithNewStateLogs =
|
---|
| 237 | from sl in db.StateLogs
|
---|
| 238 | join twlf in tasksWithLastFact on sl.TaskId equals twlf.Task.TaskId
|
---|
| 239 | where twlf.LastFact == null || (sl.DateTime > twlf.LastFact.EndTime && sl.DateTime < newTime.Time)
|
---|
| 240 | group sl by twlf.Task into factGroup
|
---|
| 241 | select new { Task = factGroup.Key, StateLogs = factGroup.OrderBy(x => x.DateTime) };
|
---|
| 242 |
|
---|
| 243 | var tasksWithLastFactsAndStateLogs =
|
---|
| 244 | from twsl in tasksWithNewStateLogs
|
---|
| 245 | join twlf in tasksWithLastFact on twsl.Task equals twlf.Task
|
---|
| 246 | select new { twlf.Task, twlf.LastFact, twsl.StateLogs };
|
---|
| 247 |
|
---|
| 248 | var newTaskFacts =
|
---|
| 249 | from t in tasksWithLastFactsAndStateLogs.ToList()
|
---|
| 250 | select new FactTask {
|
---|
| 251 | TaskId = t.Task.TaskId,
|
---|
| 252 | JobId = t.Task.JobId,
|
---|
| 253 | DimTimeStart = t.LastFact.DimTimeStart,
|
---|
| 254 | DimTimeEnd = newTime,
|
---|
| 255 | // ...
|
---|
| 256 | };
|
---|
| 257 |
|
---|
| 258 | db.FactTasks.InsertAllOnSubmit(newTaskFacts);
|
---|
| 259 | }
|
---|
[9526] | 260 | }
|
---|
| 261 | } |
---|