All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.edu.iu.dsc.tws.tsched.builder.TaskSchedulePlanBuilder Maven / Gradle / Ivy

Go to download

Twister2 Big Data Hosting Environment: A composable framework for high-performance data analytics

The newest version!
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
package edu.iu.dsc.tws.tsched.builder;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
import java.util.logging.Logger;

import com.google.common.annotations.VisibleForTesting;

import edu.iu.dsc.tws.api.compute.exceptions.TaskSchedulerException;
import edu.iu.dsc.tws.api.compute.schedule.elements.Resource;
import edu.iu.dsc.tws.api.compute.schedule.elements.TaskInstanceId;
import edu.iu.dsc.tws.api.compute.schedule.elements.TaskInstancePlan;
import edu.iu.dsc.tws.api.compute.schedule.elements.TaskSchedulePlan;
import edu.iu.dsc.tws.api.compute.schedule.elements.WorkerSchedulePlan;
import edu.iu.dsc.tws.tsched.utils.TaskScheduleUtils;

/**
 * This class is mainly responsible for building the task schedule plan.
 */
public class TaskSchedulePlanBuilder {

  private static final Logger LOG = Logger.getLogger(TaskSchedulePlanBuilder.class.getName());

  private TaskSchedulePlan previousTaskSchedulePlan;

  private Resource instanceDefaultResourceValue;
  private Resource containerMaximumResourceValue;

  private Map taskRamMap;
  private Map taskCpuMap;
  private Map taskDiskMap;

  private Map containers;
  private TreeSet taskIds;
  private HashMap> taskIndexes;

  private int requestedContainerPadding;
  private int numberOfContainers;
  private int id;

  public TaskSchedulePlanBuilder(int scheduleId, TaskSchedulePlan previousTaskSchedulePlan) {
    this.id = scheduleId;
    this.previousTaskSchedulePlan = previousTaskSchedulePlan;
    this.numberOfContainers = 0;
    this.requestedContainerPadding = 0;
    this.taskRamMap = new HashMap<>();
  }

  public Map getContainers() {
    return containers;
  }

  public void setContainers(Map containers) {
    this.containers = containers;
  }

  public TaskSchedulePlanBuilder setTaskRamMap(Map taskramMap) {
    this.taskRamMap = taskramMap;
    return this;
  }

  public TaskSchedulePlanBuilder setTaskDiskMap(Map taskdiskMap) {
    this.taskDiskMap = taskdiskMap;
    return this;
  }

  public TaskSchedulePlanBuilder setTaskCpuMap(Map taskcpuMap) {
    this.taskCpuMap = taskcpuMap;
    return this;
  }

  public int getJobId() {
    return id;
  }

  public void setJobId(int jobId) {
    this.id = jobId;
  }

  public TaskSchedulePlanBuilder setInstanceDefaultResourceValue(Resource defaultResourcevalue) {
    this.instanceDefaultResourceValue = defaultResourcevalue;
    return this;
  }

  public TaskSchedulePlanBuilder setContainerMaximumResourceValue(
      Resource containerMaxResourceValue) {
    this.containerMaximumResourceValue = containerMaxResourceValue;
    return this;
  }

  public TaskSchedulePlanBuilder setRequestedContainerPadding(
      int reqContainerPadding) {
    this.requestedContainerPadding = reqContainerPadding;
    return this;
  }

  public TaskSchedulePlanBuilder updateNumContainers(int numOfContainers) {
    this.numberOfContainers = numOfContainers;
    return this;
  }

  /**
   * It add the instance plan to the container and update the task indexes and task ids indexes.
   */
  private static void addToContainer(Container container,
                                     TaskInstancePlan taskInstancePlan,
                                     Map> taskIndexes,
                                     Set taskIds)
      throws TaskSchedulerException {
    container.add(taskInstancePlan);
    String taskName = taskInstancePlan.getTaskName();
    if (taskIndexes.get(taskName) == null) {
      taskIndexes.put(taskName, new TreeSet<>());
    }
    taskIndexes.get(taskName).add(taskInstancePlan.getTaskIndex());
    taskIds.add(taskInstancePlan.getTaskId());
  }

  public TaskSchedulePlanBuilder addInstance(Integer containerId, String taskName) throws
      TaskSchedulerException {

    initContainer(containerId);
    int taskId = taskIds.isEmpty() ? 1 : taskIds.last() + 1;
    int taskIndex = taskIndexes.get(taskName) != null
        ? taskIndexes.get(taskName).last() + 1 : 0;

    TaskInstanceId taskInstanceId = new TaskInstanceId(taskName, taskId, taskIndex);
    Resource resource = TaskScheduleUtils.getResourceRequirement(
        taskName, this.taskRamMap, this.instanceDefaultResourceValue,
        this.containerMaximumResourceValue, this.requestedContainerPadding);

    try {
      addToContainer(containers.get(containerId),
          new TaskInstancePlan(taskInstanceId, resource), taskIndexes, taskIds);
    } catch (TaskSchedulerException e) {
      throw new TaskSchedulerException(String.format(
          "Insufficient container resources to add instance %s with resources %s to container %d.",
          taskInstanceId, resource, containerId), e);
    }
    LOG.info("Task id, index, name:" + taskId + "\t" + taskIndex + "\t" + taskName
        + "\tadded to Container:" + containers.get(containerId));
    return this;
  }

  /**
   * It will add the task instance to the container based on the container score value.
   */
  public void addInstance(Scorer scorer, String taskName) throws TaskSchedulerException {
    List> scorers = new LinkedList<>();
    scorers.add(scorer);
    addInstance(scorers, taskName);
  }

  /**
   * This method first initialize the container value then add the task instance in the sorted
   * container score values.
   */
  private int addInstance(List> scorers, String taskName)
      throws TaskSchedulerException {
    initContainers();
    for (Container container : sortContainers(scorers, this.containers.values())) {
      try {
        addInstance(container.getContainerId(), taskName);
        return container.getContainerId();
      } catch (TaskSchedulerException ignored) {
      }
    }
    throw new TaskSchedulerException(String.format(
        "Insufficient resources to add '%s' instance to any of the %d containers.",
        taskName, this.containers.size()));
  }

  @VisibleForTesting
  private static List sortContainers(List> scorers,
                                                Collection containers) {
    List sorted = new ArrayList<>(containers);
    sorted.sort(new ChainedContainerComparator<>(scorers));
    return sorted;
  }

  /**
   * This method first validates the available resource settings and invoke the build container
   * plans method to build the container based on the task instance ram, disk, and cpu map values.
   */
  public TaskSchedulePlan build() {
    assertResourceSettings();
    Set workerSchedulePlans = buildContainerPlans(
        this.containers, this.taskRamMap, this.instanceDefaultResourceValue);
    return new TaskSchedulePlan(id, workerSchedulePlans);
  }

  /**
   * This method first initialize the container map values, task index values, and task id sets.
   */
  private void initContainers() {
    assertResourceSettings();
    Map containerMap = this.containers;
    HashMap> taskindexes = this.taskIndexes;
    TreeSet taskids = this.taskIds;

    if (taskindexes == null) {
      taskindexes = new HashMap<>();
    }

    if (taskids == null) {
      taskids = new TreeSet<>();
    }

    if (containerMap == null) {
      if (this.previousTaskSchedulePlan == null) {
        containerMap = new HashMap<>();
        for (int containerId = 1; containerId <= numberOfContainers; containerId++) {
          containerMap.put(containerId, new Container(containerId,
              this.containerMaximumResourceValue, this.requestedContainerPadding));
        }
      } else {
        try {
          //containerMap = getContainers(this.previousTaskSchedulePlan);
          containerMap = getContainers(this.previousTaskSchedulePlan,
              this.requestedContainerPadding, taskindexes, taskids);
        } catch (TaskSchedulerException e) {
          throw new TaskSchedulerException(
              "Could not initialize containers using existing packing plan", e);
        }
      }
    }
    if (this.numberOfContainers > containerMap.size()) {
      List> scorers = new ArrayList<>();
      scorers.add(new ContainerIdScorer());
      List sortedContainers = sortContainers(scorers, containerMap.values());

      int nextContainerId = sortedContainers.get(sortedContainers.size() - 1).getContainerId() + 1;
      Resource capacity =
          containerMap.get(sortedContainers.get(0).getContainerId()).getResource();

      for (int i = 0; i < numberOfContainers - containerMap.size(); i++) {
        containerMap.put(nextContainerId,
            new Container(nextContainerId, capacity, this.requestedContainerPadding));
        nextContainerId++;
      }
    }
    this.taskIds = taskids;
    this.taskIndexes = taskindexes;
    this.containers = containerMap;
  }

  private void initContainer(int containerId) {
    initContainers();
    if (this.containers.get(containerId) == null) {
      this.containers.put(containerId, new Container(
          containerId, this.containerMaximumResourceValue, this.requestedContainerPadding));
    }
  }

  private void assertResourceSettings() {
    if (this.instanceDefaultResourceValue == null) {
      throw new TaskSchedulerException(
          "defaultInstanceResource must be set on PackingPlanBuilder before modifying containers");
    }
    if (this.containerMaximumResourceValue == null) {
      throw new TaskSchedulerException(
          "maxContainerResource must be set on PackingPlanBuilder before modifying containers");
    }
  }

  private Set buildContainerPlans(Map containerValue,
                                                      Map taskramMap,
                                                      Resource instdefaultresourcevalue) {

    Set workerSchedulePlans = new LinkedHashSet<>();
    try {
      for (Integer containerId : containerValue.keySet()) {
        Container container = containerValue.get(containerId);
        if (container.getTaskInstances().size() == 0) {
          continue;
        }
        double containerRAMValue = 0.0;
        double containerDiskValue = 0.0;
        double containerCPUValue = 0.0;

        Set taskInstancePlans = new HashSet<>();

        for (TaskInstancePlan taskInstancePlan : container.getTaskInstances()) {

          TaskInstanceId taskInstanceId = new TaskInstanceId(taskInstancePlan.getTaskName(),
              taskInstancePlan.getTaskId(), taskInstancePlan.getTaskIndex());

          double instanceRAMValue;
          if (taskramMap.containsKey(taskInstanceId.getTaskName())) {
            instanceRAMValue = taskramMap.get(taskInstanceId.getTaskName());
          } else {
            instanceRAMValue = instdefaultresourcevalue.getRam();
          }
          containerRAMValue += instanceRAMValue;

          double instanceDiskValue = instdefaultresourcevalue.getDisk();
          containerDiskValue += instanceDiskValue;

          double instanceCPUValue = instdefaultresourcevalue.getCpu();
          containerCPUValue += instanceCPUValue;

          LOG.fine("Resource Container Values:" + "Ram Value:" + containerRAMValue + "\t"
              + "Cpu Value:" + containerCPUValue + "\t" + "Disk Value:" + containerDiskValue);

          Resource resource = new Resource(instanceRAMValue, instanceDiskValue, instanceCPUValue);
          taskInstancePlans.add(new TaskInstancePlan(taskInstanceId.getTaskName(),
              taskInstanceId.getTaskId(), taskInstanceId.getTaskIndex(), resource));
        }

        containerCPUValue += (requestedContainerPadding * containerCPUValue) / 100;
        containerRAMValue += containerRAMValue + requestedContainerPadding;
        containerDiskValue += containerDiskValue + requestedContainerPadding;

        Resource resource = new Resource(containerRAMValue, containerDiskValue, containerCPUValue);
        WorkerSchedulePlan workerSchedulePlan =
            new WorkerSchedulePlan(containerId, taskInstancePlans, resource);
        workerSchedulePlans.add(workerSchedulePlan);
      }
    } catch (TaskSchedulerException ne) {
      throw new RuntimeException("Exception Occured" + ne.getMessage());
    }
    return workerSchedulePlans;
  }

  /**
   * Get the containers based on the task schedule plan
   */
  private Map getContainers(TaskSchedulePlan previoustaskschedulePlan)
      throws TaskSchedulerException {

    Map containerMap = new HashMap<>();
    Resource resource = previoustaskschedulePlan.getMaxContainerResources();
    for (WorkerSchedulePlan currentWorkerSchedulePlan : previoustaskschedulePlan.getContainers()) {
      Container container = new Container(currentWorkerSchedulePlan.getContainerId(), resource,
          requestedContainerPadding);
      for (TaskInstancePlan instancePlan : currentWorkerSchedulePlan.getTaskInstances()) {
        try {
          addToContainer(container, instancePlan, taskIndexes, taskIds);
        } catch (TaskSchedulerException e) {
          throw new TaskSchedulerException(String.format(
              "Insufficient container resources to add instancePlan %s to container %s",
              instancePlan, container), e);
        }
      }
      containerMap.put(currentWorkerSchedulePlan.getContainerId(), container);
    }
    return containerMap;
  }

  /**
   * Get the containers based on the task schedule plan
   * @param previoustaskschedulePlan
   * @return
   * @throws TaskSchedulerException
   */
  private Map getContainers(TaskSchedulePlan previoustaskschedulePlan,
                                                int containerPadding,
                                                Map> taskindexes,
                                                TreeSet taskids)
      throws TaskSchedulerException {

    Map containerMap = new HashMap<>();
    Resource resource = previoustaskschedulePlan.getMaxContainerResources();
    for (WorkerSchedulePlan currentWorkerSchedulePlan : previoustaskschedulePlan.getContainers()) {
      Container container = new Container(currentWorkerSchedulePlan.getContainerId(), resource,
          containerPadding);
      for (TaskInstancePlan instancePlan : currentWorkerSchedulePlan.getTaskInstances()) {
        try {
          addToContainer(container, instancePlan, taskindexes, taskids);
        } catch (TaskSchedulerException e) {
          throw new TaskSchedulerException(String.format(
              "Insufficient container resources to add instancePlan %s to container %s",
              instancePlan, container), e);
        }
      }
      containerMap.put(currentWorkerSchedulePlan.getContainerId(), container);
    }
    return containerMap;
  }


  private static class ChainedContainerComparator implements Comparator {
    private final Comparator comparator;
    private final ChainedContainerComparator tieBreaker;

    ChainedContainerComparator(List> scorers) {
      this((Queue>) new LinkedList<>(scorers));
    }

    ChainedContainerComparator(Queue> scorers) {
      if (scorers.isEmpty()) {
        this.comparator = new EqualsComparator<>();
        this.tieBreaker = null;
      } else {
        this.comparator = new ContainerComparator<>(scorers.remove());
        this.tieBreaker = new ChainedContainerComparator<>(scorers);
      }
    }

    @Override
    public int compare(T thisOne, T thatOne) {
      int delta = comparator.compare(thisOne, thatOne);
      if (delta != 0 || this.tieBreaker == null) {
        return delta;
      }
      return tieBreaker.compare(thisOne, thatOne);
    }
  }

  private static class EqualsComparator implements Comparator {

    @Override
    public int compare(T thisOne, T thatOne) {
      return 0;
    }
  }

  private static class ContainerComparator implements Comparator {
    private Scorer scorer;

    ContainerComparator(Scorer scorer) {
      this.scorer = scorer;
    }

    @Override
    public int compare(T thisOne, T thatOne) {
      int sign = 1;
      if (!scorer.sortAscending()) {
        sign = -1;
      }
      return sign * (getScore(thisOne) - getScore(thatOne));
    }

    private int getScore(T container) {
      return (int) (1000 * scorer.getScore(container));
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy