diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java index 628c58576e..a9e8423ab2 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfiguration.java @@ -426,6 +426,19 @@ public class CapacitySchedulerConfiguration extends ReservationSchedulerConfigur private ConfigurationProperties configurationProperties; + public int getMaximumAutoCreatedQueueDepth(String queuePath) { + return getInt(getQueuePrefix(queuePath) + MAXIMUM_QUEUE_DEPTH, + getInt(PREFIX + MAXIMUM_QUEUE_DEPTH, DEFAULT_MAXIMUM_QUEUE_DEPTH)); + } + + public void setMaximumAutoCreatedQueueDepth(String queuePath, int value) { + setInt(getQueuePrefix(queuePath) + MAXIMUM_QUEUE_DEPTH, value); + } + + public void setMaximumAutoCreatedQueueDepth(int value) { + setInt(PREFIX + MAXIMUM_QUEUE_DEPTH, value); + } + /** * Different resource types supported. */ @@ -2136,6 +2149,13 @@ public void setDefaultLifetimePerQueue(String queue, long defaultLifetime) { public static final int DEFAULT_AUTO_QUEUE_CREATION_V2_MAX_QUEUES = 1000; + @Private + public static final String MAXIMUM_QUEUE_DEPTH = + AUTO_QUEUE_CREATION_V2_PREFIX + "maximum-queue-depth"; + + @Private + public static final int DEFAULT_MAXIMUM_QUEUE_DEPTH = 2; + @Private public static final boolean DEFAULT_AUTO_QUEUE_CREATION_ENABLED = false; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java index c1669d0c76..50e8d5289c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java @@ -23,6 +23,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -72,7 +73,6 @@ public CSQueue hook(CSQueue queue) { } } - private static final int MAXIMUM_DYNAMIC_QUEUE_DEPTH = 2; private static final QueueHook NOOP = new QueueHook(); private CapacitySchedulerContext csContext; private final YarnAuthorizationProvider authorizer; @@ -592,14 +592,6 @@ public List determineMissingParents( && parentCandidate.length() != 0) { ++firstStaticParentDistance; - if (firstStaticParentDistance > MAXIMUM_DYNAMIC_QUEUE_DEPTH) { - throw new SchedulerDynamicEditException( - "Could not auto create queue " + queue.getFullPath() - + ". The distance of the LeafQueue from the first static " + - "ParentQueue is " + firstStaticParentDistance + ", which is " + - "above the limit."); - } - if (firstExistingParent == null) { parentsToCreate.addFirst(parentCandidate.toString()); } @@ -614,6 +606,16 @@ public List determineMissingParents( firstExistingStaticParent = getQueue(parentCandidate.toString()); } + int maximumDepthOfStaticParent = csContext.getConfiguration().getMaximumAutoCreatedQueueDepth( + firstExistingStaticParent.getQueuePath()); + if (firstStaticParentDistance > maximumDepthOfStaticParent) { + throw new SchedulerDynamicEditException( + "Could not auto create queue " + queue.getFullPath() + + ". The distance of the LeafQueue from the first static " + + "ParentQueue is " + firstStaticParentDistance + ", which is " + + "above the limit."); + } + if (!(firstExistingParent instanceof ParentQueue)) { throw new SchedulerDynamicEditException( "Could not auto create hierarchy of " diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java index b5eaf3ca76..037312b716 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerNewQueueAutoCreation.java @@ -318,11 +318,40 @@ public void testAutoCreateQueueWhenSiblingsNotInWeightMode() createQueue("root.a.a2-auto"); } - @Test(expected = SchedulerDynamicEditException.class) - public void testAutoCreateQueueShouldFailIfDepthIsAboveLimit() + @Test() + public void testAutoCreateMaximumQueueDepth() throws Exception { startScheduler(); - createQueue("root.a.a3-auto.a4-auto.a5-auto"); + // By default, max depth is 2, therefore this is an invalid scenario + Assert.assertThrows(SchedulerDynamicEditException.class, + () -> createQueue("root.a.a3-auto.a4-auto.a5-auto")); + + // Set depth 3 for root.a, making it a valid scenario + csConf.setMaximumAutoCreatedQueueDepth("root.a", 3); + cs.reinitialize(csConf, mockRM.getRMContext()); + try { + createQueue("root.a.a3-auto.a4-auto.a5-auto"); + } catch (SchedulerDynamicEditException sde) { + LOG.error("%s", sde); + Assert.fail("Depth is set for root.a, exception should not be thrown"); + } + + // Set global depth to 3 + csConf.setMaximumAutoCreatedQueueDepth(3); + csConf.unset(CapacitySchedulerConfiguration.getQueuePrefix("root.a") + + CapacitySchedulerConfiguration.MAXIMUM_QUEUE_DEPTH); + cs.reinitialize(csConf, mockRM.getRMContext()); + try { + createQueue("root.a.a6-auto.a7-auto.a8-auto"); + } catch (SchedulerDynamicEditException sde) { + LOG.error("%s", sde); + Assert.fail("Depth is set globally, exception should not be thrown"); + } + + // Set depth on a dynamic queue, which has no effect on auto queue creation validation + csConf.setMaximumAutoCreatedQueueDepth("root.a.a6-auto.a7-auto.a8-auto", 10); + Assert.assertThrows(SchedulerDynamicEditException.class, + () -> createQueue("root.a.a6-auto.a7-auto.a8-auto.a9-auto.a10-auto.a11-auto")); } @Test(expected = SchedulerDynamicEditException.class)