Currently, iterateAlloc tries one guess on the remaining capacity
and falls back to small steps if that guess turns out to be too
optimistic. In the typical case, that the allocation is bound by
memory that initial guess works quite well; however, in some cases
other requirements limit the amount of instances allocatable on a
cluster. Instead of immediately giving up in this case, try smaller
guess-and-verify steps to avoid having to check for global N+1 redundancy
too often.

Signed-off-by: Klaus Aehlig <[email protected]>
---
 src/Ganeti/HTools/Cluster.hs | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/Ganeti/HTools/Cluster.hs b/src/Ganeti/HTools/Cluster.hs
index adfe87d..98b4731 100644
--- a/src/Ganeti/HTools/Cluster.hs
+++ b/src/Ganeti/HTools/Cluster.hs
@@ -785,7 +785,7 @@ guessBigstepSize nl inst =
       -- however, at every node we might lose almost an instance if it just
       -- doesn't fit by a tiny margin
       guess = capacity - Container.size nl
-  in if guess < 10 then 10 else guess
+  in if guess < 20 then 20 else guess
 
 -- | A speed-up version of `iterateAllocSmallStep`.
 --
@@ -795,11 +795,17 @@ guessBigstepSize nl inst =
 -- if the result of this is globally N+1 redundant, then everything was OK
 -- inbetween and we can continue from there. Only if that fails, do a
 -- step-by-step iterative allocation.
-iterateAlloc :: AlgorithmOptions -> AllocMethod
-iterateAlloc opts nl il limit newinst allocnodes ixes cstats =
+-- In order to further speed up the computation while keeping it robust, we
+-- first try (if the first argument is True) a number of steps guessed from
+-- the node capacity, then, if that failed, a fixed step size and only as last
+-- restort step-by-step iterative allocation.
+iterateAlloc' :: Bool -> AlgorithmOptions -> AllocMethod
+iterateAlloc' tryHugestep opts nl il limit newinst allocnodes ixes cstats =
   if not $ algCapacity opts
     then iterateAllocSmallStep opts nl il limit newinst allocnodes ixes cstats
-    else let bigstepsize = guessBigstepSize nl newinst
+    else let bigstepsize = if tryHugestep
+                             then guessBigstepSize nl newinst
+                             else 10
              (limit', newlimit) = maybe (Just bigstepsize, Nothing)
                                     (Just . min bigstepsize
                                      &&& Just . max 0 . flip (-) bigstepsize)
@@ -811,10 +817,17 @@ iterateAlloc opts nl il limit newinst allocnodes ixes 
cstats =
             Ok res@(_, nl', il', ixes', cstats') | redundant nl' il' ->
               if newlimit == Just 0 || length ixes' == length ixes
                 then return res
-                else iterateAlloc opts nl' il' newlimit newinst allocnodes
-                                  ixes' cstats'
-            _ -> iterateAllocSmallStep opts nl il limit newinst allocnodes
-                                       ixes cstats
+                else iterateAlloc' tryHugestep opts nl' il' newlimit newinst
+                                   allocnodes ixes' cstats'
+            _ -> if tryHugestep
+                   then iterateAlloc' False opts nl il limit newinst allocnodes
+                                      ixes cstats
+                   else iterateAllocSmallStep opts nl il limit newinst
+                                              allocnodes ixes cstats
+
+-- | A speed-up version of `iterateAllocSmallStep`.
+iterateAlloc :: AlgorithmOptions -> AllocMethod
+iterateAlloc = iterateAlloc' True
 
 -- | Predicate whether shrinking a single resource can lead to a valid
 -- allocation.
-- 
2.4.3.573.g4eafbef

Reply via email to