Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Services.Hive/3.3/HiveStatisticsGenerator.cs @ 18078

Last change on this file since 18078 was 17574, checked in by jkarder, 4 years ago

#3062: overhauled statistics generation and cleanup

  • switched to a single thread for database cleanup and statistics generation (executed sequentially)
  • switched to preemptive deletion of items that are in status DeletionPending (for jobs: statelogs, taskdata, tasks)
  • added code that aborts tasks whose jobs have already been marked for deletion
  • added method UseTransactionAndSubmit in addition to UseTransaction in PersistenceManager
  • updated DAO methods and introduced more bare metal sql
  • introduced DAO methods for batch deletion
  • fixed usage of enum values in DAO sql queries
  • deleted unnecessary triggers tr_JobDeleteCascade and tr_TaskDeleteCascade in Prepare Hive Database.sql
  • changed scheduling for less interference with janitor and other heartbeats
    • increased scheduling patience from 20 to 70 seconds (to wait longer to get the mutex for scheduling)
    • changed signature of ITaskScheduler.Schedule
    • added base class for TaskSchedulers and moved assignment of tasks to slaves into it
    • changed RoundRobinTaskScheduler to use bare metal sql
  • made MessageContainer a storable type (leftover)
  • updated HiveJanitorServiceInstaller.nsi
File size: 27.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 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.Linq;
25using HeuristicLab.Services.Access.DataAccess;
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      Console.WriteLine("started generate statistics");
38
39      using (var pm = new PersistenceManager(true)) {
40        var sw = new System.Diagnostics.Stopwatch();
41
42        sw.Start();
43        pm.UseTransactionAndSubmit(() => { UpdateDimProjectTable(pm); });
44        sw.Stop();
45        LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateDimProjectTable: {sw.Elapsed}");
46        Console.WriteLine($"UpdateDimProjectTable: {sw.Elapsed}");
47        sw.Reset();
48
49        pm.UseTransactionAndSubmit(() => {
50          sw.Start();
51          UpdateDimUserTable(pm);
52          sw.Stop();
53          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateDimUserTable: {sw.Elapsed}");
54          Console.WriteLine($"UpdateDimUserTable: {sw.Elapsed}");
55          sw.Reset();
56
57          sw.Start();
58          UpdateDimJobTable(pm);
59          sw.Stop();
60          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateDimJobTable: {sw.Elapsed}");
61          Console.WriteLine($"UpdateDimJobTable: {sw.Elapsed}");
62          sw.Reset();
63
64          sw.Start();
65          UpdateDimClientsTable(pm);
66          sw.Stop();
67          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateDimClientsTable: {sw.Elapsed}");
68          Console.WriteLine($"UpdateDimClientsTable: {sw.Elapsed}");
69          sw.Reset();
70        });
71
72        pm.UseTransactionAndSubmit(() => {
73          sw.Start();
74          var time = UpdateDimTimeTable(pm);
75          sw.Stop();
76          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateDimTimeTable: {sw.Elapsed}");
77          Console.WriteLine($"UpdateDimTimeTable: {sw.Elapsed}");
78          sw.Reset();
79
80          sw.Start();
81          UpdateFactClientInfoTable(time, pm);
82          sw.Stop();
83          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateFactClientInfoTable: {sw.Elapsed}");
84          Console.WriteLine($"UpdateFactClientInfoTable: {sw.Elapsed}");
85          sw.Reset();
86
87          sw.Start();
88          UpdateFactProjectInfoTable(time, pm);
89          sw.Stop();
90          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateFactProjectInfoTable: {sw.Elapsed}");
91          Console.WriteLine($"UpdateFactProjectInfoTable: {sw.Elapsed}");
92          sw.Reset();
93
94
95          sw.Start();
96          UpdateFactTaskTable(pm);
97          sw.Stop();
98          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateFactTaskTable: {sw.Elapsed}");
99          Console.WriteLine($"UpdateFactTaskTable: {sw.Elapsed}");
100          sw.Reset();
101
102          sw.Start();
103          UpdateExistingDimJobs(pm);
104          sw.Stop();
105          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"UpdateExistingDimJobs: {sw.Elapsed}");
106          Console.WriteLine($"UpdateExistingDimJobs: {sw.Elapsed}");
107          sw.Reset();
108
109          sw.Start();
110          FlagJobsForDeletion(pm);
111          sw.Stop();
112          LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log($"FlagJobsForDeletion: {sw.Elapsed}");
113          Console.WriteLine($"FlagJobsForDeletion: {sw.Elapsed}");
114          sw.Reset();
115        }, longRunning: true);
116      }
117    }
118
119    private DimTime UpdateDimTimeTable(PersistenceManager pm) {
120      var dimTimeDao = pm.DimTimeDao;
121      var now = DateTime.Now;
122      var timeEntry = new DimTime {
123        Time = now,
124        Minute = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0),
125        Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
126        Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
127        Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
128        Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
129      };
130      return dimTimeDao.Save(timeEntry);
131    }
132
133    private void UpdateDimUserTable(PersistenceManager pm) {
134      var dimUserDao = pm.DimUserDao;
135      var resourceDao = pm.ResourceDao;
136      var jobDao = pm.JobDao;
137      var existingUserIds = dimUserDao.GetAll().Select(x => x.UserId);
138      var vaildResourceOwnerIds = resourceDao.GetResourcesWithValidOwner().Select(x => x.OwnerUserId.Value);
139      var jobOwnerIds = jobDao.GetAll().Select(x => x.OwnerUserId);
140      var newUserIds = vaildResourceOwnerIds
141        .Union(jobOwnerIds)
142        .Where(id => !existingUserIds.Contains(id))
143        .ToList();
144      dimUserDao.Save(newUserIds.Select(x => new DimUser {
145        UserId = x,
146        Name = GetUserName(x)
147      }));
148    }
149
150    // add new projects
151    // delete expired projects
152    // update information of existing projects
153    private void UpdateDimProjectTable(PersistenceManager pm) {
154      var projectDao = pm.ProjectDao;
155      var dimProjectDao = pm.DimProjectDao;
156
157      var projects = projectDao.GetAll().ToList();
158      var dimProjects = dimProjectDao.GetAllOnlineProjects().ToList();
159
160      var onlineProjects = dimProjects.Where(x => projects.Select(y => y.ProjectId).Contains(x.ProjectId));
161      var addedProjects = projects.Where(x => !dimProjects.Select(y => y.ProjectId).Contains(x.ProjectId));
162      var removedProjects = dimProjects.Where(x => !projects.Select(y => y.ProjectId).Contains(x.ProjectId));
163
164      // set expiration time of removed projects
165      foreach (var p in removedProjects) {
166        p.DateExpired = DateTime.Now;
167      }
168
169      // add new projects
170      dimProjectDao.Save(addedProjects.Select(x => new DimProject {
171        ProjectId = x.ProjectId,
172        ParentProjectId = x.ParentProjectId,
173        Name = x.Name,
174        Description = x.Description,
175        OwnerUserId = x.OwnerUserId,
176        StartDate = x.StartDate,
177        EndDate = x.EndDate,
178        DateCreated = x.DateCreated,
179        DateExpired = null
180      }));
181
182      // expire project if its parent has changed and create a new entry
183      // otherwise perform "normal" update
184      foreach (var dimP in onlineProjects) {
185        var p = projects.Where(x => x.ProjectId == dimP.ProjectId).SingleOrDefault();
186        if (p != null) {
187          if (dimP.ParentProjectId == null ? p.ParentProjectId != null : dimP.ParentProjectId != p.ParentProjectId) { // or: (!object.Equals(dimP.ParentProjectId, p.ParentProjectId))
188            dimP.DateExpired = DateTime.Now;
189            dimProjectDao.Save(new DimProject {
190              ProjectId = p.ProjectId,
191              ParentProjectId = p.ParentProjectId,
192              Name = p.Name,
193              Description = p.Description,
194              OwnerUserId = p.OwnerUserId,
195              StartDate = p.StartDate,
196              EndDate = p.EndDate,
197              DateCreated = p.DateCreated,
198              DateExpired = null
199            });
200          } else {
201            dimP.Name = p.Name;
202            dimP.Description = p.Description;
203            dimP.OwnerUserId = p.OwnerUserId;
204            dimP.StartDate = p.StartDate;
205            dimP.EndDate = p.EndDate;
206          }
207        }
208      }
209    }
210
211    private void UpdateDimJobTable(PersistenceManager pm) {
212      var dimProjectDao = pm.DimProjectDao;
213      var dimJobDao = pm.DimJobDao;
214      var jobDao = pm.JobDao;
215      var taskDao = pm.TaskDao;
216      var dimJobIds = dimJobDao.GetAll().Select(x => x.JobId);
217      var newJobs = jobDao.GetAll()
218        .Where(x => !dimJobIds.Contains(x.JobId))
219        .Select(x => new {
220          JobId = x.JobId,
221          UserId = x.OwnerUserId,
222          JobName = x.Name ?? string.Empty,
223          DateCreated = x.DateCreated,
224          ProjectId = dimProjectDao.GetLastValidIdByProjectId(x.ProjectId),
225          TotalTasks = taskDao.GetAll().Count(y => y.JobId == x.JobId)
226        })
227        .ToList();
228      dimJobDao.Save(newJobs.Select(x => new DimJob {
229        JobId = x.JobId,
230        JobName = x.JobName,
231        UserId = x.UserId,
232        UserName = GetUserName(x.UserId),
233        DateCreated = x.DateCreated,
234        ProjectId = x.ProjectId,
235        TotalTasks = x.TotalTasks,
236        CompletedTasks = 0,
237        DateCompleted = null
238      }));
239    }
240
241    private void UpdateExistingDimJobs(PersistenceManager pm) {
242      var dimJobDao = pm.DimJobDao;
243      dimJobDao.UpdateExistingDimJobs();
244    }
245
246    private void FlagJobsForDeletion(PersistenceManager pm) {
247      var jobDao = pm.JobDao;
248      var jobs = jobDao.GetJobsReadyForDeletion();
249      foreach (var job in jobs) {
250        job.State = JobState.DeletionPending;
251      }
252    }
253
254    private void UpdateDimClientsTable(PersistenceManager pm) {
255      var dimClientDao = pm.DimClientDao;
256      var resourceDao = pm.ResourceDao;
257
258      var resources = resourceDao.GetAll().ToList(); // all live now
259      var dimClients = dimClientDao.GetAllOnlineClients().ToList(); // all in statistics which are online (i.e. not expired)
260
261      var onlineClients = dimClients.Where(x => resources.Select(y => y.ResourceId).Contains(x.ResourceId));
262      var addedResources = resources.Where(x => !dimClients.Select(y => y.ResourceId).Contains(x.ResourceId));
263      var removedResources = dimClients.Where(x => !resources.Select(y => y.ResourceId).Contains(x.ResourceId));
264
265      // set expiration time of removed resources
266      foreach (var r in removedResources) {
267        r.DateExpired = DateTime.Now;
268      }
269
270      // add new resources
271      dimClientDao.Save(addedResources.Select(x => new DimClient {
272        ResourceId = x.ResourceId,
273        ParentResourceId = x.ParentResourceId,
274        Name = x.Name,
275        ResourceType = x.ResourceType,
276        DateCreated = DateTime.Now,
277        DateExpired = null
278      }));
279
280      // expire client if its parent has changed and create a new entry
281      // otherwise perform "normal" update
282      foreach (var dimc in onlineClients) {
283        var r = resources.Where(x => x.ResourceId == dimc.ResourceId).SingleOrDefault();
284        if (r != null) {
285          if (dimc.ParentResourceId == null ? r.ParentResourceId != null : dimc.ParentResourceId != r.ParentResourceId) {
286            var now = DateTime.Now;
287            dimc.DateExpired = now;
288            dimClientDao.Save(new DimClient {
289              ResourceId = r.ResourceId,
290              ParentResourceId = r.ParentResourceId,
291              Name = r.Name,
292              ResourceType = r.ResourceType,
293              DateCreated = now,
294              DateExpired = null
295            });
296          } else {
297            dimc.Name = r.Name;
298          }
299        }
300      }
301    }
302
303    //// (1) for new slaves (not yet reported in Table DimClients) ...
304    //// and modified slaves (name or parent resource changed) a new DimClient-entry is created
305    //// (2) for already reported removed and modifid clients the expiration date is set
306    //private void UpdateDimClientsTableOld(PersistenceManager pm) {
307    //  var dimClientDao = pm.DimClientDao;
308    //  var slaveDao = pm.SlaveDao;
309    //  var slaves = slaveDao.GetAll();
310    //  var recentlyAddedClients = dimClientDao.GetAllOnlineClients();
311    //  var slaveIds = slaves.Select(x => x.ResourceId);
312
313    //  var removedClientIds = recentlyAddedClients
314    //    .Where(x => !slaveIds.Contains(x.ResourceId))
315    //    .Select(x => x.Id);
316    //  var modifiedClients =
317    //    from slave in slaves
318    //    join client in recentlyAddedClients on slave.ResourceId equals client.ResourceId
319    //    where (slave.Name != client.Name
320    //           || slave.ParentResourceId == null && client.ResourceGroupId != null // because both can be null and null comparison
321    //           || slave.ParentResourceId != null && client.ResourceGroupId == null // does return no entry on the sql server
322    //           || slave.ParentResourceId != client.ResourceGroupId
323    //           || ((slave.ParentResource != null) && slave.ParentResource.ParentResourceId != client.ResourceGroup2Id))
324    //    select new {
325    //      SlaveId = slave.ResourceId,
326    //      ClientId = client.Id
327    //    };
328    //  var clientIds = dimClientDao.GetAllOnlineClients().Select(x => x.ResourceId);
329    //  var modifiedClientIds = modifiedClients.Select(x => x.SlaveId);
330    //  var newClients = slaves
331    //    .Where(x => !clientIds.Contains(x.ResourceId)
332    //                || modifiedClientIds.Contains(x.ResourceId))
333    //    .Select(x => new {
334    //      x.ResourceId,
335    //      x.Name,
336    //      ResourceGroupId = x.ParentResourceId,
337    //      GroupName = x.ParentResource != null ? x.ParentResource.Name : null,
338    //      ResourceGroup2Id = x.ParentResource != null ? x.ParentResource.ParentResourceId : null,
339    //      GroupName2 = x.ParentResource != null ? x.ParentResource.ParentResource != null ? x.ParentResource.ParentResource.Name : null : null
340    //    })
341    //    .ToList();
342
343    //  var clientsToUpdate = removedClientIds.Union(modifiedClients.Select(x => x.ClientId));
344    //  dimClientDao.UpdateExpirationTime(clientsToUpdate, DateTime.Now);
345    //  dimClientDao.Save(newClients.Select(x => new DimClient {
346    //    ResourceId = x.ResourceId,
347    //    Name = x.Name,
348    //    ExpirationTime = null,
349    //    ResourceGroupId = x.ResourceGroupId,
350    //    GroupName = x.GroupName,
351    //    ResourceGroup2Id = x.ResourceGroup2Id,
352    //    GroupName2 = x.GroupName2
353    //  }));
354    //}
355
356
357    private void UpdateFactClientInfoTable(DimTime newTime, PersistenceManager pm) {
358      var factClientInfoDao = pm.FactClientInfoDao;
359      var slaveDao = pm.SlaveDao;
360      var dimClientDao = pm.DimClientDao;
361
362      var newRawFactInfos =
363        from s in slaveDao.GetAll()
364        join c in dimClientDao.GetAllOnlineSlaves() on s.ResourceId equals c.ResourceId
365        join lcf in factClientInfoDao.GetLastUpdateTimestamps() on c.ResourceId equals lcf.ResourceId into joinCf
366        from cf in joinCf.DefaultIfEmpty()
367        select new {
368          ClientId = c.Id,
369          UserId = s.OwnerUserId ?? Guid.Empty,
370          TotalCores = s.Cores ?? 0,
371          FreeCores = s.FreeCores ?? 0,
372          TotalMemory = s.Memory ?? 0,
373          FreeMemory = s.FreeMemory ?? 0,
374          CpuUtilization = s.CpuUtilization,
375          SlaveState = s.SlaveState,
376          IsAllowedToCalculate = s.IsAllowedToCalculate,
377          LastFactTimestamp = cf.Timestamp
378        };
379
380      factClientInfoDao.Save(
381        from x in newRawFactInfos.ToList()
382        let duration = x.LastFactTimestamp != null
383                       ? (int)(newTime.Time - (DateTime)x.LastFactTimestamp).TotalSeconds
384                       : (int)SmallestTimeSpan.TotalSeconds
385        select new FactClientInfo {
386          ClientId = x.ClientId,
387          DimTime = newTime,
388          UserId = x.UserId,
389          NumUsedCores = x.TotalCores - x.FreeCores,
390          NumTotalCores = x.TotalCores,
391          UsedMemory = x.TotalMemory - x.FreeMemory,
392          TotalMemory = x.TotalMemory,
393          CpuUtilization = Math.Round(x.CpuUtilization, 2),
394          SlaveState = x.SlaveState,
395          IdleTime = x.SlaveState == SlaveState.Idle && x.IsAllowedToCalculate ? duration : 0,
396          UnavailableTime = x.SlaveState == SlaveState.Idle && !x.IsAllowedToCalculate ? duration : 0,
397          OfflineTime = x.SlaveState == SlaveState.Offline ? duration : 0,
398          IsAllowedToCalculate = x.IsAllowedToCalculate
399        }
400      );
401    }
402
403    private void UpdateFactProjectInfoTable(DimTime newTime, PersistenceManager pm) {
404      var factProjectInfoDao = pm.FactProjectInfoDao;
405      var dimProjectDao = pm.DimProjectDao;
406      var projectDao = pm.ProjectDao;
407
408      var projectAvailabilityStats = projectDao.GetAvailabilityStatsPerProject();
409      var projectUsageStats = projectDao.GetUsageStatsPerProject();
410      var dimProjects = dimProjectDao.GetAllOnlineProjects().ToList();
411
412      factProjectInfoDao.Save(
413        from dimp in dimProjects
414        let aStats = projectAvailabilityStats.Where(x => x.ProjectId == dimp.ProjectId).SingleOrDefault()
415        let uStats = projectUsageStats.Where(x => x.ProjectId == dimp.ProjectId).SingleOrDefault()
416        select new FactProjectInfo {
417          ProjectId = dimp.Id,
418          DimTime = newTime,
419          NumTotalCores = aStats != null ? aStats.Cores : 0,
420          TotalMemory = aStats != null ? aStats.Memory : 0,
421          NumUsedCores = uStats != null ? uStats.Cores : 0,
422          UsedMemory = uStats != null ? uStats.Memory : 0
423        }
424        );
425    }
426
427    private void UpdateFactTaskTable(PersistenceManager pm) {
428      var factTaskDao = pm.FactTaskDao;
429      var taskDao = pm.TaskDao;
430      var dimClientDao = pm.DimClientDao;
431
432      var preselectedNewAndNotFinishedTasks =
433        (from task in taskDao.GetAll()
434         from factTask in factTaskDao.GetAll().Where(f => task.TaskId == f.TaskId).DefaultIfEmpty()
435         let stateLogs = task.StateLogs.OrderByDescending(x => x.DateTime).ToList()
436         let lastSlaveId = stateLogs.First(x => x.SlaveId != null)
437         where !task.IsParentTask && (factTask.TaskId == null || factTask.EndTime == null)
438         select new { Task = task, StateLogs = stateLogs, LastSlaveId = lastSlaveId }).ToList();
439
440      Console.WriteLine("preselectedNewAndNotFinishedTasks.Count = {0}", preselectedNewAndNotFinishedTasks.Count);
441
442      // jkarder: maybe we can split this query into multiple ones to retrieve state logs and the last slave
443
444      var clients = dimClientDao.GetAllOnlineClients().ToList();
445      Console.WriteLine("clients.Count = {0}", clients.Count);
446      var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks().ToList();
447      Console.WriteLine("notFinishedFactTasks.Count = {0}", notFinishedFactTasks.Count);
448
449      var newAndNotFinishedTasks =
450        (from x in preselectedNewAndNotFinishedTasks
451         let task = x.Task
452         let stateLogs = x.StateLogs // jkarder: if multiple join results in multiple rows, statelogs of all equal tasks must be the same ...
453         let lastSlaveId = x.LastSlaveId
454         join lastFactTask in notFinishedFactTasks on task.TaskId equals lastFactTask.TaskId into lastFactPerTask
455         from lastFact in lastFactPerTask.DefaultIfEmpty()
456           // jkarder:
457           // we can still fix this another way, if we only select that one row from dimclients that fits the given statelog/lastslave entry
458           // dimclient has multiple entires for one and the same client, because we track changes in resource group hierarchies
459           // -> left join from task/statelog to dimclient results in multiple rows because multiple rows in dimclient with the same resource id exist
460           // -> further down the road we call singleordefault to single out tasks to get the data for the update
461           // -> dimclient should only contain one valid row for a given time span that fits to the lastslaveid.datetime
462           // -> client.datecreated <= lastslaveid.datetime <= client.dateexpired
463           // it's aweful ...
464         from client in clients.Where(c => lastSlaveId != null && lastSlaveId.SlaveId == c.ResourceId && c.DateCreated <= lastSlaveId.DateTime && (c.DateExpired == null || lastSlaveId.DateTime <= c.DateExpired)).DefaultIfEmpty()
465           // jkarder:
466           //join client in clients on lastSlaveId.SlaveId equals client.ResourceId into clientsPerSlaveId
467           //from client in clientsPerSlaveId.DefaultIfEmpty()
468         select new {
469           TaskId = task.TaskId,
470           JobId = task.JobId,
471           Priority = task.Priority,
472           CoresRequired = task.CoresNeeded,
473           MemoryRequired = task.MemoryNeeded,
474           State = task.State,
475           StateLogs = stateLogs.OrderBy(x => x.DateTime).ToList(),
476           LastClientId = client != null
477                        ? client.Id : lastFact != null
478                        ? lastFact.LastClientId : (Guid?)null,
479           NotFinishedTask = notFinishedFactTasks.Any(y => y.TaskId == task.TaskId)
480         }).ToList();
481
482      Console.WriteLine("newAndNotFinishedTasks.Count = {0}", newAndNotFinishedTasks.Count);
483
484
485      // (1) update data of already existing facts
486      // i.e. for all in newAndNotFinishedTasks where NotFinishedTask = true
487      foreach (var notFinishedFactTask in notFinishedFactTasks) {
488        // jkarder: firstordefault should work too, because statelogs of multiple task rows that result from the earlier join have to be the same
489        var nfftUpdate = newAndNotFinishedTasks.Where(x => x.TaskId == notFinishedFactTask.TaskId).FirstOrDefault();
490        if (nfftUpdate != null) {
491          var taskData = CalculateFactTaskData(nfftUpdate.StateLogs);
492
493          notFinishedFactTask.StartTime = taskData.StartTime;
494          notFinishedFactTask.EndTime = taskData.EndTime;
495          notFinishedFactTask.LastClientId = nfftUpdate.LastClientId;
496          notFinishedFactTask.Priority = nfftUpdate.Priority;
497          notFinishedFactTask.CoresRequired = nfftUpdate.CoresRequired;
498          notFinishedFactTask.MemoryRequired = nfftUpdate.MemoryRequired;
499          notFinishedFactTask.NumCalculationRuns = taskData.CalculationRuns;
500          notFinishedFactTask.NumRetries = taskData.Retries;
501          notFinishedFactTask.WaitingTime = taskData.WaitingTime;
502          notFinishedFactTask.CalculatingTime = taskData.CalculatingTime;
503          notFinishedFactTask.TransferTime = taskData.TransferTime;
504          notFinishedFactTask.TaskState = nfftUpdate.State;
505          notFinishedFactTask.Exception = taskData.Exception;
506          notFinishedFactTask.InitialWaitingTime = taskData.InitialWaitingTime;
507        } else {
508          //Console.WriteLine("could not update task {0}", notFinishedFactTask.TaskId);
509        }
510      }
511
512      Console.WriteLine("nfft update complete");
513
514      // (2) insert facts for new tasks
515      // i.e. for all in newAndNotFinishedTasks where NotFinishedTask = false
516      var newFactTasks = (from x in newAndNotFinishedTasks
517                          where !x.NotFinishedTask
518                          let taskData = CalculateFactTaskData(x.StateLogs)
519                          select new FactTask {
520                            TaskId = x.TaskId,
521                            JobId = x.JobId,
522                            StartTime = taskData.StartTime,
523                            EndTime = taskData.EndTime,
524                            LastClientId = x.LastClientId,
525                            Priority = x.Priority,
526                            CoresRequired = x.CoresRequired,
527                            MemoryRequired = x.MemoryRequired,
528                            NumCalculationRuns = taskData.CalculationRuns,
529                            NumRetries = taskData.Retries,
530                            WaitingTime = taskData.WaitingTime,
531                            CalculatingTime = taskData.CalculatingTime,
532                            TransferTime = taskData.TransferTime,
533                            TaskState = x.State,
534                            Exception = taskData.Exception,
535                            InitialWaitingTime = taskData.InitialWaitingTime
536                          }).ToList();
537      Console.WriteLine("newFactTasks.Count = {0}", newFactTasks.Count);
538      factTaskDao.Save(newFactTasks);
539      Console.WriteLine("save of new fact tasks completed");
540    }
541
542    private string GetUserName(Guid userId) {
543      try {
544        // we cannot use the ServiceLocator.Instance.UserManager since the janitor service
545        // is not hosted in the iis the MemberShip.GetUser method causes exceptions
546        // needs to be further investigated current workaround: use the authenticationcontext
547        // we could also connect to the access service to get the user name
548        using (ASPNETAuthenticationDataContext dc = new ASPNETAuthenticationDataContext()) {
549          var user = dc.aspnet_Users.SingleOrDefault(x => x.UserId == userId);
550          return user != null ? user.UserName : UnknownUserName;
551        }
552      } catch (Exception) {
553        return UnknownUserName;
554      }
555    }
556
557    private class FactTaskData {
558      public int CalculationRuns { get; set; }
559      public int Retries { get; set; }
560      public long CalculatingTime { get; set; }
561      public long WaitingTime { get; set; }
562      public long TransferTime { get; set; }
563      public long InitialWaitingTime { get; set; }
564      public string Exception { get; set; }
565      public DateTime? StartTime { get; set; }
566      public DateTime? EndTime { get; set; }
567    }
568
569    private FactTaskData CalculateFactTaskData(IEnumerable<StateLog> stateLogs) {
570      var factTaskData = new FactTaskData();
571      var enumerator = stateLogs.GetEnumerator();
572      if (enumerator.MoveNext()) {
573        StateLog current = enumerator.Current, first = current, prev = null;
574        while (current != null) {
575          var next = enumerator.MoveNext() ? enumerator.Current : null;
576          int timeSpanInSeconds;
577          if (next != null) {
578            timeSpanInSeconds = (int)(next.DateTime - current.DateTime).TotalSeconds;
579          } else {
580            timeSpanInSeconds = (int)(DateTime.Now - current.DateTime).TotalSeconds;
581            factTaskData.Exception = current.Exception;
582          }
583          switch (current.State) {
584            case TaskState.Calculating:
585              factTaskData.CalculatingTime += timeSpanInSeconds;
586              factTaskData.CalculationRuns++;
587              if (factTaskData.CalculationRuns == 1) {
588                factTaskData.StartTime = current.DateTime;
589                factTaskData.InitialWaitingTime = (int)(current.DateTime - first.DateTime).TotalSeconds;
590              }
591              if (prev != null && prev.State != TaskState.Transferring) {
592                factTaskData.Retries++;
593              }
594              break;
595
596            case TaskState.Waiting:
597              factTaskData.WaitingTime += timeSpanInSeconds;
598              break;
599
600            case TaskState.Transferring:
601              factTaskData.TransferTime += timeSpanInSeconds;
602              break;
603
604            case TaskState.Finished:
605            case TaskState.Failed:
606            case TaskState.Aborted:
607              factTaskData.EndTime = current.DateTime;
608              break;
609          }
610          prev = current;
611          current = next;
612        }
613      }
614      return factTaskData;
615    }
616  }
617}
Note: See TracBrowser for help on using the repository browser.