aurora-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject incubator-aurora git commit: Offer filtering for static vetoes. Part 2 of 4: Veto groups.
Date Fri, 13 Feb 2015 02:22:07 GMT
Repository: incubator-aurora
Updated Branches:
  refs/heads/master f3473a3d9 -> 7637200fe


Offer filtering for static vetoes. Part 2 of 4: Veto groups.

Bugs closed: AURORA-909

Reviewed at https://reviews.apache.org/r/30890/


Project: http://git-wip-us.apache.org/repos/asf/incubator-aurora/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-aurora/commit/7637200f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-aurora/tree/7637200f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-aurora/diff/7637200f

Branch: refs/heads/master
Commit: 7637200fe44ba7590479d42e0d2f559823589556
Parents: f3473a3
Author: Maxim Khutornenko <maxim@apache.org>
Authored: Thu Feb 12 18:21:49 2015 -0800
Committer: Maxim Khutornenko <maxim@apache.org>
Committed: Thu Feb 12 18:21:49 2015 -0800

----------------------------------------------------------------------
 .../org/apache/aurora/scheduler/TaskVars.java   | 52 +++---------------
 .../scheduler/filter/SchedulingFilter.java      | 56 ++++++++++++++++++--
 .../scheduler/filter/SchedulingFilterImpl.java  | 31 +++++------
 .../apache/aurora/scheduler/TaskVarsTest.java   | 31 +++++++----
 .../filter/SchedulingFilterImplTest.java        | 25 +++++++++
 5 files changed, 122 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7637200f/src/main/java/org/apache/aurora/scheduler/TaskVars.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/TaskVars.java b/src/main/java/org/apache/aurora/scheduler/TaskVars.java
index f017cdd..54d893e 100644
--- a/src/main/java/org/apache/aurora/scheduler/TaskVars.java
+++ b/src/main/java/org/apache/aurora/scheduler/TaskVars.java
@@ -43,7 +43,7 @@ import org.apache.aurora.scheduler.events.PubsubEvent.TaskStateChange;
 import org.apache.aurora.scheduler.events.PubsubEvent.TasksDeleted;
 import org.apache.aurora.scheduler.events.PubsubEvent.Vetoed;
 import org.apache.aurora.scheduler.filter.SchedulingFilter.Veto;
-import org.apache.aurora.scheduler.filter.SchedulingFilter.VetoType;
+import org.apache.aurora.scheduler.filter.SchedulingFilter.VetoGroup;
 import org.apache.aurora.scheduler.storage.AttributeStore;
 import org.apache.aurora.scheduler.storage.Storage;
 import org.apache.aurora.scheduler.storage.Storage.StoreProvider;
@@ -61,33 +61,11 @@ class TaskVars extends AbstractIdleService implements EventSubscriber
{
   private static final ImmutableSet<ScheduleStatus> TRACKED_JOB_STATES =
       ImmutableSet.of(ScheduleStatus.LOST, ScheduleStatus.FAILED);
 
-  /**
-   * Tracks {@link Vetoed} events that have strictly static vetoes to determine task/offer
-   * satisfiability. Vetoes are considered static if the cached offer will never be able
to satisfy
-   * a given task requirements.
-   */
   @VisibleForTesting
-  static final String VETO_STATIC_NAME = "scheduling_veto_static";
-
-  /**
-   * Tracks {@link Vetoed} events that have strictly dynamic vetoes to determine task/offer
-   * satisfiability. Vetoes are considered dynamic if the cached offer may still satisfy
a given
-   * task requirements if cluster conditions change (e.g. other tasks are killed or rescheduled).
-   */
-  @VisibleForTesting
-  static final String VETO_DYNAMIC_NAME = "scheduling_veto_dynamic";
-
-  /**
-   * Tracks {@link Vetoed} events that have both static and dynamic vetoes.
-   */
-  @VisibleForTesting
-  static final String VETO_MIXED_NAME = "scheduling_veto_mixed";
-
-  private static final Map<VetoType, String> VETO_TYPES_TO_COUNTERS = ImmutableMap.of(
-      VetoType.INSUFFICIENT_RESOURCES, VETO_STATIC_NAME,
-      VetoType.CONSTRAINT_MISMATCH, VETO_STATIC_NAME,
-      VetoType.LIMIT_NOT_SATISFIED, VETO_DYNAMIC_NAME,
-      VetoType.MAINTENANCE, VETO_STATIC_NAME
+  static final Map<VetoGroup, String> VETO_GROUPS_TO_COUNTERS = ImmutableMap.of(
+      VetoGroup.STATIC, "scheduling_veto_static",
+      VetoGroup.DYNAMIC, "scheduling_veto_dynamic",
+      VetoGroup.MIXED, "scheduling_veto_mixed"
   );
 
   private final LoadingCache<String, Counter> counters;
@@ -249,24 +227,10 @@ class TaskVars extends AbstractIdleService implements EventSubscriber
{
 
   @Subscribe
   public void taskVetoed(Vetoed event) {
-    // This handler has high call frequency and as such needs to be optimized for reduced
-    // heap churn. We are going to use loop flags to avoid additional object creation.
-    String metricName = null;
-    for (Veto veto : event.getVetoes()) {
-      String currentName = VETO_TYPES_TO_COUNTERS.get(veto.getVetoType());
-      if (currentName == null) {
-        throw new IllegalStateException("Unknown veto type in " + event);
-      }
-
-      if (metricName == null) {
-        metricName = currentName;
-      } else if (!currentName.equals(metricName)) {
-        counters.getUnchecked(VETO_MIXED_NAME).increment();
-        return;
-      }
+    VetoGroup vetoGroup = Veto.identifyGroup(event.getVetoes());
+    if (vetoGroup != VetoGroup.EMPTY) {
+      counters.getUnchecked(VETO_GROUPS_TO_COUNTERS.get(vetoGroup)).increment();
     }
-
-    counters.getUnchecked(metricName).increment();
   }
 
   private static class Counter implements Supplier<Long> {

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7637200f/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilter.java b/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilter.java
index 6a43bcd..3313bd2 100644
--- a/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilter.java
+++ b/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilter.java
@@ -31,36 +31,67 @@ import static org.apache.aurora.scheduler.filter.SchedulingFilter.VetoType.MAINT
  */
 public interface SchedulingFilter {
 
+  enum VetoGroup {
+    /**
+     * An empty group of {@link Veto} instances.
+     */
+    EMPTY,
+
+    /**
+     * Represents a group of static {@link Veto} instances. Vetoes are considered static
if
+     * a given offer will never be able to satisfy given task requirements.
+     */
+    STATIC,
+
+    /**
+     * Represents a group of dynamic {@link Veto} instances. Vetoes are considered dynamic
if
+     * a given offer may be able to satisfy given task requirements if cluster conditions
change
+     * (e.g. other tasks are killed or rescheduled).
+     */
+    DYNAMIC,
+
+    /**
+     * Represents a group of both static and dynamic {@link Veto} instances.
+     */
+    MIXED
+  }
+
   enum VetoType {
     /**
      * Not enough resources to satisfy a proposed scheduling assignment.
      */
-    INSUFFICIENT_RESOURCES("Insufficient: %s"),
+    INSUFFICIENT_RESOURCES("Insufficient: %s", VetoGroup.STATIC),
 
     /**
      * Unable to satisfy proposed scheduler assignment constraints.
      */
-    CONSTRAINT_MISMATCH("Constraint not satisfied: %s"),
+    CONSTRAINT_MISMATCH("Constraint not satisfied: %s", VetoGroup.STATIC),
 
     /**
      * Constraint limit is not satisfied for a proposed scheduling assignment.
      */
-    LIMIT_NOT_SATISFIED("Limit not satisfied: %s"),
+    LIMIT_NOT_SATISFIED("Limit not satisfied: %s", VetoGroup.DYNAMIC),
 
     /**
      * Unable to satisfy a proposed scheduler assignment due to cluster maintenance.
      */
-    MAINTENANCE("Host %s for maintenance");
+    MAINTENANCE("Host %s for maintenance", VetoGroup.STATIC);
 
     private final String reasonFormat;
+    private final VetoGroup group;
 
-    VetoType(String reasonFormat) {
+    VetoType(String reasonFormat, VetoGroup group) {
       this.reasonFormat = reasonFormat;
+      this.group = group;
     }
 
     String formatReason(String reason) {
       return String.format(reasonFormat, reason);
     }
+
+    VetoGroup getGroup() {
+      return group;
+    }
   }
 
   /**
@@ -139,6 +170,21 @@ public interface SchedulingFilter {
       return vetoType;
     }
 
+    public static VetoGroup identifyGroup(Iterable<Veto> vetoes) {
+      // This code has high call frequency and is optimized for reduced heap churn.
+      VetoGroup group = VetoGroup.EMPTY;
+      for (Veto veto : vetoes) {
+        VetoGroup currentGroup = veto.getVetoType().getGroup();
+
+        if (group == VetoGroup.EMPTY) {
+          group = currentGroup;
+        } else if (!currentGroup.equals(group)) {
+          return VetoGroup.MIXED;
+        }
+      }
+      return group;
+    }
+
     @Override
     public boolean equals(Object o) {
       if (!(o instanceof Veto)) {

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7637200f/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java b/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java
index f06fdae..a020ce5 100644
--- a/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java
+++ b/src/main/java/org/apache/aurora/scheduler/filter/SchedulingFilterImpl.java
@@ -19,7 +19,6 @@ import java.util.Set;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Ordering;
@@ -101,7 +100,7 @@ public class SchedulingFilterImpl implements SchedulingFilter {
   }
 
   private static void maybeAddVeto(
-      ImmutableList.Builder<Veto> vetoes,
+      ImmutableSet.Builder<Veto> vetoes,
       ResourceVector vector,
       double available,
       double requested) {
@@ -112,8 +111,8 @@ public class SchedulingFilterImpl implements SchedulingFilter {
     }
   }
 
-  private static Iterable<Veto> getResourceVetoes(ResourceSlot available, ResourceSlot
required) {
-    ImmutableList.Builder<Veto> vetoes = ImmutableList.builder();
+  private static Set<Veto> getResourceVetoes(ResourceSlot available, ResourceSlot required)
{
+    ImmutableSet.Builder<Veto> vetoes = ImmutableSet.builder();
     maybeAddVeto(vetoes, CPU, available.getNumCpus(), required.getNumCpus());
     maybeAddVeto(vetoes, RAM, available.getRam().as(Data.MB), required.getRam().as(Data.MB));
     maybeAddVeto(vetoes, DISK, available.getDisk().as(Data.MB), required.getDisk().as(Data.MB));
@@ -144,12 +143,12 @@ public class SchedulingFilterImpl implements SchedulingFilter {
     this.executorSettings = requireNonNull(executorSettings);
   }
 
-  private Iterable<Veto> getConstraintVetoes(
+  private Set<Veto> getConstraintVetoes(
       Iterable<IConstraint> taskConstraints,
       AttributeAggregate jobState,
       Iterable<IAttribute> offerAttributes) {
 
-    ImmutableList.Builder<Veto> vetoes = ImmutableList.builder();
+    ImmutableSet.Builder<Veto> vetoes = ImmutableSet.builder();
     for (IConstraint constraint : VALUES_FIRST.sortedCopy(taskConstraints)) {
       Optional<Veto> veto = ConstraintMatcher.getVeto(jobState, offerAttributes, constraint);
       if (veto.isPresent()) {
@@ -190,14 +189,16 @@ public class SchedulingFilterImpl implements SchedulingFilter {
       return maintenanceVeto.asSet();
     }
 
-    return ImmutableSet.<Veto>builder()
-        .addAll(getConstraintVetoes(
-            request.getConstraints(),
-            request.getJobState(),
-            resource.getAttributes().getAttributes()))
-        .addAll(getResourceVetoes(
-            resource.getResourceSlot(),
-            ResourceSlot.from(request.getTask(), executorSettings)))
-        .build();
+    Set<Veto> resourceVetoes = getResourceVetoes(
+        resource.getResourceSlot(),
+        ResourceSlot.from(request.getTask(), executorSettings));
+    if (!resourceVetoes.isEmpty()) {
+      return resourceVetoes;
+    }
+
+    return getConstraintVetoes(
+        request.getConstraints(),
+        request.getJobState(),
+        resource.getAttributes().getAttributes());
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7637200f/src/test/java/org/apache/aurora/scheduler/TaskVarsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/TaskVarsTest.java b/src/test/java/org/apache/aurora/scheduler/TaskVarsTest.java
index 4e7efb3..13520eb 100644
--- a/src/test/java/org/apache/aurora/scheduler/TaskVarsTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/TaskVarsTest.java
@@ -13,6 +13,7 @@
  */
 package org.apache.aurora.scheduler;
 
+import java.util.EnumSet;
 import java.util.Map;
 
 import com.google.common.base.Optional;
@@ -36,6 +37,7 @@ import org.apache.aurora.scheduler.events.PubsubEvent;
 import org.apache.aurora.scheduler.events.PubsubEvent.TaskStateChange;
 import org.apache.aurora.scheduler.events.PubsubEvent.TasksDeleted;
 import org.apache.aurora.scheduler.filter.SchedulingFilter.Veto;
+import org.apache.aurora.scheduler.filter.SchedulingFilter.VetoGroup;
 import org.apache.aurora.scheduler.storage.entities.IHostAttributes;
 import org.apache.aurora.scheduler.storage.entities.IScheduledTask;
 import org.apache.aurora.scheduler.storage.testing.StorageTestUtil;
@@ -52,14 +54,13 @@ import static org.apache.aurora.gen.ScheduleStatus.INIT;
 import static org.apache.aurora.gen.ScheduleStatus.LOST;
 import static org.apache.aurora.gen.ScheduleStatus.PENDING;
 import static org.apache.aurora.gen.ScheduleStatus.RUNNING;
-import static org.apache.aurora.scheduler.TaskVars.VETO_DYNAMIC_NAME;
-import static org.apache.aurora.scheduler.TaskVars.VETO_MIXED_NAME;
-import static org.apache.aurora.scheduler.TaskVars.VETO_STATIC_NAME;
+import static org.apache.aurora.scheduler.TaskVars.VETO_GROUPS_TO_COUNTERS;
 import static org.apache.aurora.scheduler.TaskVars.jobStatName;
 import static org.apache.aurora.scheduler.TaskVars.rackStatName;
 import static org.easymock.EasyMock.expect;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 
 public class TaskVarsTest extends EasyMockTest {
 
@@ -69,6 +70,10 @@ public class TaskVarsTest extends EasyMockTest {
   private static final String TASK_ID = "task_id";
   private static final String ENV = "test";
 
+  private static final String STATIC_COUNTER = VETO_GROUPS_TO_COUNTERS.get(VetoGroup.STATIC);
+  private static final String DYNAMIC_COUNTER = VETO_GROUPS_TO_COUNTERS.get(VetoGroup.DYNAMIC);
+  private static final String MIXED_COUNTER = VETO_GROUPS_TO_COUNTERS.get(VetoGroup.MIXED);
+
   private StorageTestUtil storageUtil;
   private StatsProvider trackedProvider;
   private StatsProvider untrackedProvider;
@@ -219,7 +224,7 @@ public class TaskVarsTest extends EasyMockTest {
   @Test
   public void testStaticVetoGroup() {
     expectStatusCountersInitialized();
-    expectStatExport(VETO_STATIC_NAME);
+    expectStatExport(STATIC_COUNTER);
 
     replayAndBuild();
     schedulerActivated();
@@ -229,25 +234,25 @@ public class TaskVarsTest extends EasyMockTest {
         Veto.insufficientResources("ram", 500),
         Veto.insufficientResources("cpu", 500));
 
-    assertEquals(1, getValue(VETO_STATIC_NAME));
+    assertEquals(1, getValue(STATIC_COUNTER));
   }
 
   @Test
   public void testDynamicVetoGroup() {
     expectStatusCountersInitialized();
-    expectStatExport(VETO_DYNAMIC_NAME);
+    expectStatExport(DYNAMIC_COUNTER);
 
     replayAndBuild();
     schedulerActivated();
 
     applyVeto(makeTask(JOB_A, PENDING), Veto.unsatisfiedLimit("constraint"));
-    assertEquals(1, getValue(VETO_DYNAMIC_NAME));
+    assertEquals(1, getValue(DYNAMIC_COUNTER));
   }
 
   @Test
   public void testMixedVetoGroup() {
     expectStatusCountersInitialized();
-    expectStatExport(VETO_MIXED_NAME);
+    expectStatExport(MIXED_COUNTER);
 
     replayAndBuild();
     schedulerActivated();
@@ -256,7 +261,7 @@ public class TaskVarsTest extends EasyMockTest {
         Veto.unsatisfiedLimit("constraint"),
         Veto.insufficientResources("ram", 500));
 
-    assertEquals(1, getValue(VETO_MIXED_NAME));
+    assertEquals(1, getValue(MIXED_COUNTER));
   }
 
   @Test
@@ -346,4 +351,12 @@ public class TaskVarsTest extends EasyMockTest {
     changeState(a, LOST);
     // Since no attributes are stored for the host, a variable is not exported/updated.
   }
+
+  @Test
+  public void testAllVetoGroupsCovered() {
+    replayAndBuild();
+    for (VetoGroup group : EnumSet.complementOf(EnumSet.of(VetoGroup.EMPTY))) {
+      assertNotNull("Unknown VetoGroup value: " + group, VETO_GROUPS_TO_COUNTERS.get(group));
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-aurora/blob/7637200f/src/test/java/org/apache/aurora/scheduler/filter/SchedulingFilterImplTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/aurora/scheduler/filter/SchedulingFilterImplTest.java
b/src/test/java/org/apache/aurora/scheduler/filter/SchedulingFilterImplTest.java
index 52ee7c1..b006684 100644
--- a/src/test/java/org/apache/aurora/scheduler/filter/SchedulingFilterImplTest.java
+++ b/src/test/java/org/apache/aurora/scheduler/filter/SchedulingFilterImplTest.java
@@ -41,6 +41,7 @@ import org.apache.aurora.scheduler.configuration.ConfigurationManager;
 import org.apache.aurora.scheduler.filter.SchedulingFilter.ResourceRequest;
 import org.apache.aurora.scheduler.filter.SchedulingFilter.UnusedResource;
 import org.apache.aurora.scheduler.filter.SchedulingFilter.Veto;
+import org.apache.aurora.scheduler.filter.SchedulingFilter.VetoGroup;
 import org.apache.aurora.scheduler.mesos.Offers;
 import org.apache.aurora.scheduler.mesos.TaskExecutors;
 import org.apache.aurora.scheduler.storage.AttributeStore;
@@ -457,6 +458,30 @@ public class SchedulingFilterImplTest extends EasyMockTest {
     checkConstraint(hostA, "jvm", true, "1.6", "1.7");
   }
 
+  @Test
+  public void testVetoGroups() {
+    control.replay();
+
+    assertEquals(VetoGroup.EMPTY, Veto.identifyGroup(ImmutableSet.<Veto>of()));
+
+    assertEquals(
+        VetoGroup.STATIC,
+        Veto.identifyGroup(ImmutableSet.of(
+            Veto.constraintMismatch("denied"),
+            Veto.insufficientResources("ram", 100),
+            Veto.maintenance("draining"))));
+
+    assertEquals(
+        VetoGroup.DYNAMIC,
+        Veto.identifyGroup(ImmutableSet.of(Veto.unsatisfiedLimit("denied"))));
+
+    assertEquals(
+        VetoGroup.MIXED,
+        Veto.identifyGroup(ImmutableSet.of(
+            Veto.insufficientResources("ram", 100),
+            Veto.unsatisfiedLimit("denied"))));
+  }
+
   private ITaskConfig checkConstraint(
       IHostAttributes hostAttributes,
       String constraintName,


Mime
View raw message