diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java index c98aadc..54901df 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/AllocationConfiguration.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Set; import org.apache.hadoop.conf.Configuration; @@ -105,6 +106,7 @@ private ReservationQueueConfiguration globalReservationQueueConfig; private final Set nonPreemptableQueues; + private final Map queueOversubscriptionSetting; public AllocationConfiguration(QueueProperties queueProperties, AllocationFileParser allocationFileParser, @@ -140,6 +142,8 @@ public AllocationConfiguration(QueueProperties queueProperties, this.placementPolicy = newPlacementPolicy; this.configuredQueues = queueProperties.getConfiguredQueues(); this.nonPreemptableQueues = queueProperties.getNonPreemptableQueues(); + this.queueOversubscriptionSetting = + queueProperties.getQueueOversubscriptionSetting(); } public AllocationConfiguration(Configuration conf) { @@ -169,6 +173,7 @@ public AllocationConfiguration(Configuration conf) { placementPolicy = QueuePlacementPolicy.fromConfiguration(conf, configuredQueues); nonPreemptableQueues = new HashSet<>(); + queueOversubscriptionSetting = new HashMap<>(0); } /** @@ -241,6 +246,10 @@ public boolean isPreemptable(String queueName) { return !nonPreemptableQueues.contains(queueName); } + public Optional isOversubscriptionAllowed(String queueName) { + return Optional.ofNullable(queueOversubscriptionSetting.get(queueName)); + } + private float getQueueWeight(String queue) { Float weight = queueWeights.get(queue); return (weight == null) ? 1.0f : weight; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSLeafQueue.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSLeafQueue.java index 2a90228..4dfccce 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSLeafQueue.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSLeafQueue.java @@ -370,6 +370,11 @@ public Resource assignContainer(FSSchedulerNode node, boolean opportunistic) { getName() + " fairShare: " + getFairShare()); } + if (opportunistic && !isOversubscriptionAllowed()) { + // do not proceed if the queue is opted out of over-subscription + return assigned; + } + if (!assignContainerPreCheck(node, opportunistic)) { return assigned; } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java index f293eb1..60462b8 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FSQueue.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Optional; import java.util.Set; import org.apache.commons.logging.Log; @@ -75,6 +76,7 @@ private ConfigurableResource maxShare; protected int maxRunningApps; private ConfigurableResource maxChildQueueResource; + private boolean isOversubscriptionAllowed; // maxAMShare is a value between 0 and 1. protected float maxAMShare; @@ -92,6 +94,7 @@ public FSQueue(String name, FairScheduler scheduler, FSParentQueue parent) { this.queueEntity = new PrivilegedEntity(EntityType.QUEUE, name); this.metrics = FSQueueMetrics.forQueue(getName(), parent, true, scheduler.getConf()); this.parent = parent; + this.isOversubscriptionAllowed = true; setPolicy(scheduler.getAllocationConfiguration().getSchedulingPolicy(name)); reinit(false); } @@ -111,6 +114,14 @@ public final void reinit(boolean recursive) { allocConf.initFSQueue(this); updatePreemptionVariables(); + Optional allowed = allocConf.isOversubscriptionAllowed(name); + if (allowed.isPresent()) { + isOversubscriptionAllowed = allowed.get(); + } else if (getParent() != null){ + // inherit from the parent queue if it is not explicitly set + isOversubscriptionAllowed = getParent().isOversubscriptionAllowed(); + } + if (recursive) { for (FSQueue child : getChildQueues()) { child.reinit(recursive); @@ -212,6 +223,15 @@ public long getStartTime() { return 0; } + public boolean isOversubscriptionAllowed() { + return isOversubscriptionAllowed; + } + + @VisibleForTesting + public void allowOversubscription(boolean allowed) { + this.isOversubscriptionAllowed = allowed; + } + @Override public Priority getPriority() { Priority p = recordFactory.newRecordInstance(Priority.class); @@ -583,7 +603,6 @@ public String dumpState() { return sb.toString(); } - /** * Recursively dump states of all queues. * diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/AllocationFileQueueParser.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/AllocationFileQueueParser.java index ec7e4a4..c7e72fc 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/AllocationFileQueueParser.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/AllocationFileQueueParser.java @@ -68,6 +68,7 @@ private static final String ACL_SUBMIT_RESERVATIONS = "aclSubmitReservations"; private static final String RESERVATION = "reservation"; private static final String ALLOW_PREEMPTION_FROM = "allowPreemptionFrom"; + private static final String ALLOW_OVERSUBSCRIPTION ="allowOversubscription"; private static final String QUEUE = "queue"; private static final String POOL = "pool"; @@ -207,6 +208,9 @@ private void loadQueue(String parentName, Element element, if (!Boolean.parseBoolean(text)) { builder.nonPreemptableQueues(queueName); } + } else if (ALLOW_OVERSUBSCRIPTION.equals(field.getTagName())) { + Boolean allow = Boolean.parseBoolean(getTrimmedTextData(field)); + builder.addQueueOversubscriptionSetting(queueName, allow); } else if (QUEUE.endsWith(field.getTagName()) || POOL.equals(field.getTagName())) { loadQueue(queueName, field, builder); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/QueueProperties.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/QueueProperties.java index ee5f179..eb7f23e 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/QueueProperties.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/allocation/QueueProperties.java @@ -52,6 +52,7 @@ reservationAcls; private final Set reservableQueues; private final Set nonPreemptableQueues; + private final Map queueOversubscriptionSetting; private final Map> configuredQueues; QueueProperties(Builder builder) { @@ -70,6 +71,7 @@ this.maxChildQueueResources = builder.maxChildQueueResources; this.reservationAcls = builder.reservationAcls; this.queueAcls = builder.queueAcls; + this.queueOversubscriptionSetting = builder.queueOversubscriptionSetting; } public Map> getConfiguredQueues() { @@ -133,6 +135,9 @@ return nonPreemptableQueues; } + public Map getQueueOversubscriptionSetting() { + return queueOversubscriptionSetting; + } /** * Builder class for {@link QueueProperties}. * All methods are adding queue properties to the maps of this builder @@ -160,6 +165,7 @@ reservationAcls = new HashMap<>(); private Set reservableQueues = new HashSet<>(); private Set nonPreemptableQueues = new HashSet<>(); + private Map queueOversubscriptionSetting = new HashMap<>(0); // Remember all queue names so we can display them on web UI, etc. // configuredQueues is segregated based on whether it is a leaf queue // or a parent queue. This information is used for creating queues @@ -253,6 +259,12 @@ public Builder nonPreemptableQueues(String queue) { return this; } + public Builder addQueueOversubscriptionSetting( + String queue, Boolean allow) { + this.queueOversubscriptionSetting.put(queue, allow); + return this; + } + public void configuredQueues(FSQueueType queueType, String queueName) { this.configuredQueues.get(queueType).add(queueName); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/FairSchedulerQueueInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/FairSchedulerQueueInfo.java index fe313a6..45b9ea9 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/FairSchedulerQueueInfo.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/FairSchedulerQueueInfo.java @@ -68,6 +68,7 @@ private String schedulingPolicy; private boolean preemptable; + private boolean allowOversubscription; private FairSchedulerQueueInfoList childQueues; @@ -118,6 +119,7 @@ public FairSchedulerQueueInfo(FSQueue queue, FairScheduler scheduler) { } preemptable = queue.isPreemptable(); + allowOversubscription = queue.isOversubscriptionAllowed(); childQueues = getChildQueues(queue, scheduler); } @@ -255,4 +257,8 @@ public String getSchedulingPolicy() { public boolean isPreemptable() { return preemptable; } + + public boolean isOversubscriptionAllowed() { + return allowOversubscription; + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestAllocationFileLoaderService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestAllocationFileLoaderService.java index 4a7461d..ce47268 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestAllocationFileLoaderService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestAllocationFileLoaderService.java @@ -570,6 +570,67 @@ public void testBackwardsCompatibleAllocationFileParsing() throws Exception { } @Test + public void testQueueOptOutOfOversubscription() throws Exception { + final Configuration conf = new Configuration(); + conf.set(FairSchedulerConfiguration.ALLOCATION_FILE, ALLOC_FILE); + AllocationFileLoaderService allocLoader = new AllocationFileLoaderService(); + + PrintWriter out = new PrintWriter(new FileWriter(ALLOC_FILE)); + out.println(""); + out.println(""); + // Queue A has the default value of allowOversubscription + out.println(""); + // The child queue of A, queueA.child1 has overridden the parent's setting + out.println(""); + out.println("false"); + out.println(""); + // The child queue of A, queueA.child2 inherits the setting from its parent + out.println(""); + out.println(""); + // Queue A has opted out of oversubscription + out.println(""); + // The child queue of B, queueB.child has overridden the parent's setting + out.println("true"); + // The child queue of A, queueA.child1 has overridden the parent's setting + out.println(""); + // The child queue of B, queueB.child2 inherits the setting from its parent + out.println(""); + out.println("false"); + out.println(""); + out.println(""); + out.println(""); + out.close(); + + allocLoader.init(conf); + ReloadListener confHolder = new ReloadListener(); + allocLoader.setReloadListener(confHolder); + allocLoader.reloadAllocations(); + AllocationConfiguration queueConf = confHolder.allocConf; + + assertTrue("allowOversubscription is not set for queueA", + !queueConf.isOversubscriptionAllowed("root.queueA").isPresent()); + assertTrue("allowOversubscription is not set for queueA.child2", + !queueConf.isOversubscriptionAllowed("root.queueA.child2").isPresent()); + assertTrue("allowOversubscription is not set for queueB.child1", + !queueConf.isOversubscriptionAllowed("root.queueB.child1").isPresent()); + + assertTrue("allowOversubscription is set for queueB", + queueConf.isOversubscriptionAllowed("root.queueB").isPresent()); + assertTrue("queueB does allow oversubscription", + queueConf.isOversubscriptionAllowed("root.queueB").get()); + assertTrue("allowOversubscription is set for queueB.child2", + queueConf.isOversubscriptionAllowed("root.queueB.child2").isPresent()); + assertTrue("queueB.child2 does not allow oversubscription", + !queueConf.isOversubscriptionAllowed("root.queueB.child2").get()); + + assertTrue("allowOversubscription is set for queueA.child1", + queueConf.isOversubscriptionAllowed("root.queueA.child1").isPresent()); + assertTrue("queueA.child1 does not allow oversubscription", + !queueConf.isOversubscriptionAllowed("root.queueA.child1").get()); + + } + + @Test public void testSimplePlacementPolicyFromConf() throws Exception { Configuration conf = new Configuration(); conf.set(FairSchedulerConfiguration.ALLOCATION_FILE, ALLOC_FILE); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java index 10cf317..ca1c60c 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestFairScheduler.java @@ -2783,6 +2783,118 @@ public void testResourceRequestOptOutOfOversubscription() throws Exception { } } + @Test + public void testQueueOptOutOfOversubscription() throws IOException { + conf.setBoolean(YarnConfiguration.RM_SCHEDULER_OVERSUBSCRIPTION_ENABLED, + true); + // disable resource request normalization in fair scheduler + int memoryAllocationIncrement = conf.getInt( + FairSchedulerConfiguration.RM_SCHEDULER_INCREMENT_ALLOCATION_MB, + FairSchedulerConfiguration. + DEFAULT_RM_SCHEDULER_INCREMENT_ALLOCATION_MB); + conf.setInt( + FairSchedulerConfiguration.RM_SCHEDULER_INCREMENT_ALLOCATION_MB, 1); + int memoryAllocationMinimum = conf.getInt( + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB, + YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB); + conf.setInt(YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB, 1); + + try { + scheduler.init(conf); + scheduler.start(); + scheduler.reinitialize(conf, resourceManager.getRMContext()); + + FSLeafQueue queue1 = + scheduler.getQueueManager().getLeafQueue("queue1", true); + // queue 2 has opted out of oversubscription + FSLeafQueue queue2 = + scheduler.getQueueManager().getLeafQueue("queue2", true); + queue2.allowOversubscription(false); + + FSParentQueue queue3 + = scheduler.getQueueManager().getParentQueue("queue3", true); + // queue 3 has opted out of oversubscription + queue3.allowOversubscription(false); + FSLeafQueue queue4 = + scheduler.getQueueManager().getLeafQueue("queue3.queue4", true); + assertTrue("queue 4 should inherit the setting from queue 3", + !queue4.isOversubscriptionAllowed()); + + + // Add a node with 4G of memory and 4 vcores and an overallocation + // threshold of 0.75f and 0.75f for memory and cpu respectively + OverAllocationInfo overAllocationInfo = OverAllocationInfo.newInstance( + ResourceThresholds.newInstance(0.75f, 0.75f)); + MockNodes.MockRMNodeImpl node = MockNodes.newNodeInfo(1, + Resources.createResource(4096, 4), overAllocationInfo); + scheduler.handle(new NodeAddedSchedulerEvent(node)); + + // create a scheduling request in queue1 that leaves some unallocated resources + ApplicationAttemptId appAttempt1 = + createSchedulingRequest(3600, "queue1", "user1", 1, false); + scheduler.handle(new NodeUpdateSchedulerEvent(node)); + assertEquals(3600, scheduler.getQueueManager().getQueue("queue1"). + getGuaranteedResourceUsage().getMemorySize()); + List allocatedContainers1 = + scheduler.getSchedulerApp(appAttempt1).pullNewlyAllocatedContainers(); + assertTrue(allocatedContainers1.size() == 1); + assertEquals("unexpected container execution type", + ExecutionType.GUARANTEED, + allocatedContainers1.get(0).getExecutionType()); + + // node utilization is low after the container runs on the node + ContainerStatus containerStatus = ContainerStatus.newInstance( + allocatedContainers1.get(0).getId(), ContainerState.RUNNING, "", + ContainerExitStatus.SUCCESS); + node.updateContainersAndNodeUtilization( + new UpdatedContainerInfo(Collections.singletonList(containerStatus), + Collections.emptyList()), + ResourceUtilization.newInstance(1024, 0, 0.1f)); + + // create another scheduling request in queue 2 that has opted out of + // oversubscription. + ApplicationAttemptId appAttempt2 = + createSchedulingRequest(1536, "queue2", "user1", 1, false); + scheduler.handle(new NodeUpdateSchedulerEvent(node)); + assertEquals(0, scheduler.getQueueManager().getQueue("queue2"). + getGuaranteedResourceUsage().getMemorySize()); + List allocatedContainers2 = + scheduler.getSchedulerApp(appAttempt2).pullNewlyAllocatedContainers(); + assertTrue(allocatedContainers2.size() == 0); + + // verify that a reservation is made for the second request + assertTrue("A reservation should be made for the second request", + scheduler.getNode(node.getNodeID()).getReservedContainer(). + getReservedResource().equals(Resource.newInstance(1536, 1))); + + // create another scheduling request in queue 4 that has opted out of + // oversubscription. + ApplicationAttemptId appAttempt3 = + createSchedulingRequest(1536, "queue3.queue4", "user1", 1, false); + scheduler.handle(new NodeUpdateSchedulerEvent(node)); + assertEquals(0, scheduler.getQueueManager().getQueue("queue3.queue4"). + getGuaranteedResourceUsage().getMemorySize()); + List allocatedContainers3 = + scheduler.getSchedulerApp(appAttempt3).pullNewlyAllocatedContainers(); + assertTrue(allocatedContainers3.size() == 0); + } finally { + conf.setBoolean(YarnConfiguration.RM_SCHEDULER_OVERSUBSCRIPTION_ENABLED, + false); + conf.setInt(YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB, + memoryAllocationMinimum); + conf.setInt( + FairSchedulerConfiguration.RM_SCHEDULER_INCREMENT_ALLOCATION_MB, + memoryAllocationIncrement); + } + + } + + + @Test + public void testQueueOptInOversubscriptionByDefault() { + + } + /** * Test that NO OPPORTUNISTIC containers can be allocated on a node that * is fully allocated and with a very high utilization. diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestQueueManager.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestQueueManager.java index eb2d402..13e6760 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestQueueManager.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/TestQueueManager.java @@ -305,4 +305,77 @@ public void testCreateParentQueueAndParent() { assertEquals("createQueue() returned wrong queue", "root.queue1.queue2", q2.getName()); } + + /** + * Test queues created dynamically inherit the oversubscription setting + * from its parent queue, in which oversubscription is enabled. + */ + @Test + public void testCreateQueueWithParentOversubscriptionSettingsEnabled() { + AllocationConfiguration allocConf = scheduler.getAllocationConfiguration(); + + queueManager.updateAllocationConfiguration(allocConf); + + FSQueue q1 = queueManager.createQueue("root.queue1", + FSQueueType.PARENT); + + assertNotNull("Parent queue root.queue1 was not created", + queueManager.getParentQueue("root.queue1", false)); + assertEquals("createQueue() returned wrong queue", + "root.queue1", q1.getName()); + assertTrue("root queue should always allow oversubscription", + queueManager.getParentQueue("root", false).isOversubscriptionAllowed()); + assertTrue("root.queue1 should allow oversubscription as its parent", + queueManager.getParentQueue("root.queue1", false) + .isOversubscriptionAllowed()); + + FSQueue q2 = queueManager.createQueue("root.queue1.queue2", + FSQueueType.LEAF); + assertNotNull("Leaf queue root.queue1.queue2 was not created", + queueManager.getLeafQueue("root.queue1.queue2", false)); + assertEquals("createQueue() returned wrong queue", + "root.queue1.queue2", q2.getName()); + assertTrue("root.queue1.queue2 should allow oversubscription as its parent", + queueManager.getLeafQueue("root.queue1.queue2", false) + .isOversubscriptionAllowed()); + + } + + /** + * Test queues created dynamically inherit the oversubscription setting + * from its parent queue, in which oversubscription is disabled. + */ + @Test + public void testCreateQueueWithParentOversubscriptionSettingsDisabled() { + AllocationConfiguration allocConf = scheduler.getAllocationConfiguration(); + + queueManager.updateAllocationConfiguration(allocConf); + + FSQueue q1 = queueManager.createQueue("root.queue1", + FSQueueType.PARENT); + q1.allowOversubscription(false); + + assertNotNull("Parent queue root.queue1 was not created", + queueManager.getParentQueue("root.queue1", false)); + assertEquals("createQueue() returned wrong queue", + "root.queue1", q1.getName()); + + assertTrue("root queue should always allow oversubscription", + queueManager.getParentQueue("root", false).isOversubscriptionAllowed()); + assertTrue("root.queue1 should not allow oversubscription", + !queueManager.getParentQueue("root.queue1", false) + .isOversubscriptionAllowed()); + + FSQueue q2 = queueManager.createQueue("root.queue1.queue2", + FSQueueType.LEAF); + assertNotNull("Leaf queue root.queue1.queue2 was not created", + queueManager.getLeafQueue("root.queue1.queue2", false)); + assertEquals("createQueue() returned wrong queue", + "root.queue1.queue2", q2.getName()); + assertTrue( + "root.queue1.queue2 should not allow oversubscription as its parent", + !queueManager.getLeafQueue("root.queue1.queue2", false) + .isOversubscriptionAllowed()); + + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/FairScheduler.md hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/FairScheduler.md index e253d0d..c448107 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/FairScheduler.md +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/markdown/FairScheduler.md @@ -111,6 +111,8 @@ The allocation file must be in XML format. The format contains five types of ele * **fairSharePreemptionThreshold**: the fair share preemption threshold for the queue. If the queue waits fairSharePreemptionTimeout without receiving fairSharePreemptionThreshold\*fairShare resources, it is allowed to preempt containers to take resources from other queues. If not set, the queue will inherit the value from its parent queue. Default value is 0.5f. * **allowPreemptionFrom**: determines whether the scheduler is allowed to preempt resources from the queue. The default is true. If a queue has this property set to false, this property will apply recursively to all child queues. + + * **allowOversubscription**: determines whether the scheduler is allowed to assign OPPORTUNISTIC resources to applications running in the queue when over-subscription is turned on. The default is true. * **reservation**: indicates to the `ReservationSystem` that the queue's resources is available for users to reserve. This only applies for leaf queues. A leaf queue is not reservable if this property isn't configured.