From 8f48f67d8c4efd85470951c1f07162d9be92b75c Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Wed, 6 Jul 2011 22:30:42 +0200
Subject: [PATCH] htools: add optional limit to allocation count

Currently, the tieredAlloc/iterateAlloc functions will not return
until the allocation fails; this means unit-testing their
functionality (e.g. that an instance can be allocated) is slow, since
they will allocate all possible instances.

This patch adds an optional limit that allows allocation to return
early; this makes the cluster unittests twice as fast.

Signed-off-by: Iustin Pop <iustin@google.com>
Reviewed-by: Guido Trotter <ultrotter@google.com>
---
 htools/Ganeti/HTools/Cluster.hs | 33 +++++++++++++++++++++++----------
 htools/Ganeti/HTools/QC.hs      |  4 ++--
 htools/hspace.hs                |  5 +++--
 3 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/htools/Ganeti/HTools/Cluster.hs b/htools/Ganeti/HTools/Cluster.hs
index fbca04a5d..42a91de5c 100644
--- a/htools/Ganeti/HTools/Cluster.hs
+++ b/htools/Ganeti/HTools/Cluster.hs
@@ -1036,45 +1036,58 @@ tryNodeEvac _ ini_nl ini_il mode idxs =
 -- | Recursively place instances on the cluster until we're out of space.
 iterateAlloc :: Node.List
              -> Instance.List
+             -> Maybe Int
              -> Instance.Instance
              -> AllocNodes
              -> [Instance.Instance]
              -> [CStats]
              -> Result AllocResult
-iterateAlloc nl il newinst allocnodes ixes cstats =
+iterateAlloc nl il limit newinst allocnodes ixes cstats =
       let depth = length ixes
           newname = printf "new-%d" depth::String
           newidx = length (Container.elems il) + depth
           newi2 = Instance.setIdx (Instance.setName newinst newname) newidx
+          newlimit = fmap (flip (-) 1) limit
       in case tryAlloc nl il newi2 allocnodes of
            Bad s -> Bad s
            Ok (AllocSolution { asFailures = errs, asSolutions = sols3 }) ->
+               let newsol = Ok (collapseFailures errs, nl, il, ixes, cstats) in
                case sols3 of
-                 [] -> Ok (collapseFailures errs, nl, il, ixes, cstats)
+                 [] -> newsol
                  (xnl, xi, _, _):[] ->
-                     iterateAlloc xnl (Container.add newidx xi il)
-                                  newinst allocnodes (xi:ixes)
-                                  (totalResources xnl:cstats)
+                     if limit == Just 0
+                     then newsol
+                     else iterateAlloc xnl (Container.add newidx xi il)
+                          newlimit newinst allocnodes (xi:ixes)
+                          (totalResources xnl:cstats)
                  _ -> Bad "Internal error: multiple solutions for single\
                           \ allocation"
 
 -- | The core of the tiered allocation mode.
 tieredAlloc :: Node.List
             -> Instance.List
+            -> Maybe Int
             -> Instance.Instance
             -> AllocNodes
             -> [Instance.Instance]
             -> [CStats]
             -> Result AllocResult
-tieredAlloc nl il newinst allocnodes ixes cstats =
-    case iterateAlloc nl il newinst allocnodes ixes cstats of
+tieredAlloc nl il limit newinst allocnodes ixes cstats =
+    case iterateAlloc nl il limit newinst allocnodes ixes cstats of
       Bad s -> Bad s
       Ok (errs, nl', il', ixes', cstats') ->
+          let newsol = Ok (errs, nl', il', ixes', cstats')
+              ixes_cnt = length ixes'
+              (stop, newlimit) = case limit of
+                                   Nothing -> (False, Nothing)
+                                   Just n -> (n <= ixes_cnt,
+                                              Just (n - ixes_cnt)) in
+          if stop then newsol else
           case Instance.shrinkByType newinst . fst . last $
                sortBy (comparing snd) errs of
-            Bad _ -> Ok (errs, nl', il', ixes', cstats')
-            Ok newinst' ->
-                tieredAlloc nl' il' newinst' allocnodes ixes' cstats'
+            Bad _ -> newsol
+            Ok newinst' -> tieredAlloc nl' il' newlimit
+                           newinst' allocnodes ixes' cstats'
 
 -- | Compute the tiered spec string description from a list of
 -- allocated instances.
diff --git a/htools/Ganeti/HTools/QC.hs b/htools/Ganeti/HTools/QC.hs
index 4e38a31f1..56ba8be93 100644
--- a/htools/Ganeti/HTools/QC.hs
+++ b/htools/Ganeti/HTools/QC.hs
@@ -866,7 +866,7 @@ prop_ClusterCanTieredAlloc node inst =
         il = Container.empty
         allocnodes = Cluster.genAllocNodes defGroupList nl rqnodes True
     in case allocnodes >>= \allocnodes' ->
-        Cluster.tieredAlloc nl il inst allocnodes' [] [] of
+        Cluster.tieredAlloc nl il (Just 1) inst allocnodes' [] [] of
          Types.Bad _ -> False
          Types.Ok (_, _, il', ixes, cstats) -> not (null ixes) &&
                                       IntMap.size il' == length ixes &&
@@ -909,7 +909,7 @@ prop_ClusterAllocBalance =
         allocnodes = Cluster.genAllocNodes defGroupList nl' 2 True
         i_templ = createInstance Types.unitMem Types.unitDsk Types.unitCpu
     in case allocnodes >>= \allocnodes' ->
-        Cluster.iterateAlloc nl' il i_templ allocnodes' [] [] of
+        Cluster.iterateAlloc nl' il (Just 5) i_templ allocnodes' [] [] of
          Types.Bad _ -> False
          Types.Ok (_, xnl, il', _, _) ->
                    let ynl = Container.add (Node.idx hnode) hnode xnl
diff --git a/htools/hspace.hs b/htools/hspace.hs
index 6b1a613ad..dec1bf703 100644
--- a/htools/hspace.hs
+++ b/htools/hspace.hs
@@ -302,7 +302,7 @@ main = do
        (_, trl_nl, trl_il, trl_ixes, _) <-
            if stop_allocation
            then return result_noalloc
-           else exitifbad (Cluster.tieredAlloc nl il (iofspec tspec)
+           else exitifbad (Cluster.tieredAlloc nl il Nothing (iofspec tspec)
                                   allocnodes [] [])
        let spec_map' = Cluster.tieredSpecMap trl_ixes
 
@@ -324,7 +324,8 @@ main = do
   (ereason, fin_nl, fin_il, ixes, _) <-
       if stop_allocation
       then return result_noalloc
-      else exitifbad (Cluster.iterateAlloc nl il reqinst allocnodes [] [])
+      else exitifbad (Cluster.iterateAlloc nl il Nothing
+                      reqinst allocnodes [] [])
 
   let allocs = length ixes
       sreason = reverse $ sortBy (comparing snd) ereason
-- 
GitLab