1  #region License Information


2  /* HeuristicLab


3  * Copyright (C) 20022016 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 


22  using System;


23  using System.Collections.Generic;


24  using System.Data.Linq;


25  using System.Linq;


26 


27  namespace HeuristicLab.Services.Hive.DataAccess.Daos {


28  public class TaskDao : GenericDao<Guid, Task> {


29  private Table<AssignedTaskResource> AssignedTaskResourceTable {


30  get { return DataContext.GetTable<AssignedTaskResource>(); }


31  }


32 


33  public TaskDao(DataContext dataContext) : base(dataContext) { }


34 


35  public override Task GetById(Guid id) {


36  return GetByIdQuery(DataContext, id);


37  }


38 


39  public IQueryable<Task> GetAllChildTasks() {


40  return Table.Where(x => !x.IsParentTask);


41  }


42 


43  public IQueryable<Task> GetByJobId(Guid id) {


44  return Table.Where(x => x.JobId == id);


45  }


46  public class TaskPriorityInfo {


47  public Guid JobId { get; set; }


48  public Guid TaskId { get; set; }


49  public int Priority { get; set; }


50  }


51 


52  public IEnumerable<TaskPriorityInfo> GetWaitingTasks(Slave slave) {


53  //Originally we checked here if there are parent tasks which should be calculated (with GetParentTasks(resourceIds, count, false);).


54  //Because there is at the moment no case where this makes sense (there don't exist parent tasks which need to be calculated),


55  //we skip this step because it's wasted runtime


56  return DataContext.ExecuteQuery<TaskPriorityInfo>(GetWaitingTasksQueryString,


57  slave.ResourceId,


58  Enum.GetName(typeof(TaskState), TaskState.Waiting),


59  slave.FreeCores,


60  slave.FreeMemory).ToList();


61  }


62 


63  /// <summary>


64  /// returns all parent tasks which are waiting for their child tasks to finish


65  /// </summary>


66  /// <param name="resourceIds">list of resourceids which for which the task should be valid</param>


67  /// <param name="count">maximum number of task to return</param>


68  /// <param name="finished">if true, all parent task which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned</param>


69  /// <returns></returns>


70  public IEnumerable<Task> GetParentTasks_Old(IEnumerable<Guid> resourceIds, int count, bool finished) {


71  var query = from ar in AssignedTaskResourceTable


72  where resourceIds.Contains(ar.ResourceId)


73  && ar.Task.State == TaskState.Waiting


74  && ar.Task.IsParentTask


75  && (finished ? ar.Task.FinishWhenChildJobsFinished : !ar.Task.FinishWhenChildJobsFinished)


76  && (from child in Table


77  where child.ParentTaskId == ar.Task.TaskId


78  select child.State == TaskState.Finished


79   child.State == TaskState.Aborted


80   child.State == TaskState.Failed).All(x => x)


81  && (from child in Table // avoid returning WaitForChildTasks task where no childtask exist (yet)


82  where child.ParentTaskId == ar.Task.TaskId


83  select child).Any()


84  orderby ar.Task.Priority descending


85  select ar.Task;


86  return count == 0 ? query.ToArray() : query.Take(count).ToArray();


87  }


88 


89  /// <summary>


90  /// returns all parent tasks which are waiting for their child tasks to finish


91  /// </summary>


92  /// <param name="resourceIds">list of resourceids which for which the task should be valid</param>


93  /// <param name="count">maximum number of task to return</param>


94  /// <param name="finished">if true, all parent tasks which have FinishWhenChildJobsFinished=true are returned, otherwise only FinishWhenChildJobsFinished=false are returned</param>


95  /// <returns></returns>


96  public IEnumerable<Task> GetParentTasks(IEnumerable<Guid> resourceIds, int count, bool finished) {


97  var query = from t in Table


98  where t.State == TaskState.Waiting


99  && t.IsParentTask


100  && !t.Job.AssignedJobResources.Select(x => x.ResourceId).Except(resourceIds).Any()


101  && t.FinishWhenChildJobsFinished == finished


102  && t.ChildJobs.Any()


103  && t.ChildJobs.All(x =>


104  x.State == TaskState.Finished


105   x.State == TaskState.Aborted


106   x.State == TaskState.Failed)


107  orderby t.Priority descending


108  select t;


109  return count == 0 ? query.ToArray() : query.Take(count).ToArray();


110  }


111 


112  public void UpdateExecutionTime(Guid taskId, double executionTime) {


113  DataContext.ExecuteCommand(UpdateExecutionTimeQuery, executionTime, DateTime.Now, taskId);


114  }


115 


116  #region Compiled queries


117  private static readonly Func<DataContext, Guid, Task> GetByIdQuery =


118  CompiledQuery.Compile((DataContext db, Guid taskId) =>


119  (from task in db.GetTable<Task>()


120  where task.TaskId == taskId


121  select task).SingleOrDefault());


122  #endregion


123 


124  #region String queries


125  private const string GetParentTasksQueryString = @"


126  SELECT t.* FROM [Task] t, [Job] j, [AssignedJobResource] ajr


127  WHERE t.IsParentTask = 1


128  AND t.TaskState = 'Waiting'


129  AND t.JobId = j.JobId


130  AND j.JobId = ajr.JobId


131  AND t.FinishWhenChildJobsFinished = 1


132  ... TODO (not necessary)


133  ";


134  private const string GetWaitingTasksQueryString = @"


135  WITH rbranch AS (


136  SELECT ResourceId, ParentResourceId


137  FROM [Resource]


138  WHERE ResourceId = {0}


139  UNION ALL


140  SELECT r.ResourceId, r.ParentResourceId


141  FROM [Resource] r


142  JOIN rbranch rb ON rb.ParentResourceId = r.ResourceId


143  )


144  SELECT DISTINCT t.TaskId, t.JobId, t.Priority


145  FROM [Task] t, [Job] j, [AssignedJobResource] ajr, rbranch


146  WHERE NOT (t.IsParentTask = 1 AND t.FinishWhenChildJobsFinished = 1)


147  AND t.TaskState = {1}


148  AND t.CoresNeeded <= {2}


149  AND t.MemoryNeeded <= {3}


150  AND t.JobId = j.JobId


151  AND j.JobState = 'Online'


152  AND j.JobId = ajr.JobId


153  AND ajr.ResourceId = rbranch.ResourceId


154  ";


155  private const string GetWaitingTasksQueryStringOld = @"


156  WITH pr AS (


157  SELECT ResourceId, ParentResourceId


158  FROM [Resource]


159  WHERE ResourceId = {0}


160  UNION ALL


161  SELECT r.ResourceId, r.ParentResourceId


162  FROM [Resource] r JOIN pr ON r.ResourceId = pr.ParentResourceId


163  )


164  SELECT DISTINCT t.TaskId, t.JobId, t.Priority


165  FROM pr JOIN AssignedTaskResource ar ON ar.ResourceId = pr.ResourceId


166  JOIN Task t ON t.TaskId = ar.TaskId


167  WHERE NOT (t.IsParentTask = 1 AND t.FinishWhenChildJobsFinished = 1)


168  AND t.TaskState = {1}


169  AND t.CoresNeeded <= {2}


170  AND t.MemoryNeeded <= {3}


171  ";


172 


173  private const string UpdateExecutionTimeQuery = @"


174  UPDATE [Task]


175  SET ExecutionTimeMs = {0},


176  LastHeartbeat = {1}


177  WHERE TaskId = {2}


178  ";


179  #endregion


180  }


181  } 
