#region License Information /* HeuristicLab * Copyright (C) 2002-2016 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 . */ #endregion using System; using System.Collections.Generic; using System.Data.Linq; using System.Linq; namespace HeuristicLab.Services.Hive.DataAccess.Daos { public class TaskDao : GenericDao { private Table AssignedTaskResourceTable { get { return DataContext.GetTable(); } } public TaskDao(DataContext dataContext) : base(dataContext) { } public override Task GetById(Guid id) { return GetByIdQuery(DataContext, id); } public IQueryable GetAllChildTasks() { return Table.Where(x => !x.IsParentTask); } public IQueryable GetByJobId(Guid id) { return Table.Where(x => x.JobId == id); } public class TaskPriorityInfo { public Guid JobId { get; set; } public Guid TaskId { get; set; } public int Priority { get; set; } } public IEnumerable GetWaitingTasks(Slave slave) { //Originally we checked here if there are parent tasks which should be calculated (with GetParentTasks(resourceIds, count, false);). //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(GetWaitingTasksQueryString, slave.ResourceId, Enum.GetName(typeof(TaskState), TaskState.Waiting), slave.FreeCores, slave.FreeMemory).ToList(); } /// /// returns all parent tasks which are waiting for their child tasks to finish /// /// list of resourceids which for which the task should be valid /// maximum number of task to return /// if true, all parent task which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned /// public IEnumerable GetParentTasks_Old(IEnumerable resourceIds, int count, bool finished) { var query = from ar in AssignedTaskResourceTable 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(); } /// /// returns all parent tasks which are waiting for their child tasks to finish /// /// list of resourceids which for which the task should be valid /// maximum number of task to return /// if true, all parent tasks which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned /// public IEnumerable GetParentTasks(IEnumerable resourceIds, int count, bool finished) { var query = from t in Table where t.State == TaskState.Waiting && t.IsParentTask && !t.Job.AssignedJobResources.Select(x => x.ResourceId).Except(resourceIds).Any() && 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(); } public void UpdateExecutionTime(Guid taskId, double executionTime) { DataContext.ExecuteCommand(UpdateExecutionTimeQuery, executionTime, DateTime.Now, taskId); } #region Compiled queries private static readonly Func GetByIdQuery = CompiledQuery.Compile((DataContext db, Guid taskId) => (from task in db.GetTable() where task.TaskId == taskId select task).SingleOrDefault()); #endregion #region String queries private const string GetParentTasksQueryString = @" SELECT t.* FROM [Task] t, [Job] j, [AssignedJobResource] ajr WHERE t.IsParentTask = 1 AND t.TaskState = 'Waiting' AND t.JobId = j.JobId AND j.JobId = ajr.JobId AND t.FinishWhenChildJobsFinished = 1 ... TODO (not necessary) "; private const string GetWaitingTasksQueryString = @" 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 t.TaskId, t.JobId, t.Priority 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.JobId = j.JobId AND j.JobState = 'Online' AND j.JobId = ajr.JobId AND ajr.ResourceId = rbranch.ResourceId "; private const string GetWaitingTasksQueryStringOld = @" WITH pr AS ( SELECT ResourceId, ParentResourceId FROM [Resource] WHERE ResourceId = {0} UNION ALL SELECT r.ResourceId, r.ParentResourceId FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId ) SELECT DISTINCT t.TaskId, t.JobId, t.Priority FROM pr JOIN AssignedTaskResource ar ON ar.ResourceId = pr.ResourceId JOIN Task t ON t.TaskId = ar.TaskId WHERE NOT (t.IsParentTask = 1 AND t.FinishWhenChildJobsFinished = 1) AND t.TaskState = {1} AND t.CoresNeeded <= {2} AND t.MemoryNeeded <= {3} "; private const string UpdateExecutionTimeQuery = @" UPDATE [Task] SET ExecutionTimeMs = {0}, LastHeartbeat = {1} WHERE TaskId = {2} "; #endregion } }