/// <summary>
        /// Checks to see whether any other applications runnable now that the given
        /// application has been removed from the given queue.
        /// </summary>
        /// <remarks>
        /// Checks to see whether any other applications runnable now that the given
        /// application has been removed from the given queue.  And makes them so.
        /// Runs in O(n log(n)) where n is the number of queues that are under the
        /// highest queue that went from having no slack to having slack.
        /// </remarks>
        public virtual void UpdateRunnabilityOnAppRemoval(FSAppAttempt app, FSLeafQueue queue
                                                          )
        {
            AllocationConfiguration allocConf = scheduler.GetAllocationConfiguration();
            // childqueueX might have no pending apps itself, but if a queue higher up
            // in the hierarchy parentqueueY has a maxRunningApps set, an app completion
            // in childqueueX could allow an app in some other distant child of
            // parentqueueY to become runnable.
            // An app removal will only possibly allow another app to become runnable if
            // the queue was already at its max before the removal.
            // Thus we find the ancestor queue highest in the tree for which the app
            // that was at its maxRunningApps before the removal.
            FSQueue highestQueueWithAppsNowRunnable = (queue.GetNumRunnableApps() == allocConf
                                                       .GetQueueMaxApps(queue.GetName()) - 1) ? queue : null;
            FSParentQueue parent = queue.GetParent();

            while (parent != null)
            {
                if (parent.GetNumRunnableApps() == allocConf.GetQueueMaxApps(parent.GetName()) -
                    1)
                {
                    highestQueueWithAppsNowRunnable = parent;
                }
                parent = parent.GetParent();
            }
            IList <IList <FSAppAttempt> > appsNowMaybeRunnable = new AList <IList <FSAppAttempt> >(
                );

            // Compile lists of apps which may now be runnable
            // We gather lists instead of building a set of all non-runnable apps so
            // that this whole operation can be O(number of queues) instead of
            // O(number of apps)
            if (highestQueueWithAppsNowRunnable != null)
            {
                GatherPossiblyRunnableAppLists(highestQueueWithAppsNowRunnable, appsNowMaybeRunnable
                                               );
            }
            string user           = app.GetUser();
            int    userNumRunning = usersNumRunnableApps[user];

            if (userNumRunning == null)
            {
                userNumRunning = 0;
            }
            if (userNumRunning == allocConf.GetUserMaxApps(user) - 1)
            {
                IList <FSAppAttempt> userWaitingApps = usersNonRunnableApps.Get(user);
                if (userWaitingApps != null)
                {
                    appsNowMaybeRunnable.AddItem(userWaitingApps);
                }
            }
            UpdateAppsRunnability(appsNowMaybeRunnable, appsNowMaybeRunnable.Count);
        }
        public virtual void TestRemoveDoesNotEnableAnyApp()
        {
            FSLeafQueue leaf1 = queueManager.GetLeafQueue("root.queue1", true);
            FSLeafQueue leaf2 = queueManager.GetLeafQueue("root.queue2", true);

            queueMaxApps["root"]        = 2;
            queueMaxApps["root.queue1"] = 1;
            queueMaxApps["root.queue2"] = 1;
            FSAppAttempt app1 = AddApp(leaf1, "user");

            AddApp(leaf2, "user");
            AddApp(leaf2, "user");
            NUnit.Framework.Assert.AreEqual(1, leaf1.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumNonRunnableApps());
            RemoveApp(app1);
            NUnit.Framework.Assert.AreEqual(0, leaf1.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumNonRunnableApps());
        }
        public virtual void TestRemoveEnablesAppOnCousinQueue()
        {
            FSLeafQueue leaf1 = queueManager.GetLeafQueue("root.queue1.subqueue1.leaf1", true
                                                          );
            FSLeafQueue leaf2 = queueManager.GetLeafQueue("root.queue1.subqueue2.leaf2", true
                                                          );

            queueMaxApps["root.queue1"] = 2;
            FSAppAttempt app1 = AddApp(leaf1, "user");

            AddApp(leaf2, "user");
            AddApp(leaf2, "user");
            NUnit.Framework.Assert.AreEqual(1, leaf1.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumNonRunnableApps());
            RemoveApp(app1);
            NUnit.Framework.Assert.AreEqual(0, leaf1.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(2, leaf2.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(0, leaf2.GetNumNonRunnableApps());
        }
        public virtual void TestRemoveEnablesOneByQueueOneByUser()
        {
            FSLeafQueue leaf1 = queueManager.GetLeafQueue("root.queue1.leaf1", true);
            FSLeafQueue leaf2 = queueManager.GetLeafQueue("root.queue1.leaf2", true);

            queueMaxApps["root.queue1.leaf1"] = 2;
            userMaxApps["user1"] = 1;
            FSAppAttempt app1 = AddApp(leaf1, "user1");

            AddApp(leaf1, "user2");
            AddApp(leaf1, "user3");
            AddApp(leaf2, "user1");
            NUnit.Framework.Assert.AreEqual(2, leaf1.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf1.GetNumNonRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumNonRunnableApps());
            RemoveApp(app1);
            NUnit.Framework.Assert.AreEqual(2, leaf1.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(1, leaf2.GetNumRunnableApps());
            NUnit.Framework.Assert.AreEqual(0, leaf1.GetNumNonRunnableApps());
            NUnit.Framework.Assert.AreEqual(0, leaf2.GetNumNonRunnableApps());
        }