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/fair/FSQueue.java b/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 cca08756184..cea4de9de39 100644 --- a/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 +++ b/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 @@ -398,6 +398,11 @@ private void updatePreemptionVariables() { // If the parent is non-preemptable, this queue is non-preemptable as well, // otherwise get the value from the allocation file. if (parent != null && !parent.isPreemptable()) { + if (this.isPreemptable()) { + LOG.warn(String.format("Attemping to make queue '%s'preemtable" + + " when its parent '%s' is not. Will override.", + this.getName(), parent.getName())); + } preemptable = false; } else { preemptable = scheduler.getAllocationConfiguration() @@ -575,6 +580,45 @@ public boolean verifyAndSetPolicyFromConf(AllocationConfiguration queueConf) { return true; } + /** + * Recursively check max values for queues in pre-order. Get queue values + * from the allocation file instead of properties of {@link FSQueue} objects. + * This method is invoked while reloading the allocation file. + * + * @param queueConf allocation configuration + */ + public void verifyMaxValuesFromConf(AllocationConfiguration queueConf) { + Resource maxResources = queueConf.getMaxResources(name).getResource(); + int maxRunningApps = queueConf.getQueueMaxApps(name); + Resource maxContainerAllocation = queueConf + .getQueueMaxContainerAllocation(name); + String warning = "The value for %s in queue %s " + + "exceeds that of its parent."; + + for (FSQueue child : getChildQueues()) { + Resource childResources = + queueConf.getMaxResources(child.getName()).getResource(); + int childRunningApps = queueConf.getQueueMaxApps(child.getName()); + Resource childContainerAllocation = queueConf + .getQueueMaxContainerAllocation(child.getName()); + + if (maxResources.getMemorySize() < childResources.getMemorySize() || + maxResources.getVirtualCores() < childResources.getVirtualCores()) { + LOG.warn(String.format(warning, "max resources", child.getName())); + } + if (maxRunningApps < childRunningApps) { + LOG.warn(String.format(warning, "max running apps", child.getName())); + } + if (maxContainerAllocation.getMemorySize() < + childContainerAllocation.getMemorySize() || + maxContainerAllocation.getVirtualCores() < + childContainerAllocation.getVirtualCores()) { + LOG.warn(String.format(warning, "max container allocation", child.getName())); + } + child.verifyMaxValuesFromConf(queueConf); + } + } + /** * Recursively dump states of all queues. * 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/fair/QueueManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java index 4fe38d5b0c8..975240ac72a 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/QueueManager.java @@ -601,6 +601,9 @@ public void updateAllocationConfiguration(AllocationConfiguration queueConf) { if (!rootQueue.verifyAndSetPolicyFromConf(queueConf)) { LOG.error("Setting scheduling policies for existing queues failed!"); } + // Verify that parent queues have greater than or equal to max values. + // Logged warnings will show where child values are higher. + rootQueue.verifyMaxValuesFromConf(queueConf); ensureQueueExistsAndIsCompatibleAndIsStatic(queueConf, FSQueueType.LEAF); 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/fair/TestQueueManager.java b/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 a521b3a3c92..6e17daf3f08 100644 --- a/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 +++ b/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 @@ -37,6 +37,13 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import org.apache.log4j.AppenderSkeleton; +import org.apache.log4j.Logger; +import org.apache.log4j.spi.LoggingEvent; +import org.mockito.ArgumentCaptor; /** * Test the {@link FairScheduler} queue manager correct queue hierarchies @@ -720,4 +727,72 @@ public void testRemoveSplitHierarchy() { p = queueManager.getParentQueue("root.p1", false); assertNull("root.p1 does exist", p); } + + @Test + public void testWarningOnChildQueueExceedParent() + throws Exception { + AppenderSkeleton appender = mock(AppenderSkeleton.class); + ArgumentCaptor logCaptor = + ArgumentCaptor.forClass(LoggingEvent.class); + Logger.getRootLogger().addAppender(appender); + + AllocationConfiguration allConf = mock(AllocationConfiguration.class); + ConfigurableResource cr1 = mock(ConfigurableResource.class); + when(allConf.getMaxResources(eq("root"))).thenReturn(cr1); + when(cr1.getResource()).thenReturn(Resources.createResource(2048,64)); + when(allConf.getQueueMaxContainerAllocation(eq("root"))) + .thenReturn(Resources.createResource(1024,32)); + when(allConf.getQueueMaxApps(eq("root"))).thenReturn(24); + + ConfigurableResource cr2 = mock(ConfigurableResource.class); + when(allConf.getMaxResources(eq("root.default"))).thenReturn(cr2); + when(cr2.getResource()).thenReturn(Resources.createResource(4096,96)); + when(allConf.getQueueMaxContainerAllocation(eq("root.default"))) + .thenReturn(Resources.createResource(2048,64)); + when(allConf.getQueueMaxApps(eq("root.default"))).thenReturn(36); + + ConfigurableResource cr3 = mock(ConfigurableResource.class); + when(allConf.getMaxResources(eq("root.test"))).thenReturn(cr3); + when(cr3.getResource()).thenReturn(Resources.createResource(2048,64)); + when(allConf.getQueueMaxContainerAllocation(eq("root.test"))) + .thenReturn(Resources.createResource(1024,32)); + when(allConf.getQueueMaxApps(eq("root.test"))).thenReturn(24); + + ConfigurableResource cr4 = mock(ConfigurableResource.class); + when(allConf.getMaxResources(eq("root.test.childA"))).thenReturn(cr4); + when(cr4.getResource()).thenReturn(Resources.createResource(2048,64)); + when(allConf.getQueueMaxContainerAllocation(eq("root.test.childA"))) + .thenReturn(Resources.createResource(1024,32)); + when(allConf.getQueueMaxApps(eq("root.test.childA"))).thenReturn(24); + + ConfigurableResource cr5 = mock(ConfigurableResource.class); + when(allConf.getMaxResources(eq("root.test.childB"))).thenReturn(cr5); + when(cr5.getResource()).thenReturn(Resources.createResource(2048,64)); + when(allConf.getQueueMaxContainerAllocation(eq("root.test.childB"))) + .thenReturn(Resources.createResource(1024,32)); + when(allConf.getQueueMaxApps(eq("root.test.childB"))).thenReturn(24); + + when(allConf.getSchedulingPolicy(any(String.class))) + .thenReturn(SchedulingPolicy.DEFAULT_POLICY); + Map> configuredQueues = mock(Map.class); + when(allConf.getConfiguredQueues()).thenReturn(configuredQueues); + when(configuredQueues.get(any(FSQueueType.class))) + .thenReturn(new HashSet<>()); + + queueManager.updateAllocationConfiguration(allConf); + + verify(appender, times(3)).doAppend(logCaptor.capture()); + List loggingEvents = logCaptor.getAllValues(); + assertEquals("Warning message should have been logged for max resources", + "The value for max resources in queue root.default exceeds that of " + + "its parent.", loggingEvents.get(0).getRenderedMessage()); + assertEquals("Warning message should have been logged for max running apps", + "The value for max running apps in queue root.default exceeds that " + + "of its parent.", loggingEvents.get(1).getRenderedMessage()); + assertEquals("Warning message should have been logged for max container " + + "allocation", "The value for max container allocation in queue " + + "root.default exceeds that of its parent.", + loggingEvents.get(2).getRenderedMessage()); + + } }