Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedJobResourceDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedJobResourceDao.cs	(revision 16141)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedJobResourceDao.cs	(revision 16141)
@@ -0,0 +1,248 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class AssignedJobResourceDao : GenericDao<Guid, AssignedJobResource> {
+    public AssignedJobResourceDao(DataContext dataContext) : base(dataContext) { }
+
+    public override AssignedJobResource GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public IQueryable<AssignedJobResource> GetByJobId(Guid jobId) {
+      return Table.Where(x => x.JobId == jobId);
+    }
+
+    public void DeleteByProjectId(Guid projectId) {
+      DataContext.ExecuteCommand(DeleteByProjectIdQueryString, projectId);
+    }
+
+    public void DeleteByProjectIdAndUserIds(Guid projectId, IEnumerable<Guid> userIds) {
+      string paramUserIds = string.Join(",", userIds.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramUserIds)) {
+        string queryString = string.Format(DeleteByProjectIdAndUserIdsQueryString, projectId, paramUserIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public void DeleteByProjectIds(IEnumerable<Guid> projectIds) {
+      string paramProjectIds = string.Join(",", projectIds.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds)) {
+        string queryString = string.Format(DeleteByProjectIdsQueryString, paramProjectIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public void DeleteByProjectIdsAndUserIds(IEnumerable<Guid> projectIds, IEnumerable<Guid> userIds) {
+      string paramProjectIds = string.Join(",", projectIds.Select(x => string.Format("'{0}'", x)));
+      string paramUserIds = string.Join(",", userIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds) && !string.IsNullOrWhiteSpace(paramUserIds)) {
+        string queryString = string.Format(DeleteByProjectIdsAndUserIdsQueryString, paramProjectIds, paramUserIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public void DeleteByProjectIdAndResourceIds(Guid projectId, IEnumerable<Guid> resourceIds) {
+      string paramResourceIds = string.Join(",", resourceIds.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string queryString = string.Format(DeleteByProjectIdAndResourceIdsQueryString, projectId, paramResourceIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public void DeleteByProjectIdsAndResourceIds(IEnumerable<Guid> projectIds, IEnumerable<Guid> resourceIds) {
+      string paramProjectIds = string.Join(",", projectIds.Select(x => string.Format("'{0}'", x)));
+      string paramResourceIds = string.Join(",", resourceIds.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds) && !string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string queryString = string.Format(DeleteByProjectIdsAndResourceIdsQueryString, paramProjectIds, paramResourceIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public bool CheckJobGrantedForResource(Guid jobId, Guid resourceId) {
+      return DataContext.ExecuteQuery<int>(CheckJobGrantedForResourceQueryString, jobId, resourceId).First() > 0;
+    }
+
+    public bool CheckJobGrantedForResources(Guid jobId, IEnumerable<Guid> resourceIds) {
+      string paramResourceIds = string.Join(",", resourceIds.Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string queryString = string.Format(CheckJobGrantedForResourcesQueryString, jobId, paramResourceIds);
+        return DataContext.ExecuteQuery<int>(queryString).Count() == 0;
+      }
+      return false;
+    }
+
+    public bool CheckTaskGrantedForResource(Guid taskId, Guid resourceId) {
+      return DataContext.ExecuteQuery<int>(CheckTaskGrantedForResourceQueryString, taskId, resourceId).First() > 0;
+    }
+
+    public IEnumerable<Resource> GetAllGrantedResourcesByJobId(Guid jobId) {
+      return DataContext.ExecuteQuery<Resource>(GetAllGrantedResourcesByJobIdQueryString, jobId);
+    }
+
+    public IEnumerable<Guid> GetAllGrantedResourceIdsByJobId(Guid jobId) {
+      return DataContext.ExecuteQuery<Guid>(GetAllGrantedResourceIdsByJobIdQueryString, jobId);
+    }
+
+    #region String queries
+    private const string DeleteByProjectIdQueryString = @"
+      DELETE FROM [AssignedJobResource]
+      WHERE JobId IN
+	      (
+		      SELECT j.JobId
+		      FROM [Job] j
+		      WHERE j.ProjectId = {0}
+	      )
+    ";
+    private const string DeleteByProjectIdAndUserIdsQueryString = @"
+      DELETE FROM [AssignedJobResource]
+      WHERE JobId IN
+	      (
+		      SELECT j.JobId
+		      FROM [Job] j
+		      WHERE j.ProjectId = '{0}'
+          AND j.OwnerUserId IN ({1})
+	      )
+    ";
+    private const string DeleteByProjectIdsQueryString = @"
+      DELETE FROM [AssignedJobResource]
+      WHERE JobId IN
+	      (
+		      SELECT j.JobId
+		      FROM [Job] j
+		      WHERE j.ProjectId IN ({0})
+	      )
+    ";
+    private const string DeleteByProjectIdsAndUserIdsQueryString = @"
+      DELETE FROM [AssignedJobResource]
+      WHERE JobId IN
+	      (
+		      SELECT j.JobId
+		      FROM [Job] j
+		      WHERE j.ProjectId IN ({0})
+          AND j.OwnerUserId IN ({1})
+	      )
+    ";
+    private const string DeleteByProjectIdAndResourceIdsQueryString = @"
+      DELETE FROM [AssignedJobResource]
+      WHERE JobId IN
+	      (
+		      SELECT j.JobId
+		      FROM [Job] j
+		      WHERE j.ProjectId = '{0}'
+	      )
+      AND ResourceId IN ({1})
+    ";
+    private const string DeleteByProjectIdsAndResourceIdsQueryString = @"
+      DELETE FROM [AssignedJobResource]
+      WHERE JobId IN
+	      (
+		      SELECT j.JobId
+		      FROM [Job] j
+		      WHERE j.ProjectId IN ({0})
+	      )
+      AND ResourceId IN ({1})
+    ";
+    private const string CheckJobGrantedForResourceQueryString = @"
+      WITH rbranch AS (
+        SELECT ResourceId, ParentResourceId
+        FROM [Resource]
+        WHERE ResourceId = {1}
+        UNION ALL
+        SELECT r.ResourceId, r.ParentResourceId
+        FROM [Resource] r
+        JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId
+      )
+      SELECT COUNT(ajr.JobId)
+      FROM rbranch, [AssignedJobResource] ajr
+      WHERE rbranch.ResourceId = ajr.ResourceId
+      AND ajr.JobId = {0}
+    ";
+    private const string CheckTaskGrantedForResourceQueryString = @"
+      WITH rbranch AS (
+        SELECT ResourceId, ParentResourceId
+        FROM [Resource]
+        WHERE ResourceId = {1}
+        UNION ALL
+        SELECT r.ResourceId, r.ParentResourceId
+        FROM [Resource] r
+        JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId
+      )
+      SELECT COUNT(ajr.JobId)
+      FROM rbranch, [AssignedJobResource] ajr, [Task] t
+      WHERE rbranch.ResourceId = ajr.ResourceId
+      AND ajr.JobId = t.JobId
+      AND t.JobId = {0}
+    ";
+    private const string CheckJobGrantedForResourcesQueryString = @"
+      WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+      )
+      SELECT r.ResourceId
+      FROM [Resource] r
+      WHERE r.ResourceId IN ({1})
+      EXCEPT
+      (
+	      SELECT rtree.ResourceId
+	      FROM rtree, [AssignedJobResource] ajr
+	      WHERE rtree.ParentResourceId = ajr.ResourceId
+	      AND ajr.JobId = {0}
+	      UNION
+	      SELECT ajr.ResourceId
+	      FROM [AssignedJobResource] ajr
+	      WHERE ajr.JobId = {0}
+      )
+    ";
+    private const string GetAllGrantedResourcesByJobIdQueryString = @"
+      WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+      )
+      SELECT res.*
+      FROM rtree, [AssignedJobResource] ajr, [Resource] res
+      WHERE rtree.ParentResourceId = ajr.ResourceId
+      AND rtree.ResourceId = res.ResourceId
+      AND ajr.JobId = {0}
+      UNION
+      SELECT res.*
+      FROM [AssignedJobResource] ajr, [Resource] res
+      WHERE ajr.ResourceId = res.ResourceId
+      AND ajr.JobId = {0}
+    ";
+    private const string GetAllGrantedResourceIdsByJobIdQueryString = @"
+    WITH rtree AS
+    (
+	    SELECT ResourceId, ParentResourceId
+	    FROM [Resource]
+	    UNION ALL
+	    SELECT rt.ResourceId, r.ParentResourceId
+	    FROM [Resource] r
+	    JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+    )
+    SELECT rtree.ResourceId
+    FROM rtree, [AssignedJobResource] ajr
+    WHERE rtree.ParentResourceId = ajr.ResourceId
+    AND ajr.JobId = {0}
+    UNION
+    SELECT ajr.ResourceId
+    FROM [AssignedJobResource] ajr
+    WHERE ajr.JobId = {0}
+    ";
+    #endregion
+  }
+}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedProjectResourceDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedProjectResourceDao.cs	(revision 16141)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/AssignedProjectResourceDao.cs	(revision 16141)
@@ -0,0 +1,233 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class AssignedProjectResourceDao : GenericDao<Guid, AssignedProjectResource> {
+    public AssignedProjectResourceDao(DataContext dataContext) : base(dataContext) { }
+
+    public override AssignedProjectResource GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public IQueryable<AssignedProjectResource> GetByProjectId(Guid projectId) {
+      return Table.Where(x => x.ProjectId == projectId);
+    }
+
+    public void DeleteByProjectIdAndResourceIds(Guid projectId, IEnumerable<Guid> resourceIds) {
+      string paramIds = string.Join(",", resourceIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramIds)) {
+        string query = string.Format(DeleteByProjectIdAndResourceIdsQueryString, projectId, paramIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    public void DeleteByProjectIdsAndResourceIds(IEnumerable<Guid> projectIds, IEnumerable<Guid> resourceIds) {
+      string paramProjectIds = string.Join(",", projectIds.ToList().Select(x => string.Format("'{0}'", x)));
+      string paramResourceIds = string.Join(",", resourceIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds) && !string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string query = string.Format(DeleteByProjectIdsAndResourceIdsQueryString, paramProjectIds, paramResourceIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    public void DeleteByProjectIds(IEnumerable<Guid> projectIds) {
+      string paramProjectIds = string.Join(",", projectIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds)) {
+        string query = string.Format(DeleteByProjectIdsQueryString, paramProjectIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    public bool CheckProjectGrantedForResources(Guid projectId, IEnumerable<Guid> resourceIds) {
+      string paramResourceIds = string.Join(",", resourceIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string queryString = string.Format(CheckProjectGrantedForResourcesQueryString, projectId, paramResourceIds);
+        return DataContext.ExecuteQuery<int>(queryString).Count() == 0;
+      }
+      return false;
+    }
+
+    public IEnumerable<Resource> GetAllGrantedResourcesByProjectId(Guid projectId) {
+      return DataContext.ExecuteQuery<Resource>(GetAllGrantedResourcesByProjectIdQueryString, projectId);
+    }
+
+    public IEnumerable<Guid> GetAllGrantedResourceIdsByProjectId(Guid projectId) {
+      return DataContext.ExecuteQuery<Guid>(GetAllGrantedResourceIdsByProjectIdQueryString, projectId);
+    }
+
+    public IEnumerable<Resource> GetAllGrantedResourcesByProjectIds(IEnumerable<Guid> projectIds) {
+      string paramProjectIds = string.Join(",", projectIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds)) {
+        string queryString = string.Format(GetAllGrantedResourcesByProjectIdsQueryString, paramProjectIds);
+        return DataContext.ExecuteQuery<Resource>(queryString);
+      }
+      return Enumerable.Empty<Resource>();
+    }
+
+    public IEnumerable<Guid> GetAllGrantedResourceIdsOfOwnedParentProjects(Guid projectId, Guid userId) {
+      return DataContext.ExecuteQuery<Guid>(GetAllGrantedResourceIdsOfOwnedParentProjectsQueryString, projectId, userId);
+    }
+
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, IEnumerable<AssignedProjectResource>> GetByProjectIdGetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid projectId) =>
+        from projectPermission in db.GetTable<AssignedProjectResource>()
+        where projectPermission.ProjectId == projectId
+        select projectPermission);
+    #endregion
+
+    #region String queries
+    private const string DeleteByProjectIdAndResourceIdsQueryString = @"
+      DELETE FROM [AssignedProjectResource]
+        WHERE ProjectId = '{0}'
+        AND ResourceId IN ({1});
+    ";
+    private const string DeleteByProjectIdsAndResourceIdsQueryString = @"
+      DELETE FROM [AssignedProjectResource]
+        WHERE ProjectId IN ({0})
+        AND ResourceId IN ({1});
+    ";
+    private const string DeleteByProjectIdsQueryString = @"
+      DELETE FROM [AssignedProjectResource]
+        WHERE ProjectId IN ({0})
+    ";
+    private const string CheckProjectGrantedForResourcesQueryString = @"
+    WITH rtree AS
+    (
+	    SELECT ResourceId, ParentResourceId
+	    FROM [Resource]
+	    UNION ALL
+	    SELECT rt.ResourceId, r.ParentResourceId
+	    FROM [Resource] r
+	    JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+    )
+    SELECT r.ResourceId
+    FROM [Resource] r
+    WHERE r.ResourceId IN ({1})
+    EXCEPT
+    (
+	    SELECT rtree.ResourceId
+	    FROM rtree, [AssignedProjectResource] apr
+	    WHERE rtree.ParentResourceId = apr.ResourceId
+	    AND apr.ProjectId = '{0}'
+	    UNION
+	    SELECT apr.ResourceId
+	    FROM [AssignedProjectResource] apr
+	    WHERE apr.ProjectId = '{0}'
+    )
+    ";
+    private const string GetAllGrantedResourcesByProjectIdQueryString = @"
+      WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+      )
+      SELECT res.*
+      FROM rtree, [AssignedProjectResource] apr, [Resource] res
+      WHERE rtree.ParentResourceId = apr.ResourceId
+      AND rtree.ResourceId = res.ResourceId
+      AND apr.ProjectId = '{0}'
+      UNION
+      SELECT res.*
+      FROM [AssignedProjectResource] apr, [Resource] res
+      WHERE apr.ResourceId = res.ResourceId
+      AND apr.ProjectId = '{0}'
+    ";
+    private const string GetAllGrantedResourceIdsByProjectIdQueryString = @"
+    WITH rtree AS
+    (
+	    SELECT ResourceId, ParentResourceId
+	    FROM [Resource]
+	    UNION ALL
+	    SELECT rt.ResourceId, r.ParentResourceId
+	    FROM [Resource] r
+	    JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+    )
+    SELECT rtree.ResourceId
+    FROM rtree, [AssignedProjectResource] apr
+    WHERE rtree.ParentResourceId = apr.ResourceId
+    AND apr.ProjectId = '{0}'
+    UNION
+    SELECT apr.ResourceId
+    FROM [AssignedProjectResource] apr
+    WHERE apr.ProjectId = '{0}'
+    ";
+    private const string GetAllGrantedResourcesByProjectIdsQueryString = @"
+      WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+      )
+      SELECT res.*
+      FROM rtree, [AssignedProjectResource] apr, [Resource] res
+      WHERE rtree.ParentResourceId = apr.ResourceId
+      AND rtree.ResourceId = res.ResourceId
+      AND apr.ProjectId IN ({0})
+      UNION
+      SELECT res.*
+      FROM [AssignedProjectResource] apr, [Resource] res
+      WHERE apr.ResourceId = res.ResourceId
+      AND apr.ProjectId IN ({0})
+    ";
+    private const string GetAllGrantedResourceIdsOfOwnedParentProjectsQueryString = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId
+	      FROM [Project]
+	      UNION ALL
+	      SELECT pb.ProjectId, p.ParentProjectId
+	      FROM [Project] p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pb.ParentProjectId <> pb.ProjectId
+      ),
+      rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId AND r.ParentResourceId <> r.ResourceId AND rt.ParentResourceId <> rt.ResourceId
+      )
+      SELECT DISTINCT rtree.ResourceId
+      FROM pbranch, rtree, [Project] pro, [AssignedProjectResource] apr
+      WHERE pbranch.ProjectId = {0}
+      AND pbranch.ParentProjectId = pro.ProjectId
+      AND pro.OwnerUserId = {1}
+      AND pbranch.ParentProjectId = apr.ProjectId
+      AND apr.ResourceId = rtree.ParentResourceId
+    ";
+    #endregion
+  }
+}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs	(revision 16140)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimClientDao.cs	(revision 16141)
@@ -33,10 +33,26 @@
     }
 
-    public IQueryable<DimClient> GetActiveClients() {
-      return Table.Where(x => x.ExpirationTime == null);
+    public IQueryable<DimClient> GetAllOnlineClients() {
+      return Table.Where(x => x.DateExpired == null);
     }
 
-    public IQueryable<DimClient> GetExpiredClients() {
-      return Table.Where(x => x.ExpirationTime != null);
+    public IQueryable<DimClient> GetAllExpiredClients() {
+      return Table.Where(x => x.DateExpired != null);
+    }
+
+    public IQueryable<DimClient> GetAllOnlineSlaves() {
+      return Table.Where(x => x.DateExpired == null && x.ResourceType == "Slave");
+    }
+
+    public IQueryable<DimClient> GetAllOnlineSlaveGroups() {
+      return Table.Where(x => x.DateExpired == null && x.ResourceType == "GROUP");
+    }
+
+    public IQueryable<DimClient> GetAllExpiredSlaves() {
+      return Table.Where(x => x.DateExpired != null && x.ResourceType == "Slave");
+    }
+
+    public IQueryable<DimClient> GetAllExpiredSlaveGroups() {
+      return Table.Where(x => x.DateExpired != null && x.ResourceType == "GROUP");
     }
 
@@ -44,5 +60,5 @@
       string paramIds = string.Join(",", ids.Select(x => string.Format("'{0}'", x)));
       if (!string.IsNullOrWhiteSpace(paramIds)) {
-        string query = string.Format(UpdateExpirationTimeQuery, "{0}", paramIds);
+        string query = string.Format(UpdateDateExpiredQuery, "{0}", paramIds);
         return DataContext.ExecuteCommand(query, time);
       }
@@ -59,7 +75,7 @@
 
     #region String queries
-    private const string UpdateExpirationTimeQuery =
+    private const string UpdateDateExpiredQuery =
       @"UPDATE [statistics].[DimClient] 
-           SET ExpirationTime = {0} 
+           SET DateExpired = {0} 
          WHERE Id IN ({1});";
     #endregion
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimProjectDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimProjectDao.cs	(revision 16141)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/DimProjectDao.cs	(revision 16141)
@@ -0,0 +1,72 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class DimProjectDao : GenericDao<Guid, DimProject> {
+    public DimProjectDao(DataContext dataContext) : base(dataContext) { }
+
+    public override DimProject GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public IEnumerable<DimProject> GetByProjectId(Guid projectId) {
+      return GetByProjectIdQuery(DataContext, projectId);
+    }
+
+    public Guid GetLastValidIdByProjectId(Guid projectId) {
+      return GetLastValidIdByProjectIdQuery(DataContext, projectId);
+    }
+
+    public IEnumerable<DimProject> GetAllOnlineProjects() {
+      return GetAllOnlineProjectsQuery(DataContext);
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, DimProject> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from dimProject in db.GetTable<DimProject>()
+         where dimProject.Id == id
+         select dimProject).SingleOrDefault());
+    private static readonly Func<DataContext, Guid, IEnumerable<DimProject>> GetByProjectIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid projectId) =>
+        (from dimProject in db.GetTable<DimProject>()
+         where dimProject.ProjectId == projectId
+         select dimProject));
+    private static readonly Func<DataContext, Guid, Guid> GetLastValidIdByProjectIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid projectId) =>
+        (from dimProject in db.GetTable<DimProject>()
+         where dimProject.ProjectId == projectId
+         && dimProject.DateExpired == null
+         orderby dimProject.DateCreated descending
+         select dimProject.Id).SingleOrDefault());
+    private static readonly Func<DataContext, IEnumerable<DimProject>> GetAllOnlineProjectsQuery =
+      CompiledQuery.Compile((DataContext db) =>
+        (from dimProject in db.GetTable<DimProject>()
+         where dimProject.DateExpired == null
+         select dimProject));
+    #endregion
+  }
+}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactProjectInfoDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactProjectInfoDao.cs	(revision 16141)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactProjectInfoDao.cs	(revision 16141)
@@ -0,0 +1,46 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos.HiveStatistics {
+  public class FactProjectInfoDao : GenericDao<Guid, FactProjectInfo> {
+    public FactProjectInfoDao(DataContext dataContext) : base(dataContext) { }
+
+    public override FactProjectInfo GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    private Table<DimTime> DimTimeTable {
+      get { return DataContext.GetTable<DimTime>(); }
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, FactProjectInfo> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid id) =>
+        (from factProjectInfo in db.GetTable<FactProjectInfo>()
+         where factProjectInfo.ProjectId== id
+         select factProjectInfo).SingleOrDefault());
+    #endregion
+  }
+}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs	(revision 16140)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/HiveStatistics/FactTaskDao.cs	(revision 16141)
@@ -66,5 +66,5 @@
       return from factTask in Table
              join client in DimClientTable on factTask.LastClientId equals client.Id
-             where client.ResourceGroupId == id
+             where client.ParentResourceId == id
              select factTask;
     }
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs	(revision 16140)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/JobDao.cs	(revision 16141)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections.Generic;
 using System.Data.Linq;
 using System.Linq;
@@ -32,4 +33,34 @@
     }
 
+    public void DeleteByState(JobState state) {
+      DataContext.ExecuteCommand(DeleteByStateQueryString, Enum.GetName(typeof(JobState), state));
+    }
+
+    public IEnumerable<Job> GetByProjectId(Guid id) {
+      return GetByProjectIdQuery(DataContext, id);
+    }
+
+    public IEnumerable<Job> GetByProjectIds(IEnumerable<Guid> projectIds) {
+      string paramProjectIds = string.Join(",", projectIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if(!string.IsNullOrWhiteSpace(paramProjectIds)) {
+        string queryString = string.Format(GetByProjectIdsQueryString, paramProjectIds);
+        return DataContext.ExecuteQuery<Job>(queryString);
+      }
+      return Enumerable.Empty<Job>();
+    }
+
+    public IEnumerable<Job> GetByState(JobState state) {
+      return GetByStateQuery(DataContext, state);
+    }
+
+    public IEnumerable<Guid> GetJobIdsByState(JobState state) {
+      return GetJobIdsByStateQuery(DataContext, state);
+    }
+
+    public IEnumerable<Job> GetJobsReadyForDeletion() {
+      return GetJobsReadyForDeletionQuery(DataContext);
+    }
+
+
     #region Compiled queries
     private static readonly Func<DataContext, Guid, Job> GetByIdQuery =
@@ -38,4 +69,50 @@
          where job.JobId == jobId
          select job).SingleOrDefault());
+    private static readonly Func<DataContext, Guid, IEnumerable<Job>> GetByProjectIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid projectId) =>
+        (from job in db.GetTable<Job>()
+         where job.ProjectId == projectId
+         select job));
+    private static readonly Func<DataContext, JobState, IEnumerable<Job>> GetByStateQuery =
+      CompiledQuery.Compile((DataContext db, JobState jobState) =>
+        (from job in db.GetTable<Job>()
+         where job.State == jobState
+         select job));
+    private static readonly Func<DataContext, JobState, IEnumerable<Guid>> GetJobIdsByStateQuery =
+      CompiledQuery.Compile((DataContext db, JobState jobState) =>
+        (from job in db.GetTable<Job>()
+         where job.State == jobState
+         select job.JobId));
+    private static readonly Func<DataContext, IEnumerable<Job>> GetJobsReadyForDeletionQuery =
+      CompiledQuery.Compile((DataContext db) =>
+        (from job in db.GetTable<Job>()
+         where job.State == JobState.StatisticsPending
+         && (from task in db.GetTable<Task>()
+             where task.JobId == job.JobId
+             select task.State == TaskState.Finished
+              || task.State == TaskState.Aborted
+              || task.State == TaskState.Failed).All(x => x)
+         select job));
+    #endregion
+
+    #region String queries
+    private const string DeleteByStateQueryString = @"
+      DELETE FROM [Job]
+      WHERE JobState = {0}
+    ";
+    private const string GetStatisticsPendingJobs = @"
+      SELECT DISTINCT j.*
+      FROM [Job] j
+      WHERE j.JobState = 'StatisticsPending'
+      AND 'Calculating' NOT IN (
+        SELECT t.TaskState 
+        FROM [Task] t 
+        WHERE t.JobId = j.JobId)
+    ";
+    private const string GetByProjectIdsQueryString = @"
+      SELECT DISTINCT j.*
+      FROM [Job] j
+      WHERE j.ProjectId IN ({0})
+    ";
     #endregion
   }
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ProjectDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ProjectDao.cs	(revision 16141)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ProjectDao.cs	(revision 16141)
@@ -0,0 +1,293 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class ProjectDao : GenericDao<Guid, Project> {
+    public ProjectDao(DataContext dataContext) : base(dataContext) { }
+
+    public class ProjectStats {
+      public Guid ProjectId { get; set; }
+      public int Cores { get; set; }
+      public int Memory { get; set; }
+    }
+
+    public override Project GetById(Guid id) {
+      return GetByIdQuery(DataContext, id);
+    }
+
+    public void DeleteByIds(IEnumerable<Guid> ids) {
+      string paramProjectIds = string.Join(",", ids.ToList().Select(x => string.Format("'{0}'", x)));
+      if(!string.IsNullOrWhiteSpace(paramProjectIds)) {
+        string queryString = string.Format(DeleteByIdsQueryString, paramProjectIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public IEnumerable<Project> GetUsageGrantedProjectsForUser(IEnumerable<Guid> userAndGroupIds) {
+      string paramUserAndGroupIds = string.Join(",", userAndGroupIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramUserAndGroupIds)) {
+        string queryString = string.Format(GetUsageGrantedProjectsForUserQueryString, paramUserAndGroupIds);
+        return DataContext.ExecuteQuery<Project>(queryString);
+      }
+      return Enumerable.Empty<Project>();
+    }
+
+    public IEnumerable<Project> GetAdministrationGrantedProjectsForUser(Guid userId) {
+      return DataContext.ExecuteQuery<Project>(GetAdministrationGrantedProjectsForUserQueryString, userId);
+    }
+
+    public IEnumerable<Project> GetChildProjectsById(Guid id) {
+      return DataContext.ExecuteQuery<Project>(GetChildProjectsByIdQuery, id);
+    }
+
+    public IEnumerable<Guid> GetChildProjectIdsById(Guid id) {
+      return DataContext.ExecuteQuery<Guid>(GetChildProjectIdsByIdQuery, id);
+    }
+
+    public IEnumerable<Project> GetParentProjectsById(Guid id) {
+      return DataContext.ExecuteQuery<Project>(GetParentProjectsByIdQuery, id);
+    }
+
+    public IEnumerable<Guid> GetParentProjectIdsById(Guid id) {
+      return DataContext.ExecuteQuery<Guid>(GetParentProjectIdsByIdQuery, id);
+    }
+
+    public IEnumerable<Project> GetCurrentAndParentProjectsById(Guid id) {
+      return DataContext.ExecuteQuery<Project>(GetCurrentAndParentProjectsByIdQuery, id);
+    }
+
+    public IEnumerable<Guid> GetCurrentAndParentProjectIdsById(Guid id) {
+      return DataContext.ExecuteQuery<Guid>(GetCurrentAndParentProjectIdsByIdQuery, id);
+    }
+
+    public IEnumerable<ProjectStats> GetUsageStatsPerProject() {
+      return DataContext.ExecuteQuery<ProjectStats>(GetUsageStatsPerProjectQueryString).ToList();
+    }
+
+    public IEnumerable<ProjectStats> GetAvailabilityStatsPerProject() {
+      return DataContext.ExecuteQuery<ProjectStats>(GetAvailabilityStatsPerProjectQueryString).ToList();
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, Project> GetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid projectId) =>
+        (from project in db.GetTable<Project>()
+         where project.ProjectId == projectId
+         select project).SingleOrDefault());
+    #endregion
+
+    #region String queries
+    private const string DeleteByIdsQueryString = @"
+      DELETE FROM [Project]
+      WHERE ProjectId IN ({0})
+    ";
+
+    private const string GetUsageStatsPerProjectQueryString = @"
+      SELECT j.ProjectId, SUM(t.CoresNeeded) AS Cores, SUM(t.MemoryNeeded) AS Memory
+      FROM [Task] t, [Job] j
+      WHERE t.TaskState = 'Calculating'
+      AND t.JobId = j.JobId
+      GROUP BY j.ProjectId
+    ";
+
+    private const string GetAvailabilityStatsPerProjectQueryString = @"
+      WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId
+      )
+      SELECT apr.ProjectId, SUM(res.Cores) AS Cores, SUM(res.Memory) AS Memory
+      FROM rtree, [AssignedProjectResource] apr, [Resource] res
+      WHERE rtree.ResourceId = res.ResourceId
+      AND res.ResourceType = 'Slave'
+      AND (res.SlaveState = 'Idle' OR SlaveState = 'Calculating')
+      AND rtree.ParentResourceId = apr.ResourceId
+      GROUP BY apr.ProjectId
+      UNION
+      SELECT apr.ProjectId, SUM(res.Cores) AS Cores, SUM(res.Memory) AS Memory
+      FROM [AssignedProjectResource] apr, [Resource] res
+      WHERE apr.ResourceId = res.ResourceId
+      AND res.ResourceType = 'Slave'
+      AND (res.SlaveState = 'Idle' OR SlaveState = 'Calculating')
+      GROUP BY apr.ProjectId
+    ";
+
+    private const string GetUsageGrantedProjectsForUserQueryString = @"
+      SELECT DISTINCT p.*
+      FROM [Project] p, [ProjectPermission] pp
+      WHERE p.ProjectId = pp.ProjectId
+      AND pp.GrantedUserId IN ({0})
+    ";
+
+    private const string GetAdministrationGrantedProjectsForUserQueryString = @"
+      WITH ptree AS
+      (
+	      SELECT ProjectId, ParentProjectId
+	      FROM [Project]
+	      UNION ALL
+	      SELECT pt.ProjectId, p.ParentProjectId
+	      FROM [Project] p
+	      JOIN ptree pt ON pt.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pt.ParentProjectId <> pt.ProjectId
+      )
+      SELECT DISTINCT parent.*
+      FROM [Project] parent
+      WHERE parent.OwnerUserId = {0}
+      UNION
+      SELECT DISTINCT child.* 
+      FROM ptree, [Project] parent, [Project] child
+      WHERE ptree.ParentProjectId = parent.ProjectId
+      AND ptree.ProjectId = child.ProjectId
+      AND parent.OwnerUserId = {0}
+    ";
+
+    private const string GetChildProjectsByIdQuery = @"
+    	WITH ptree AS
+      (
+	      SELECT ProjectId, ParentProjectId
+	      FROM [Project]
+	      UNION ALL
+	      SELECT pt.ProjectId, p.ParentProjectId
+	      FROM [Project] p
+	      JOIN ptree pt ON pt.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pt.ParentProjectId <> pt.ProjectId
+      )
+      SELECT DISTINCT pro.*
+      FROM ptree, [Project] pro
+      WHERE ptree.ParentProjectId = {0}
+	    AND ptree.ProjectId = pro.ProjectId
+    ";
+    private const string GetChildProjectIdsByIdQuery = @"
+      WITH ptree AS
+      (
+	      SELECT ProjectId, ParentProjectId
+	      FROM [Project]
+	      UNION ALL
+	      SELECT pt.ProjectId, r.ParentProjectId
+	      FROM [Project] r
+	      JOIN ptree pt ON pt.ParentProjectId = r.ProjectId AND r.ParentProjectId <> r.ProjectId AND pt.ParentProjectId <> pt.ProjectId
+      )
+      SELECT DISTINCT ptree.ProjectId
+      FROM ptree
+      WHERE ptree.ParentProjectId = {0}
+    ";
+    private const string GetParentProjectsByIdQuery = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId
+        FROM [Project]
+	      UNION ALL
+	      SELECT pb.ProjectId, p.ParentProjectId
+	      FROM [Project] p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pb.ParentProjectId <> pb.ProjectId
+      )
+      SELECT DISTINCT pro.*
+      FROM pbranch, [Project] pro
+      WHERE pbranch.ProjectId = {0}
+      AND pbranch.ParentProjectId = pro.ProjectId
+    ";
+    private const string GetParentProjectIdsByIdQuery = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId
+        FROM [Project]
+	      UNION ALL
+	      SELECT pb.ProjectId, p.ParentProjectId
+	      FROM [Project] p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pb.ParentProjectId <> pb.ProjectId
+      )
+      SELECT DISTINCT pbranch.ParentProjectId
+      FROM pbranch
+      WHERE pbranch.ProjectId = {0}
+    ";
+    private const string GetCurrentAndParentProjectsByIdQuery = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId
+	      FROM Project
+	      WHERE ProjectId = {0}
+	      UNION ALL
+	      SELECT p.ProjectId, p.ParentProjectId
+	      FROM Project p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId
+      )
+      SELECT DISTINCT pro.*
+      FROM pbranch, Project pro
+      WHERE pbranch.ProjectId = pro.ProjectId
+    ";
+    private const string GetCurrentAndParentProjectIdsByIdQuery = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId
+	      FROM Project
+	      WHERE ProjectId = {0}
+	      UNION ALL
+	      SELECT p.ProjectId, p.ParentProjectId
+	      FROM Project p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId
+      )
+      SELECT DISTINCT pbranch.ProjectId
+      FROM pbranch
+    ";
+    private const string GetNearestOwnedParentProjectByIdQuery = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId, CAST(ProjectId AS NVARCHAR(MAX)) Path, 1 Distance
+	      FROM [Project]
+	      WHERE ProjectId = {0}
+	      UNION ALL
+	      SELECT pb.ProjectId, p.ParentProjectId, pb.Path + N', ' + CAST(pb.ProjectId AS NVARCHAR(MAX)), pb.Distance + 1
+	      FROM [Project] p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pb.ParentProjectId <> pb.ProjectId
+      )
+      SELECT TOP(1) pro.*
+      FROM pbranch, [Project] pro
+      WHERE pbranch.ParentProjectId = pro.ProjectId
+      AND pro.OwnerUserId = {1}
+      ORDER BY pbranch.Distance
+    ";
+    private const string GetFarestOwnedParentProjectIdByIdQuery = @"
+      WITH pbranch AS
+      (
+	      SELECT ProjectId, ParentProjectId, CAST(ProjectId AS NVARCHAR(MAX)) Path, 1 Distance
+	      FROM [Project]
+	      WHERE ProjectId = {0}
+	      UNION ALL
+	      SELECT pb.ProjectId, p.ParentProjectId, pb.Path + N', ' + CAST(pb.ProjectId AS NVARCHAR(MAX)), pb.Distance + 1
+	      FROM [Project] p
+	      JOIN pbranch pb ON pb.ParentProjectId = p.ProjectId AND p.ParentProjectId <> p.ProjectId AND pb.ParentProjectId <> pb.ProjectId
+      )
+      SELECT TOP(1) pro.*
+      FROM pbranch, [Project] pro
+      WHERE pbranch.ParentProjectId = pro.ProjectId
+      AND pro.OwnerUserId = {1}
+      ORDER BY pbranch.Distance DESC
+    ";
+    #endregion
+  }
+}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ProjectPermissionDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ProjectPermissionDao.cs	(revision 16141)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ProjectPermissionDao.cs	(revision 16141)
@@ -0,0 +1,98 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Data.Linq;
+using System.Linq;
+
+namespace HeuristicLab.Services.Hive.DataAccess.Daos {
+  public class ProjectPermissionDao : GenericDao<Guid, ProjectPermission> {
+    public ProjectPermissionDao(DataContext dataContext) : base(dataContext) { }
+
+    public override ProjectPermission GetById(Guid id) {
+      throw new NotImplementedException();
+    }
+
+    public IEnumerable<ProjectPermission> GetByProjectId(Guid id) {
+      return GetByProjectIdGetByIdQuery(DataContext, id);
+    }
+
+    public bool CheckUserGrantedForProject(Guid projectId, IEnumerable<Guid> userAndGroupIds) {
+      string paramUserAndGroupIds = string.Join(",", userAndGroupIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if(!string.IsNullOrWhiteSpace(paramUserAndGroupIds)) {
+        string queryString = string.Format(CheckUserGrantedForProjectQueryString, projectId, paramUserAndGroupIds);
+        return DataContext.ExecuteQuery<int>(queryString).First() > 0;
+      }
+      return false;
+    }
+
+    public void DeleteByProjectIdAndGrantedUserIds(Guid projectId, IEnumerable<Guid> grantedUserIds) {
+      string paramIds = string.Join(",", grantedUserIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramIds)) {
+        string query = string.Format(DeleteByProjectIdAndGrantedUserIdsQueryString, projectId, paramIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    public void DeleteByProjectIdsAndGrantedUserIds(IEnumerable<Guid> projectIds, IEnumerable<Guid> grantedUserIds) {
+      string paramProjectIds = string.Join(",", projectIds.ToList().Select(x => string.Format("'{0}'", x)));
+      string paramUserIds = string.Join(",", grantedUserIds.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramProjectIds) && !string.IsNullOrWhiteSpace(paramUserIds)) {
+        string query = string.Format(DeleteByProjectIdsAndGrantedUserIdsQueryString, paramProjectIds, paramUserIds);
+        DataContext.ExecuteCommand(query);
+      }
+    }
+
+    #region Compiled queries
+    private static readonly Func<DataContext, Guid, IEnumerable<ProjectPermission>> GetByProjectIdGetByIdQuery =
+      CompiledQuery.Compile((DataContext db, Guid projectId) =>
+        from projectPermission in db.GetTable<ProjectPermission>()
+        where projectPermission.ProjectId == projectId
+        select projectPermission);
+    #endregion
+
+    #region String queries
+    private const string DeleteByProjectIdAndGrantedUserIdsQueryString = @"
+      DELETE FROM [ProjectPermission]
+      WHERE ProjectId = '{0}'
+      AND GrantedUserId IN ({1});
+    ";
+    private const string DeleteByProjectIdsAndGrantedUserIdsQueryString = @"
+      DELETE FROM [ProjectPermission]
+      WHERE ProjectId IN ({0})
+      AND GrantedUserId IN ({1});
+    ";
+    private const string CheckUserGrantedForProjectQueryString = @"
+      SELECT COUNT(pp.ProjectId)
+      FROM [ProjectPermission] pp
+      WHERE pp.ProjectId = '{0}'
+      AND pp.GrantedUserId IN ({1})
+    ";
+    private const string GetGrantedProjectsForUserQueryString = @"
+      SELECT DISTINCT p.*
+      FROM [ProjectPermission] pp, [Project] p
+      WHERE pp.GrantedUserId IN ({0})
+      AND  pp.ProjectId = p.ProjectId
+    ";
+    #endregion
+  }
+}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs	(revision 16140)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourceDao.cs	(revision 16141)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections.Generic;
 using System.Data.Linq;
 using System.Linq;
@@ -36,6 +37,47 @@
     }
 
+    public void DeleteByIds(IEnumerable<Guid> ids) {
+      string paramResourceIds = string.Join(",", ids.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string queryString = string.Format(DeleteByIdsQueryString, paramResourceIds);
+        DataContext.ExecuteCommand(queryString);
+      }
+    }
+
+    public bool CheckExistence(IEnumerable<Guid> ids) {
+      string paramResourceIds = string.Join(",", ids.ToList().Select(x => string.Format("'{0}'", x)));
+      if (!string.IsNullOrWhiteSpace(paramResourceIds)) {
+        string queryString = string.Format(CountExistenceQuery, paramResourceIds);
+        return DataContext.ExecuteQuery<int>(queryString).SingleOrDefault() == ids.Count();
+      }
+      return false;
+    }
+
     public IQueryable<Resource> GetResourcesWithValidOwner() {
       return Table.Where(x => x.OwnerUserId != null);
+    }
+
+    public IEnumerable<Resource> GetChildResourcesById(Guid id) {
+      return DataContext.ExecuteQuery<Resource>(GetChildResourcesByIdQuery, id);
+    }
+
+    public IEnumerable<Guid> GetChildResourceIdsById(Guid id) {
+      return DataContext.ExecuteQuery<Guid>(GetChildResourceIdsByIdQuery, id);
+    }
+
+    public IEnumerable<Resource> GetParentResourcesById(Guid id) {
+      return DataContext.ExecuteQuery<Resource>(GetParentResourcesByIdQuery, id);
+    }
+
+    public IEnumerable<Guid> GetParentResourceIdsById(Guid id) {
+      return DataContext.ExecuteQuery<Guid>(GetParentResourceIdsByIdQuery, id);
+    }
+
+    public IEnumerable<Resource> GetCurrentAndParentResourcesById(Guid id) {
+      return DataContext.ExecuteQuery<Resource>(GetCurrentAndParentResourcesByIdQuery, id);
+    }
+
+    public IEnumerable<Guid> GetCurrentAndParentResourceIdsById(Guid id) {
+      return DataContext.ExecuteQuery<Guid>(GetCurrentAndParentResourceIdsByIdQuery, id);
     }
 
@@ -53,4 +95,103 @@
         select resource).FirstOrDefault());
     #endregion
+
+    #region String queries
+    private const string DeleteByIdsQueryString = @"
+      DELETE FROM [Resource]
+      WHERE ResourceId IN ({0})
+    ";
+    private const string CountExistenceQuery = @"
+      SELECT COUNT(DISTINCT r.ResourceId)
+      FROM [Resource] r
+      WHERE r.ResourceId IN ({0})
+    ";
+    private const string GetChildResourcesByIdQuery = @"
+    	WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId AND r.ParentResourceId <> r.ResourceId AND rt.ParentResourceId <> rt.ResourceId
+      )
+      SELECT DISTINCT res.*
+      FROM rtree, [Resource] res
+      WHERE rtree.ParentResourceId = {0}
+	    AND rtree.ResourceId = res.ResourceId
+    ";
+    private const string GetChildResourceIdsByIdQuery = @"
+      WITH rtree AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rt.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rtree rt ON rt.ParentResourceId = r.ResourceId AND r.ParentResourceId <> r.ResourceId AND rt.ParentResourceId <> rt.ResourceId
+      )
+      SELECT DISTINCT rtree.ResourceId
+      FROM rtree
+      WHERE rtree.ParentResourceId = {0}
+    ";
+    private const string GetParentResourcesByIdQuery = @"
+      WITH rbranch AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rb.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId AND r.ParentResourceId <> r.ResourceId AND rb.ParentResourceId <> rb.ResourceId
+      )
+      SELECT DISTINCT res.*
+      FROM rbranch, [Resource] res
+      WHERE rbranch.ResourceId = {0}
+      AND rbranch.ParentResourceId = res.ResourceId
+    ";
+    private const string GetParentResourceIdsByIdQuery = @"
+      WITH rbranch AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      UNION ALL
+	      SELECT rb.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId AND r.ParentResourceId <> r.ResourceId AND rb.ParentResourceId <> rb.ResourceId
+      )
+      SELECT DISTINCT rbranch.ParentResourceId
+      FROM rbranch
+      WHERE rbranch.ResourceId = {0}
+    ";
+    private const string GetCurrentAndParentResourcesByIdQuery = @"
+      WITH rbranch AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      WHERE ResourceId = {0}
+	      UNION ALL
+	      SELECT r.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId
+      )
+      SELECT DISTINCT res.*
+      FROM rbranch, [Resource] res
+      WHERE rbranch.ResourceId = res.ResourceId
+    ";
+    private const string GetCurrentAndParentResourceIdsByIdQuery = @"
+      WITH rbranch AS
+      (
+	      SELECT ResourceId, ParentResourceId
+	      FROM [Resource]
+	      WHERE ResourceId = {0}
+	      UNION ALL
+	      SELECT r.ResourceId, r.ParentResourceId
+	      FROM [Resource] r
+	      JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId
+      )
+      SELECT DISTINCT rbranch.ResourceId
+      FROM rbranch
+    ";
+    #endregion
   }
 }
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/ResourcePermissionDao.cs	(revision 16140)
+++ 	(revision )
@@ -1,62 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using System;
-using System.Collections.Generic;
-using System.Data.Linq;
-using System.Linq;
-
-namespace HeuristicLab.Services.Hive.DataAccess.Daos {
-  public class ResourcePermissionDao : GenericDao<Guid, ResourcePermission> {
-    public ResourcePermissionDao(DataContext dataContext) : base(dataContext) { }
-
-    public override ResourcePermission GetById(Guid id) {
-      throw new NotImplementedException();
-    }
-
-    public IEnumerable<ResourcePermission> GetByResourceId(Guid id) {
-      return GetByResourceIdGetByIdQuery(DataContext, id);
-    }
-
-    public void DeleteByResourceAndGrantedUserId(Guid resourceId, IEnumerable<Guid> grantedUserId) {
-      string paramIds = string.Join(",", grantedUserId.Select(x => string.Format("'{0}'", x)));
-      if (!string.IsNullOrWhiteSpace(paramIds)) {
-        string query = string.Format(DeleteByGrantedUserQuery, resourceId, paramIds);
-        DataContext.ExecuteCommand(query);
-      }
-    }
-
-    #region Compiled queries
-    private static readonly Func<DataContext, Guid, IEnumerable<ResourcePermission>> GetByResourceIdGetByIdQuery =
-      CompiledQuery.Compile((DataContext db, Guid resourceId) =>
-        from resourcePermission in db.GetTable<ResourcePermission>()
-        where resourcePermission.ResourceId == resourceId
-        select resourcePermission);
-    #endregion
-
-    #region String queries
-    private const string DeleteByGrantedUserQuery =
-      @"DELETE FROM [ResourcePermission]
-         WHERE ResourceId = '{0}'
-           AND GrantedUserId IN ({1});";
-    #endregion
-  }
-}
Index: branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs
===================================================================
--- branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 16140)
+++ branches/2817-BinPackingSpeedup/HeuristicLab.Services.Hive.DataAccess/3.3/Daos/TaskDao.cs	(revision 16141)
@@ -27,8 +27,4 @@
 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) { }
 
@@ -54,5 +50,9 @@
       //Because there is at the moment no case where this makes sense (there don't exist parent tasks which need to be calculated), 
       //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();
+      return DataContext.ExecuteQuery<TaskPriorityInfo>(GetWaitingTasksQueryString, 
+        slave.ResourceId, 
+        Enum.GetName(typeof(TaskState), TaskState.Waiting), 
+        slave.FreeCores, 
+        slave.FreeMemory).ToList();
     }
 
@@ -62,22 +62,19 @@
     /// <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>
+    /// <param name="finished">if true, all parent tasks 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;
+    var query = from t in Table
+                where t.State == TaskState.Waiting
+                    && t.IsParentTask
+                    && t.Job.AssignedJobResources.All(x => resourceIds.ToList().Contains(x.ResourceId))
+                    && t.FinishWhenChildJobsFinished == finished
+                    && t.ChildJobs.Any()
+                    && t.ChildJobs.All(x =>
+                      x.State == TaskState.Finished
+                      || x.State == TaskState.Aborted
+                      || x.State == TaskState.Failed)
+                  orderby t.Priority descending
+                  select t;
       return count == 0 ? query.ToArray() : query.Take(count).ToArray();
     }
@@ -96,6 +93,14 @@
 
     #region String queries
+    private const string GetCalculatingChildTasksByProjectId = @"
+      SELECT t.* FROM [Task] t, [Job] j
+        WHERE t.IsParentTask = 0
+        AND t.TaskState = 'Calculating'
+        AND t.JobId = j.JobId
+        AND j.ProjectId = {0}
+        ORDER BY j.ProjectId
+    ";
     private const string GetWaitingTasksQueryString = @"
-      WITH pr AS (
+      WITH rbranch AS (
         SELECT ResourceId, ParentResourceId
         FROM [Resource]
@@ -103,13 +108,17 @@
         UNION ALL
         SELECT r.ResourceId, r.ParentResourceId
-        FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId
+        FROM [Resource] r
+        JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId
       )
       SELECT DISTINCT t.TaskId, t.JobId, t.Priority
-      FROM pr JOIN AssignedResources ar ON ar.ResourceId = pr.ResourceId
-          JOIN Task t ON t.TaskId = ar.TaskId
+      FROM [Task] t, [Job] j, [AssignedJobResource] ajr, rbranch
       WHERE NOT (t.IsParentTask = 1 AND t.FinishWhenChildJobsFinished = 1)
-          AND t.TaskState = {1}
-          AND t.CoresNeeded <= {2}
-          AND t.MemoryNeeded <= {3}
+      AND t.TaskState = {1}
+      AND t.CoresNeeded <= {2}
+      AND t.MemoryNeeded <= {3}
+      AND t.JobId = j.JobId
+      AND j.JobState = 'Online'
+      AND j.JobId = ajr.JobId
+      AND ajr.ResourceId = rbranch.ResourceId
     ";
 
