source: branches/HiveProjectManagement/HeuristicLab.Services.Hive/3.3/HiveStatisticsGenerator.cs @ 15666

Last change on this file since 15666 was 15666, checked in by jzenisek, 3 years ago

#2839 implemented project facts-logging in HiveStatisticsGenerator

File size: 23.6 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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
40        pm.UseTransaction(() => {
41          UpdateDimProjectTable(pm);
42        });
43
44        pm.UseTransaction(() => {
45          UpdateDimUserTable(pm);
46         
47          UpdateDimJobTable(pm);
48          UpdateDimClientsTable(pm);
49          pm.SubmitChanges();
50        });
51
52        DimTime time = null;
53        pm.UseTransaction(() => {
54          time = UpdateDimTimeTable(pm);
55          pm.SubmitChanges();
56        });
57
58        if (time != null) {
59          pm.UseTransaction(() => {
60            UpdateFactClientInfoTable(time, pm);
61            UpdateFactProjectInfoTable(time, pm);
62            pm.SubmitChanges();
63          });
64
65          pm.UseTransaction(() => {
66            UpdateTaskFactsTable(pm);
67            try {
68              pm.SubmitChanges();
69              UpdateExistingDimJobs(pm);
70              pm.SubmitChanges();
71            }
72            catch (DuplicateKeyException e) {
73              var logger = LogFactory.GetLogger(typeof(HiveStatisticsGenerator).Namespace);
74              logger.Log(string.Format(
75                @"Propable change from summertime to wintertime, resulting in overlapping times.
76                          On wintertime to summertime change, slave timeouts and a fact gap will occur.
77                          Exception Details: {0}", e));
78            }
79          });
80        }
81
82        pm.UseTransaction(() => {
83          FlagJobsForDeletion(pm);
84          pm.SubmitChanges();
85        });
86      }
87    }
88
89    private DimTime UpdateDimTimeTable(PersistenceManager pm) {
90      var dimTimeDao = pm.DimTimeDao;
91      var now = DateTime.Now;
92      var timeEntry = new DimTime {
93        Time = now,
94        Minute = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0),
95        Hour = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0),
96        Day = new DateTime(now.Year, now.Month, now.Day, 0, 0, 0),
97        Month = new DateTime(now.Year, now.Month, 1, 0, 0, 0),
98        Year = new DateTime(now.Year, 1, 1, 0, 0, 0)
99      };
100      return dimTimeDao.Save(timeEntry);
101    }
102
103    private void UpdateDimUserTable(PersistenceManager pm) {
104      var dimUserDao = pm.DimUserDao;
105      var resourceDao = pm.ResourceDao;
106      var jobDao = pm.JobDao;
107      var existingUserIds = dimUserDao.GetAll().Select(x => x.UserId);
108      var vaildResourceOwnerIds = resourceDao.GetResourcesWithValidOwner().Select(x => x.OwnerUserId.Value);
109      var jobOwnerIds = jobDao.GetAll().Select(x => x.OwnerUserId);
110      var newUserIds = vaildResourceOwnerIds
111        .Union(jobOwnerIds)
112        .Where(id => !existingUserIds.Contains(id))
113        .ToList();
114      dimUserDao.Save(newUserIds.Select(x => new DimUser {
115        UserId = x,
116        Name = GetUserName(x)
117      }));
118    }
119
120    // add new projects
121    // delete expired projects
122    // update information of existing projects
123    private void UpdateDimProjectTable(PersistenceManager pm) {
124      var projectDao = pm.ProjectDao;
125      var dimProjectDao = pm.DimProjectDao;
126
127      var projects = projectDao.GetAll().ToList();
128      var dimProjects = dimProjectDao.GetAllOnlineProjects().ToList();
129
130      var onlineProjects = dimProjects.Where(x => projects.Select(y => y.ProjectId).Contains(x.ProjectId));
131      var addedProjects = projects.Where(x => !dimProjects.Select(y => y.ProjectId).Contains(x.ProjectId));
132      var removedProjects = dimProjects.Where(x => !projects.Select(y => y.ProjectId).Contains(x.ProjectId));
133
134      // set expiration time of removed projects
135      foreach (var p in removedProjects) {
136        p.DateExpired = DateTime.Now;
137      }
138
139      // add new projects
140      dimProjectDao.Save(addedProjects.Select(x => new DimProject {
141        ProjectId = x.ProjectId,
142        ParentProjectId = x.ParentProjectId,
143        Name = x.Name,
144        Description = x.Description,
145        OwnerUserId = x.OwnerUserId,
146        StartDate = x.StartDate,
147        EndDate = x.EndDate,
148        DateCreated = x.DateCreated,
149        DateExpired = null
150      }));
151
152      // if a project's parent has changed expire entry in DimProject and create a new entry
153      // else perform "normal" update
154      foreach (var dimP in onlineProjects) {
155        var p = projects.Where(x => x.ProjectId == dimP.ProjectId).SingleOrDefault();
156        if (p != null) {
157          if (dimP.ParentProjectId != p.ParentProjectId) {
158            dimP.DateExpired = DateTime.Now;
159            dimProjectDao.Save(new DimProject {
160              ProjectId = p.ProjectId,
161              ParentProjectId = p.ParentProjectId,
162              Name = p.Name,
163              Description = p.Description,
164              OwnerUserId = p.OwnerUserId,
165              StartDate = p.StartDate,
166              EndDate = p.EndDate,
167              DateCreated = p.DateCreated,
168              DateExpired = null
169            });
170          } else {
171            dimP.Name = p.Name;
172            dimP.Description = p.Description;
173            dimP.OwnerUserId = p.OwnerUserId;
174            dimP.StartDate = p.StartDate;
175            dimP.EndDate = p.EndDate;
176          }
177        }
178      }
179    }
180
181    private void UpdateDimJobTable(PersistenceManager pm) {
182      var dimProjectDao = pm.DimProjectDao;
183      var dimJobDao = pm.DimJobDao;
184      var jobDao = pm.JobDao;
185      var taskDao = pm.TaskDao;
186      var dimJobIds = dimJobDao.GetAll().Select(x => x.JobId);
187      var newJobs = jobDao.GetAll()
188        .Where(x => !dimJobIds.Contains(x.JobId))
189        .Select(x => new {
190          JobId = x.JobId,
191          UserId = x.OwnerUserId,
192          JobName = x.Name ?? string.Empty,
193          DateCreated = x.DateCreated,
194          ProjectId = dimProjectDao.GetLastValidIdByProjectId(x.ProjectId),
195          TotalTasks = taskDao.GetAll().Count(y => y.JobId == x.JobId)
196        })
197        .ToList();
198      dimJobDao.Save(newJobs.Select(x => new DimJob {
199        JobId = x.JobId,
200        JobName = x.JobName,
201        UserId = x.UserId,
202        UserName = GetUserName(x.UserId),
203        DateCreated = x.DateCreated,
204        ProjectId = x.ProjectId,
205        TotalTasks = x.TotalTasks,
206        CompletedTasks = 0,
207        DateCompleted = null
208      }));
209    }
210
211    private void UpdateExistingDimJobs(PersistenceManager pm) {
212      var dimProjectDao = pm.DimProjectDao;
213      var jobDao = pm.JobDao;
214      var dimJobDao = pm.DimJobDao;
215      var factTaskDao = pm.FactTaskDao;
216      foreach (var dimJob in dimJobDao.GetNotCompletedJobs()) {
217        var taskStates = factTaskDao.GetByJobId(dimJob.JobId)
218            .GroupBy(x => x.TaskState)
219            .Select(x => new {
220              State = x.Key,
221              Count = x.Count()
222            }).ToList();
223        int totalTasks = 0, completedTasks = 0;
224        foreach (var state in taskStates) {
225          totalTasks += state.Count;
226          if (CompletedStates.Contains(state.State)) {
227            completedTasks += state.Count;
228          }
229        }
230        var job = jobDao.GetById(dimJob.JobId);
231        if (totalTasks == completedTasks) {
232          var completeDate = factTaskDao.GetLastCompletedTaskFromJob(dimJob.JobId);
233          if (completeDate == null) {
234            if (job == null) {
235              completeDate = DateTime.Now;
236            }
237          }
238          dimJob.DateCompleted = completeDate;
239        }
240        if(job != null) {
241          dimJob.JobName = job.Name;
242          dimJob.ProjectId = dimProjectDao.GetLastValidIdByProjectId(job.ProjectId);
243        }
244
245        dimJob.TotalTasks = totalTasks;
246        dimJob.CompletedTasks = completedTasks;
247      }
248    }
249
250    private void FlagJobsForDeletion(PersistenceManager pm) {
251      var jobDao = pm.JobDao;
252      var jobs = jobDao.GetJobsReadyForDeletion();
253      foreach(var job in jobs) {
254        job.State = JobState.DeletionPending;
255      }
256    }
257
258    // (1) for new slaves (not yet reported in Table DimClients) ...
259    // and modified slaves (name or parent resource changed) a new DimClient-entry is created
260    // (2) for already reported removed and modifid clients the expiration date is set
261    private void UpdateDimClientsTable(PersistenceManager pm) {
262      var dimClientDao = pm.DimClientDao;
263      var slaveDao = pm.SlaveDao;
264      var slaves = slaveDao.GetAll();
265      var recentlyAddedClients = dimClientDao.GetActiveClients();
266      var slaveIds = slaves.Select(x => x.ResourceId);
267
268      var removedClientIds = recentlyAddedClients
269        .Where(x => !slaveIds.Contains(x.ResourceId))
270        .Select(x => x.Id);
271      var modifiedClients =
272        from slave in slaves
273        join client in recentlyAddedClients on slave.ResourceId equals client.ResourceId
274        where (slave.Name != client.Name
275               || slave.ParentResourceId == null && client.ResourceGroupId != null // because both can be null and null comparison
276               || slave.ParentResourceId != null && client.ResourceGroupId == null // does return no entry on the sql server
277               || slave.ParentResourceId != client.ResourceGroupId
278               || ((slave.ParentResource != null) && slave.ParentResource.ParentResourceId != client.ResourceGroup2Id))
279        select new {
280          SlaveId = slave.ResourceId,
281          ClientId = client.Id
282        };
283      var clientIds = dimClientDao.GetActiveClients().Select(x => x.ResourceId);
284      var modifiedClientIds = modifiedClients.Select(x => x.SlaveId);
285      var newClients = slaves
286        .Where(x => !clientIds.Contains(x.ResourceId)
287                    || modifiedClientIds.Contains(x.ResourceId))
288        .Select(x => new {
289          x.ResourceId,
290          x.Name,
291          ResourceGroupId = x.ParentResourceId,
292          GroupName = x.ParentResource != null ? x.ParentResource.Name : null,
293          ResourceGroup2Id = x.ParentResource != null ? x.ParentResource.ParentResourceId : null,
294          GroupName2 = x.ParentResource != null ? x.ParentResource.ParentResource != null ? x.ParentResource.ParentResource.Name : null : null
295        })
296        .ToList();
297
298      var clientsToUpdate = removedClientIds.Union(modifiedClients.Select(x => x.ClientId));
299      dimClientDao.UpdateExpirationTime(clientsToUpdate, DateTime.Now);
300      dimClientDao.Save(newClients.Select(x => new DimClient {
301        ResourceId = x.ResourceId,
302        Name = x.Name,
303        ExpirationTime = null,
304        ResourceGroupId = x.ResourceGroupId,
305        GroupName = x.GroupName,
306        ResourceGroup2Id = x.ResourceGroup2Id,
307        GroupName2 = x.GroupName2
308      }));
309    }
310
311    private void UpdateFactClientInfoTable(DimTime newTime, PersistenceManager pm) {
312      var factClientInfoDao = pm.FactClientInfoDao;
313      var slaveDao = pm.SlaveDao;
314      var dimClientDao = pm.DimClientDao;
315
316      var newRawFactInfos =
317        from s in slaveDao.GetAll()
318        join c in dimClientDao.GetActiveClients() on s.ResourceId equals c.ResourceId
319        join lcf in factClientInfoDao.GetLastUpdateTimestamps() on c.ResourceId equals lcf.ResourceId into joinCf
320        from cf in joinCf.DefaultIfEmpty()
321        select new {
322          ClientId = c.Id,
323          UserId = s.OwnerUserId ?? Guid.Empty,
324          TotalCores = s.Cores ?? 0,
325          FreeCores = s.FreeCores ?? 0,
326          TotalMemory = s.Memory ?? 0,
327          FreeMemory = s.FreeMemory ?? 0,
328          CpuUtilization = s.CpuUtilization,
329          SlaveState = s.SlaveState,
330          IsAllowedToCalculate = s.IsAllowedToCalculate,
331          LastFactTimestamp = cf.Timestamp
332        };
333
334      factClientInfoDao.Save(
335        from x in newRawFactInfos.ToList()
336        let duration = x.LastFactTimestamp != null
337                       ? (int)(newTime.Time - (DateTime)x.LastFactTimestamp).TotalSeconds
338                       : (int)SmallestTimeSpan.TotalSeconds
339        select new FactClientInfo {
340          ClientId = x.ClientId,
341          DimTime = newTime,
342          UserId = x.UserId,
343          NumUsedCores = x.TotalCores - x.FreeCores,
344          NumTotalCores = x.TotalCores,
345          UsedMemory = x.TotalMemory - x.FreeMemory,
346          TotalMemory = x.TotalMemory,
347          CpuUtilization = Math.Round(x.CpuUtilization, 2),
348          SlaveState = x.SlaveState,
349          IdleTime = x.SlaveState == SlaveState.Idle && x.IsAllowedToCalculate ? duration : 0,
350          UnavailableTime = x.SlaveState == SlaveState.Idle && !x.IsAllowedToCalculate ? duration : 0,
351          OfflineTime = x.SlaveState == SlaveState.Offline ? duration : 0,
352          IsAllowedToCalculate = x.IsAllowedToCalculate
353        }
354      );
355    }
356
357    private void UpdateFactProjectInfoTable(DimTime newTime, PersistenceManager pm) {
358      var factProjectInfoDao = pm.FactProjectInfoDao;
359      var dimProjectDao = pm.DimProjectDao;
360      var projectDao = pm.ProjectDao;
361
362      var projectAvailabilityStats = projectDao.GetAvailabilityStatsPerProject();
363      var projectUsageStats = projectDao.GetUsageStatsPerProject();
364      var dimProjects = dimProjectDao.GetAllOnlineProjects().ToList();
365
366      factProjectInfoDao.Save(
367        from dimp in dimProjects
368        let aStats = projectAvailabilityStats.Where(x => x.ProjectId == dimp.ProjectId).SingleOrDefault()
369        let uStats = projectUsageStats.Where(x => x.ProjectId == dimp.ProjectId).SingleOrDefault()
370        select new FactProjectInfo {
371            ProjectId = dimp.ProjectId,
372            DimTime = newTime,
373            NumTotalCores = aStats != null ? aStats.Cores : 0,
374            TotalMemory = aStats != null ? aStats.Memory : 0,
375            NumUsedCores = uStats != null ? uStats.Cores : 0,
376            UsedMemory = uStats != null ? uStats.Memory : 0
377          }
378        );
379    }
380
381    private void UpdateTaskFactsTable(PersistenceManager pm) {
382      var factTaskDao = pm.FactTaskDao;
383      var taskDao = pm.TaskDao;
384      var dimClientDao = pm.DimClientDao;
385
386      var factTaskIds = factTaskDao.GetAll().Select(x => x.TaskId);
387      var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks();
388      //var notFinishedFactTasks = factTaskDao.GetNotFinishedTasks().Select(x => new {
389      //  x.TaskId,
390      //  x.LastClientId
391      //});
392
393      // query several properties for all new and not finished tasks
394      // in order to use them later eitheir
395      // (1) to update the fact task entry of not finished tasks
396      // (2) to insert a new fact task entry for new tasks
397      var newAndNotFinishedTasks =
398        (from task in taskDao.GetAllChildTasks()
399         let stateLogs = task.StateLogs.OrderByDescending(x => x.DateTime)
400         let lastSlaveId = stateLogs.First(x => x.SlaveId != null).SlaveId
401         where (!factTaskIds.Contains(task.TaskId)
402                || notFinishedFactTasks.Select(x => x.TaskId).Contains(task.TaskId))
403         join lastFactTask in notFinishedFactTasks on task.TaskId equals lastFactTask.TaskId into lastFactPerTask
404         from lastFact in lastFactPerTask.DefaultIfEmpty()
405         join client in dimClientDao.GetActiveClients() on lastSlaveId equals client.ResourceId into clientsPerSlaveId
406         from client in clientsPerSlaveId.DefaultIfEmpty()
407         select new {
408           TaskId = task.TaskId,
409           JobId = task.JobId,
410           Priority = task.Priority,
411           CoresRequired = task.CoresNeeded,
412           MemoryRequired = task.MemoryNeeded,
413           State = task.State,
414           StateLogs = stateLogs.OrderBy(x => x.DateTime),
415           LastClientId = client != null
416                          ? client.Id : lastFact != null
417                          ? lastFact.LastClientId : (Guid?)null,
418           NotFinishedTask = notFinishedFactTasks.Any(y => y.TaskId == task.TaskId)
419         }).ToList();
420
421      // (1) update data of already existing facts
422      // i.e. for all in newAndNotFinishedTasks where NotFinishedTask = true
423      foreach (var notFinishedFactTask in notFinishedFactTasks) {
424        var nfftUpdate = newAndNotFinishedTasks.Where(x => x.TaskId == notFinishedFactTask.TaskId).SingleOrDefault();
425        if(nfftUpdate != null) {
426          var taskData = CalculateFactTaskData(nfftUpdate.StateLogs);
427
428          notFinishedFactTask.StartTime = taskData.StartTime;
429          notFinishedFactTask.EndTime = taskData.EndTime;
430          notFinishedFactTask.LastClientId = nfftUpdate.LastClientId;
431          notFinishedFactTask.Priority = nfftUpdate.Priority;
432          notFinishedFactTask.CoresRequired = nfftUpdate.CoresRequired;
433          notFinishedFactTask.MemoryRequired = nfftUpdate.MemoryRequired;
434          notFinishedFactTask.NumCalculationRuns = taskData.CalculationRuns;
435          notFinishedFactTask.NumRetries = taskData.Retries;
436          notFinishedFactTask.WaitingTime = taskData.WaitingTime;
437          notFinishedFactTask.CalculatingTime = taskData.CalculatingTime;
438          notFinishedFactTask.TransferTime = taskData.TransferTime;
439          notFinishedFactTask.TaskState = nfftUpdate.State;
440          notFinishedFactTask.Exception = taskData.Exception;
441          notFinishedFactTask.InitialWaitingTime = taskData.InitialWaitingTime;
442        }
443      }
444
445      // (2) insert facts for new tasks
446      // i.e. for all in newAndNotFinishedTasks where NotFinishedTask = false
447      factTaskDao.Save(
448        from x in newAndNotFinishedTasks
449        where !x.NotFinishedTask
450        let taskData = CalculateFactTaskData(x.StateLogs)
451        select new FactTask {
452          TaskId = x.TaskId,
453          JobId = x.JobId,
454          StartTime = taskData.StartTime,
455          EndTime = taskData.EndTime,
456          LastClientId = x.LastClientId,
457          Priority = x.Priority,
458          CoresRequired = x.CoresRequired,
459          MemoryRequired = x.MemoryRequired,
460          NumCalculationRuns = taskData.CalculationRuns,
461          NumRetries = taskData.Retries,
462          WaitingTime = taskData.WaitingTime,
463          CalculatingTime = taskData.CalculatingTime,
464          TransferTime = taskData.TransferTime,
465          TaskState = x.State,
466          Exception = taskData.Exception,
467          InitialWaitingTime = taskData.InitialWaitingTime
468        });
469
470
471      ////update data of already existing facts
472      //foreach (var notFinishedTask in factTaskDao.GetNotFinishedTasks()) {
473      //  var ntc = newTasks.Where(x => x.TaskId == notFinishedTask.TaskId);
474      //  if (ntc.Any()) {
475      //    var x = ntc.Single();
476      //    var taskData = CalculateFactTaskData(x.StateLogs);
477
478      //    notFinishedTask.StartTime = taskData.StartTime;
479      //    notFinishedTask.EndTime = taskData.EndTime;
480      //    notFinishedTask.LastClientId = x.LastClientId;
481      //    notFinishedTask.Priority = x.Priority;
482      //    notFinishedTask.CoresRequired = x.CoresRequired;
483      //    notFinishedTask.MemoryRequired = x.MemoryRequired;
484      //    notFinishedTask.NumCalculationRuns = taskData.CalculationRuns;
485      //    notFinishedTask.NumRetries = taskData.Retries;
486      //    notFinishedTask.WaitingTime = taskData.WaitingTime;
487      //    notFinishedTask.CalculatingTime = taskData.CalculatingTime;
488      //    notFinishedTask.TransferTime = taskData.TransferTime;
489      //    notFinishedTask.TaskState = x.State;
490      //    notFinishedTask.Exception = taskData.Exception;
491      //    notFinishedTask.InitialWaitingTime = taskData.InitialWaitingTime;
492      //  }
493      //}
494    }
495
496    private string GetUserName(Guid userId) {
497      try {
498        // we cannot use the ServiceLocator.Instance.UserManager since the janitor service
499        // is not hosted in the iis the MemberShip.GetUser method causes exceptions
500        // needs to be further investigated current workaround: use the authenticationcontext
501        // we could also connect to the access service to get the user name
502        using (ASPNETAuthenticationDataContext dc = new ASPNETAuthenticationDataContext()) {
503          var user = dc.aspnet_Users.SingleOrDefault(x => x.UserId == userId);
504          return user != null ? user.UserName : UnknownUserName;
505        }
506      }
507      catch (Exception) {
508        return UnknownUserName;
509      }
510    }
511
512    private class FactTaskData {
513      public int CalculationRuns { get; set; }
514      public int Retries { get; set; }
515      public long CalculatingTime { get; set; }
516      public long WaitingTime { get; set; }
517      public long TransferTime { get; set; }
518      public long InitialWaitingTime { get; set; }
519      public string Exception { get; set; }
520      public DateTime? StartTime { get; set; }
521      public DateTime? EndTime { get; set; }
522    }
523
524    private FactTaskData CalculateFactTaskData(IEnumerable<StateLog> stateLogs) {
525      var factTaskData = new FactTaskData();
526      var enumerator = stateLogs.GetEnumerator();
527      if (enumerator.MoveNext()) {
528        StateLog current = enumerator.Current, first = current, prev = null;
529        while (current != null) {
530          var next = enumerator.MoveNext() ? enumerator.Current : null;
531          int timeSpanInSeconds;
532          if (next != null) {
533            timeSpanInSeconds = (int)(next.DateTime - current.DateTime).TotalSeconds;
534          } else {
535            timeSpanInSeconds = (int)(DateTime.Now - current.DateTime).TotalSeconds;
536            factTaskData.Exception = current.Exception;
537          }
538          switch (current.State) {
539            case TaskState.Calculating:
540              factTaskData.CalculatingTime += timeSpanInSeconds;
541              factTaskData.CalculationRuns++;
542              if (factTaskData.CalculationRuns == 1) {
543                factTaskData.StartTime = current.DateTime;
544                factTaskData.InitialWaitingTime = (int)(current.DateTime - first.DateTime).TotalSeconds;
545              }
546              if (prev != null && prev.State != TaskState.Transferring) {
547                factTaskData.Retries++;
548              }
549              break;
550
551            case TaskState.Waiting:
552              factTaskData.WaitingTime += timeSpanInSeconds;
553              break;
554
555            case TaskState.Transferring:
556              factTaskData.TransferTime += timeSpanInSeconds;
557              break;
558
559            case TaskState.Finished:
560            case TaskState.Failed:
561            case TaskState.Aborted:
562              factTaskData.EndTime = current.DateTime;
563              break;
564          }
565          prev = current;
566          current = next;
567        }
568      }
569      return factTaskData;
570    }
571  }
572}
Note: See TracBrowser for help on using the repository browser.