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

com.twitter.heron.spi.packing.PackingPlan Maven / Gradle / Ivy

// Copyright 2016 Twitter. All rights reserved.
//
// 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 com.twitter.heron.spi.packing;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;

import com.twitter.heron.common.basics.ByteAmount;

public class PackingPlan {
  private final String id;
  private final Map containersMap;
  private final Set containers;

  public PackingPlan(String id, Set containers) {
    this.id = id;
    this.containers = ImmutableSet.copyOf(containers);
    containersMap = new HashMap<>();
    for (ContainerPlan containerPlan : containers) {
      containersMap.put(containerPlan.getId(), containerPlan);
    }
  }

  /**
   * Computes the maximum of all the resources required by the containers in the packing plan. If
   * the PackingPlan has already been scheduled, the scheduled resources will be used over the
   * required resources.
   *
   * @return maximum Resources found in all containers.
   */
  public Resource getMaxContainerResources() {
    double maxCpu = 0;
    ByteAmount maxRam = ByteAmount.ZERO;
    ByteAmount maxDisk = ByteAmount.ZERO;
    for (ContainerPlan containerPlan : getContainers()) {
      Resource containerResource =
          containerPlan.getScheduledResource().or(containerPlan.getRequiredResource());
      maxCpu = Math.max(maxCpu, containerResource.getCpu());
      maxRam = maxRam.max(containerResource.getRam());
      maxDisk = maxDisk.max(containerResource.getDisk());
    }

    return new Resource(maxCpu, maxRam, maxDisk);
  }

  /**
   * Creates a clone of {@link PackingPlan}. It also computes the maximum of all the resources
   * required by containers in the packing plan and updates the containers of the clone with the
   * max resource information
   */
  public PackingPlan cloneWithHomogeneousScheduledResource() {
    Resource maxResource = getMaxContainerResources();
    Set updatedContainers = new LinkedHashSet<>();
    for (ContainerPlan container : getContainers()) {
      updatedContainers.add(container.cloneWithScheduledResource(maxResource));
    }

    return new PackingPlan(getId(), updatedContainers);
  }

  public String getId() {
    return id;
  }

  public Set getContainers() {
    return containers;
  }

  public Map getContainersMap() {
    return containersMap;
  }

  public Optional getContainer(int containerId) {
    return Optional.fromNullable(this.containersMap.get(containerId));
  }

  public Integer getInstanceCount() {
    Integer totalInstances = 0;
    for (Integer count : getComponentCounts().values()) {
      totalInstances += count;
    }
    return totalInstances;
  }

  /**
   * Return a map containing the count of all of the components, keyed by name
   */
  public Map getComponentCounts() {
    Map componentCounts = new HashMap<>();
    for (ContainerPlan containerPlan : getContainers()) {
      for (InstancePlan instancePlan : containerPlan.getInstances()) {
        Integer count = 0;
        if (componentCounts.containsKey(instancePlan.getComponentName())) {
          count = componentCounts.get(instancePlan.getComponentName());
        }
        componentCounts.put(instancePlan.getComponentName(), ++count);
      }
    }
    return componentCounts;
  }

  /**
   * Get the formatted String describing component ram distribution from PackingPlan,
   * used by executor
   *
   * @return String describing component ram distribution
   */
  public String getComponentRamDistribution() {
    Map ramMap = new HashMap<>();
    // The implementation assumes instances for the same component require same ram
    for (ContainerPlan containerPlan : this.getContainers()) {
      for (InstancePlan instancePlan : containerPlan.getInstances()) {
        ramMap.put(instancePlan.getComponentName(), instancePlan.getResource().getRam());
      }
    }

    // Convert it into a formatted String
    StringBuilder ramMapBuilder = new StringBuilder();
    for (String component : ramMap.keySet()) {
      ramMapBuilder.append(String.format("%s:%d,", component, ramMap.get(component).asBytes()));
    }

    // Remove the duplicated "," at the end
    ramMapBuilder.deleteCharAt(ramMapBuilder.length() - 1);
    return ramMapBuilder.toString();
  }

  @Override
  public String toString() {
    return String.format("{plan-id: %s, containers-list: %s}",
        getId(), getContainers().toString());
  }

  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }

    PackingPlan that = (PackingPlan) o;

    return getId().equals(that.getId())
        && getContainers().equals(that.getContainers());
  }

  @Override
  public int hashCode() {
    int result = getId().hashCode();
    result = 31 * result + getContainers().hashCode();
    return result;
  }

  public static class InstancePlan {
    private final String componentName;
    private final int taskId;
    private final int componentIndex;
    private final Resource resource;

    public InstancePlan(InstanceId instanceId, Resource resource) {
      this.componentName = instanceId.getComponentName();
      this.taskId = instanceId.getTaskId();
      this.componentIndex = instanceId.getComponentIndex();
      this.resource = resource;
    }

    public String getComponentName() {
      return componentName;
    }

    public int getTaskId() {
      return taskId;
    }

    public int getComponentIndex() {
      return componentIndex;
    }

    public Resource getResource() {
      return resource;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      InstancePlan that = (InstancePlan) o;

      return getComponentName().equals(that.getComponentName())
          && getTaskId() == that.getTaskId()
          && getComponentIndex() == that.getComponentIndex()
          && getResource().equals(that.getResource());
    }

    @Override
    public int hashCode() {
      int result = getComponentName().hashCode();
      result = 31 * result + ((Integer) getTaskId()).hashCode();
      result = 31 * result + ((Integer) getComponentIndex()).hashCode();
      result = 31 * result + getResource().hashCode();
      return result;
    }

    @Override
    public String toString() {
      return String.format(
          "{component-name: %s, task-id: %s, component-index: %s, instance-resource: %s}",
          getComponentName(), getTaskId(), getComponentIndex(), getResource().toString());
    }
  }

  public static class ContainerPlan {
    private final int id;
    private final Set instances;
    private final Resource requiredResource;
    private final Optional scheduledResource;

    public ContainerPlan(int id, Set instances, Resource requiredResource) {
      this(id, instances, requiredResource, null);
    }

    public ContainerPlan(int id,
                         Set instances,
                         Resource requiredResource,
                         Resource scheduledResource) {
      this.id = id;
      this.instances = ImmutableSet.copyOf(instances);
      this.requiredResource = requiredResource;
      this.scheduledResource = Optional.fromNullable(scheduledResource);
    }

    public int getId() {
      return id;
    }

    public Set getInstances() {
      return instances;
    }

    public Resource getRequiredResource() {
      return requiredResource;
    }

    public Optional getScheduledResource() {
      return scheduledResource;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }

      ContainerPlan that = (ContainerPlan) o;

      return id == that.id
          && getInstances().equals(that.getInstances())
          && getRequiredResource().equals(that.getRequiredResource())
          && getScheduledResource().equals(that.getScheduledResource());
    }

    @Override
    public int hashCode() {
      int result = id;
      result = 31 * result + getInstances().hashCode();
      result = 31 * result + getRequiredResource().hashCode();
      if (scheduledResource.isPresent()) {
        result = 31 * result + getScheduledResource().get().hashCode();
      }
      return result;
    }

    /**
     * Returns a {@link ContainerPlan} with updated scheduledResource
     */
    private ContainerPlan cloneWithScheduledResource(Resource resource) {
      return new ContainerPlan(getId(), getInstances(), getRequiredResource(), resource);
    }

    @Override
    public String toString() {
      String str = String.format("{container-id: %s, instances-list: %s, required-resource: %s",
          id, getInstances().toString(), getRequiredResource());
      if (scheduledResource.isPresent()) {
        str = String.format("%s, scheduled-resource: %s", str, getScheduledResource().get());
      }

      return str + "}";
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy