Index: /branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs
===================================================================
--- /branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 12788)
+++ /branches/HiveStatistics/sources/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 12789)
@@ -27,4 +27,8 @@
 namespace HeuristicLab.Services.Hive.DataAccess.Daos {
   public class TaskDao : GenericDao<Guid, Task> {
+    private Table<AssignedResource> AssignedResourceTable {
+      get { return DataContext.GetTable<AssignedResource>(); }
+    }
+
     public TaskDao(DataContext dataContext) : base(dataContext) { }
 
@@ -51,4 +55,30 @@
       //we skip this step because it's wasted runtime
       return DataContext.ExecuteQuery<TaskPriorityInfo>(GetWaitingTasksQueryString, slave.ResourceId, Enum.GetName(typeof(TaskState), TaskState.Waiting), slave.FreeCores, slave.FreeMemory).ToList();
+    }
+
+    /// <summary>
+    /// returns all parent tasks which are waiting for their child tasks to finish
+    /// </summary>
+    /// <param name="resourceIds">list of resourceids which for which the task should be valid</param>
+    /// <param name="count">maximum number of task to return</param>
+    /// <param name="finished">if true, all parent task which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned</param>
+    /// <returns></returns>
+    public IEnumerable<Task> GetParentTasks(IEnumerable<Guid> resourceIds, int count, bool finished) {
+      var query = from ar in AssignedResourceTable
+                  where resourceIds.Contains(ar.ResourceId)
+                     && ar.Task.State == TaskState.Waiting
+                     && ar.Task.IsParentTask
+                     && (finished ? ar.Task.FinishWhenChildJobsFinished : !ar.Task.FinishWhenChildJobsFinished)
+                     && (from child in Table
+                         where child.ParentTaskId == ar.Task.TaskId
+                         select child.State == TaskState.Finished
+                             || child.State == TaskState.Aborted
+                             || child.State == TaskState.Failed).All(x => x)
+                     && (from child in Table // avoid returning WaitForChildTasks task where no child-task exist (yet)
+                         where child.ParentTaskId == ar.Task.TaskId
+                         select child).Any()
+                  orderby ar.Task.Priority descending
+                  select ar.Task;
+      return count == 0 ? query.ToArray() : query.Take(count).ToArray();
     }
 
Index: /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HeuristicLab.Services.Hive-3.3.csproj
===================================================================
--- /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HeuristicLab.Services.Hive-3.3.csproj	(revision 12788)
+++ /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HeuristicLab.Services.Hive-3.3.csproj	(revision 12789)
@@ -143,4 +143,5 @@
     <Compile Include="HiveStatisticsGenerator.cs" />
     <Compile Include="Interfaces\IStatisticsGenerator.cs" />
+    <Compile Include="Manager\NewEventManager.cs" />
     <Compile Include="Manager\NewHeartbeatManager.cs" />
     <Compile Include="NewHiveService.cs" />
Index: /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveJanitor.cs
===================================================================
--- /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveJanitor.cs	(revision 12788)
+++ /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/HiveJanitor.cs	(revision 12789)
@@ -31,18 +31,13 @@
     private AutoResetEvent generateStatisticsWaitHandle;
 
-    private ITransactionManager trans {
-      get { return ServiceLocator.Instance.TransactionManager; }
+    private IPersistenceManager PersistenceManager {
+      get { return ServiceLocator.Instance.PersistenceManager; }
     }
-
-    private IEventManager eventManager {
+    private IEventManager EventManager {
       get { return ServiceLocator.Instance.EventManager; }
     }
 
-    private IStatisticsGenerator statisticsGenerator {
+    private IStatisticsGenerator StatisticsGenerator {
       get { return ServiceLocator.Instance.StatisticsGenerator; }
-    }
-
-    private IHiveDao dao {
-      get { return ServiceLocator.Instance.HiveDao; }
     }
 
@@ -64,14 +59,18 @@
           LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log("HiveJanitor: starting cleanup.");
           bool cleanup = false;
-          trans.UseTransaction(() => {
-            DateTime lastCleanup = dao.GetLastCleanup();
-            if (DateTime.Now - lastCleanup > HeuristicLab.Services.Hive.Properties.Settings.Default.CleanupInterval) {
-              dao.SetLastCleanup(DateTime.Now);
-              cleanup = true;
-            }
-          }, true);
-
+          using (var pm = PersistenceManager) {
+            var lifecycleDao = pm.LifecycleDao;
+            pm.UseTransaction(() => {
+              var lifecycle = lifecycleDao.GetLastLifecycle();
+              if (lifecycle == null
+                  || DateTime.Now - lifecycle.LastCleanup > HeuristicLab.Services.Hive.Properties.Settings.Default.CleanupInterval) {
+                lifecycleDao.UpdateLifecycle();
+                cleanup = true;
+              }
+              pm.SubmitChanges();
+            }, true);
+          }
           if (cleanup) {
-            eventManager.Cleanup();
+            EventManager.Cleanup();
           }
           LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log("HiveJanitor: cleanup finished.");
@@ -89,5 +88,5 @@
         try {
           LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log("HiveJanitor: starting generate statistics.");
-          statisticsGenerator.GenerateStatistics();
+          StatisticsGenerator.GenerateStatistics();
           LogFactory.GetLogger(typeof(HiveJanitor).Namespace).Log("HiveJanitor: generate statistics finished.");
         }
Index: /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/NewEventManager.cs
===================================================================
--- /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/NewEventManager.cs	(revision 12789)
+++ /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/Manager/NewEventManager.cs	(revision 12789)
@@ -0,0 +1,111 @@
+﻿using System;
+using System.Linq;
+using HeuristicLab.Services.Hive.DataAccess;
+using HeuristicLab.Services.Hive.DataAccess.Interfaces;
+
+namespace HeuristicLab.Services.Hive.Manager {
+  public class NewEventManager : IEventManager {
+    private const string SlaveTimeout = "Slave timed out.";
+    private IPersistenceManager PersistenceManager {
+      get { return ServiceLocator.Instance.PersistenceManager; }
+    }
+    private IAuthorizationManager AuthorizationManager {
+      get { return ServiceLocator.Instance.AuthorizationManager; }
+    }
+    private ILogger Log {
+      get { return LogFactory.GetLogger(this.GetType().Namespace); }
+    }
+
+    public void Cleanup() {
+      using (var pm = PersistenceManager) {
+        // same transactions as the old EventManager
+        pm.UseTransaction(() => {
+          SetTimeoutSlavesOffline(pm);
+          SetTimeoutTasksWaiting(pm);
+          DeleteObsoleteSlaves(pm);
+          pm.SubmitChanges();
+        });
+
+        pm.UseTransaction(() => {
+          FinishParentTasks(pm);
+          pm.SubmitChanges();
+        });
+      }
+    }
+
+    /// <summary>
+    /// Searches for slaves which are timed out, puts them and their task offline
+    /// </summary>
+    private void SetTimeoutSlavesOffline(IPersistenceManager pm) {
+      var slaveDao = pm.SlaveDao;
+      var slaves = slaveDao.GetOnlineSlaves();
+      foreach (var slave in slaves) {
+        if (!slave.LastHeartbeat.HasValue ||
+            (DateTime.Now - slave.LastHeartbeat.Value) >
+            HeuristicLab.Services.Hive.Properties.Settings.Default.SlaveHeartbeatTimeout) {
+          slave.SlaveState = SlaveState.Offline;
+        }
+      }
+    }
+
+    /// <summary>
+    /// Looks for parent tasks which have FinishWhenChildJobsFinished and set their state to finished
+    /// </summary>
+    private void FinishParentTasks(IPersistenceManager pm) {
+      var resourceDao = pm.ResourceDao;
+      var taskDao = pm.TaskDao;
+      var resourceIds = resourceDao.GetAll().Select(x => x.ResourceId).ToList();
+      var parentTasksToFinish = taskDao.GetParentTasks(resourceIds, 0, true);
+      foreach (var task in parentTasksToFinish) {
+        task.State = TaskState.Finished;
+        task.StateLogs.Add(new StateLog {
+          State = task.State,
+          SlaveId = null,
+          UserId = null,
+          Exception = string.Empty,
+          DateTime = DateTime.Now
+        });
+      }
+    }
+
+    /// <summary>
+    /// Looks for task which have not sent heartbeats for some time and reschedules them for calculation
+    /// </summary>
+    private void SetTimeoutTasksWaiting(IPersistenceManager pm) {
+      var taskDao = pm.TaskDao;
+      var tasks = taskDao.GetAll().Where(x => (x.State == TaskState.Calculating && (DateTime.Now - x.LastHeartbeat) > HeuristicLab.Services.Hive.Properties.Settings.Default.CalculatingJobHeartbeatTimeout)
+                                           || (x.State == TaskState.Transferring && (DateTime.Now - x.LastHeartbeat) > HeuristicLab.Services.Hive.Properties.Settings.Default.TransferringJobHeartbeatTimeout));
+      foreach (var task in tasks) {
+        task.State = TaskState.Waiting;
+        task.StateLogs.Add(new StateLog {
+          State = task.State,
+          SlaveId = null,
+          UserId = null,
+          Exception = SlaveTimeout,
+          DateTime = DateTime.Now
+        });
+        task.Command = null;
+      }
+    }
+
+    /// <summary>
+    /// Searches for slaves that are disposable and deletes them if they were offline for too long
+    /// </summary>
+    private void DeleteObsoleteSlaves(IPersistenceManager pm) {
+      var slaveDao = pm.SlaveDao;
+      var downtimeDao = pm.DowntimeDao;
+      var slaveIds = slaveDao.GetAll()
+        .Where(x => x.IsDisposable.GetValueOrDefault()
+                 && x.SlaveState == SlaveState.Offline
+                 && (DateTime.Now - x.LastHeartbeat) > Hive.Properties.Settings.Default.SweepInterval)
+        .Select(x => x.ResourceId)
+        .ToList();
+      foreach (var id in slaveIds) {
+        bool downtimesAvailable = downtimeDao.GetByResourceId(id).Any();
+        if (!downtimesAvailable) {
+          slaveDao.Delete(id);
+        }
+      }
+    }
+  }
+}
Index: /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/ServiceLocator.cs
===================================================================
--- /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/ServiceLocator.cs	(revision 12788)
+++ /branches/HiveStatistics/sources/HeuristicLab.Services.Hive/3.3/ServiceLocator.cs	(revision 12789)
@@ -82,5 +82,5 @@
     public IEventManager EventManager {
       get {
-        if (eventManager == null) eventManager = new EventManager();
+        if (eventManager == null) eventManager = new NewEventManager();
         return eventManager;
       }
