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/FairScheduler.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java index 15e2318..e39edd8 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/FairScheduler.java @@ -1683,22 +1683,33 @@ private void verifyMoveDoesNotViolateConstraints(FSAppAttempt app, */ private void executeMove(SchedulerApplication app, FSAppAttempt attempt, FSLeafQueue oldQueue, FSLeafQueue newQueue) { - boolean wasRunnable = oldQueue.removeApp(attempt); // if app was not runnable before, it may be runnable now - boolean nowRunnable = maxRunningEnforcer.canAppBeRunnable(newQueue, - attempt.getUser()); + boolean wasRunnable = oldQueue.isRunnableApp(attempt); + boolean nowRunnable; + if (wasRunnable) { + // If the app was runnable, don't need to check whether exceeding the user + // max apps since move a runnable app will not affect user's running app + // number. + nowRunnable = !maxRunningEnforcer.exceedQueueMaxRunningApps(newQueue); + } else { + nowRunnable = maxRunningEnforcer.canAppBeRunnable(newQueue, + attempt.getUser()); + } + + // move cannot change an app from runnable to non-runnable if (wasRunnable && !nowRunnable) { throw new IllegalStateException("Should have already verified that app " + attempt.getApplicationId() + " would be runnable in new queue"); } - + if (wasRunnable) { maxRunningEnforcer.untrackRunnableApp(attempt); } else if (nowRunnable) { // App has changed from non-runnable to runnable maxRunningEnforcer.untrackNonRunnableApp(attempt); } - + + oldQueue.removeApp(attempt); attempt.move(newQueue); // This updates all the metrics app.setQueue(newQueue); newQueue.addApp(attempt, nowRunnable); 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/MaxRunningAppsEnforcer.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/MaxRunningAppsEnforcer.java index 8592fa6..5ffc17f 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/MaxRunningAppsEnforcer.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/fair/MaxRunningAppsEnforcer.java @@ -56,23 +56,39 @@ public MaxRunningAppsEnforcer(FairScheduler scheduler) { * maxRunningApps limits. */ public boolean canAppBeRunnable(FSQueue queue, String user) { + return !exceedUserMaxApps(user) && !exceedQueueMaxRunningApps(queue); + } + + /** + * Checks whether the number of user runnable apps exceeds the limitation. + */ + public boolean exceedUserMaxApps(String user) { AllocationConfiguration allocConf = scheduler.getAllocationConfiguration(); Integer userNumRunnable = usersNumRunnableApps.get(user); if (userNumRunnable == null) { userNumRunnable = 0; } if (userNumRunnable >= allocConf.getUserMaxApps(user)) { - return false; + return true; } + + return false; + } + + /** + * Recursively checks whether the number of queue runnable apps exceeds the + * limitation. + */ + public boolean exceedQueueMaxRunningApps(FSQueue queue) { // Check queue and all parent queues while (queue != null) { if (queue.getNumRunnableApps() >= queue.getMaxRunningApps()) { - return false; + return true; } queue = queue.getParent(); } - return true; + return false; } /**