Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Cluster.hs @ 446d8827

History | View | Annotate | Download (24.7 kB)

1 e4f08c46 Iustin Pop
{-| Implementation of cluster-wide logic.
2 e4f08c46 Iustin Pop
3 e4f08c46 Iustin Pop
This module holds all pure cluster-logic; I\/O related functionality
4 7ae514ba Iustin Pop
goes into the "Main" module for the individual binaries.
5 e4f08c46 Iustin Pop
6 e4f08c46 Iustin Pop
-}
7 e4f08c46 Iustin Pop
8 669d7e3d Iustin Pop
module Ganeti.HTools.Cluster
9 e4f08c46 Iustin Pop
    (
10 e4f08c46 Iustin Pop
     -- * Types
11 e4f08c46 Iustin Pop
     NodeList
12 e4f08c46 Iustin Pop
    , InstanceList
13 740ec004 Iustin Pop
    , NameList
14 e4f08c46 Iustin Pop
    , Placement
15 e4f08c46 Iustin Pop
    , Solution(..)
16 e4f08c46 Iustin Pop
    , Table(..)
17 e4f08c46 Iustin Pop
    , Removal
18 b0517d61 Iustin Pop
    , Score
19 e4f08c46 Iustin Pop
    -- * Generic functions
20 e4f08c46 Iustin Pop
    , totalResources
21 e4f08c46 Iustin Pop
    -- * First phase functions
22 e4f08c46 Iustin Pop
    , computeBadItems
23 e4f08c46 Iustin Pop
    -- * Second phase functions
24 e4f08c46 Iustin Pop
    , computeSolution
25 e4f08c46 Iustin Pop
    , applySolution
26 e4f08c46 Iustin Pop
    , printSolution
27 7dfaafb1 Iustin Pop
    , printSolutionLine
28 142538ff Iustin Pop
    , formatCmds
29 e4f08c46 Iustin Pop
    , printNodes
30 e4f08c46 Iustin Pop
    -- * Balacing functions
31 e4f08c46 Iustin Pop
    , checkMove
32 e4f08c46 Iustin Pop
    , compCV
33 e4f08c46 Iustin Pop
    , printStats
34 e4f08c46 Iustin Pop
    ) where
35 e4f08c46 Iustin Pop
36 e4f08c46 Iustin Pop
import Data.List
37 e4f08c46 Iustin Pop
import Data.Maybe (isNothing, fromJust)
38 e4f08c46 Iustin Pop
import Text.Printf (printf)
39 e4f08c46 Iustin Pop
import Data.Function
40 9d3fada5 Iustin Pop
import Control.Monad
41 e4f08c46 Iustin Pop
42 669d7e3d Iustin Pop
import qualified Ganeti.HTools.Container as Container
43 669d7e3d Iustin Pop
import qualified Ganeti.HTools.Instance as Instance
44 669d7e3d Iustin Pop
import qualified Ganeti.HTools.Node as Node
45 e4c5beaf Iustin Pop
import Ganeti.HTools.Types
46 669d7e3d Iustin Pop
import Ganeti.HTools.Utils
47 e4f08c46 Iustin Pop
48 7ae514ba Iustin Pop
-- | A separate name for the cluster score type
49 e4f08c46 Iustin Pop
type Score = Double
50 e4f08c46 Iustin Pop
51 e4f08c46 Iustin Pop
-- | The description of an instance placement.
52 c5c295bc Iustin Pop
type Placement = (Int, Int, Int, Score)
53 e4f08c46 Iustin Pop
54 e4f08c46 Iustin Pop
{- | A cluster solution described as the solution delta and the list
55 e4f08c46 Iustin Pop
of placements.
56 e4f08c46 Iustin Pop
57 e4f08c46 Iustin Pop
-}
58 e4f08c46 Iustin Pop
data Solution = Solution Int [Placement]
59 e4f08c46 Iustin Pop
                deriving (Eq, Ord, Show)
60 e4f08c46 Iustin Pop
61 e4f08c46 Iustin Pop
-- | Returns the delta of a solution or -1 for Nothing
62 e4f08c46 Iustin Pop
solutionDelta :: Maybe Solution -> Int
63 e4f08c46 Iustin Pop
solutionDelta sol = case sol of
64 e4f08c46 Iustin Pop
                      Just (Solution d _) -> d
65 e4f08c46 Iustin Pop
                      _ -> -1
66 e4f08c46 Iustin Pop
67 e4f08c46 Iustin Pop
-- | A removal set.
68 e4f08c46 Iustin Pop
data Removal = Removal NodeList [Instance.Instance]
69 e4f08c46 Iustin Pop
70 e4f08c46 Iustin Pop
-- | An instance move definition
71 00b51a14 Iustin Pop
data IMove = Failover                -- ^ Failover the instance (f)
72 19493d33 Iustin Pop
           | ReplacePrimary Int      -- ^ Replace primary (f, r:np, f)
73 19493d33 Iustin Pop
           | ReplaceSecondary Int    -- ^ Replace secondary (r:ns)
74 19493d33 Iustin Pop
           | ReplaceAndFailover Int  -- ^ Replace secondary, failover (r:np, f)
75 19493d33 Iustin Pop
           | FailoverAndReplace Int  -- ^ Failover, replace secondary (f, r:ns)
76 e4f08c46 Iustin Pop
             deriving (Show)
77 e4f08c46 Iustin Pop
78 e4f08c46 Iustin Pop
-- | The complete state for the balancing solution
79 e4f08c46 Iustin Pop
data Table = Table NodeList InstanceList Score [Placement]
80 e4f08c46 Iustin Pop
             deriving (Show)
81 e4f08c46 Iustin Pop
82 e4f08c46 Iustin Pop
-- General functions
83 e4f08c46 Iustin Pop
84 e4f08c46 Iustin Pop
-- | Cap the removal list if needed.
85 e4f08c46 Iustin Pop
capRemovals :: [a] -> Int -> [a]
86 e4f08c46 Iustin Pop
capRemovals removals max_removals =
87 e4f08c46 Iustin Pop
    if max_removals > 0 then
88 e4f08c46 Iustin Pop
        take max_removals removals
89 e4f08c46 Iustin Pop
    else
90 e4f08c46 Iustin Pop
        removals
91 e4f08c46 Iustin Pop
92 e4f08c46 Iustin Pop
-- | Check if the given node list fails the N+1 check.
93 e4f08c46 Iustin Pop
verifyN1Check :: [Node.Node] -> Bool
94 e4f08c46 Iustin Pop
verifyN1Check nl = any Node.failN1 nl
95 e4f08c46 Iustin Pop
96 e4f08c46 Iustin Pop
-- | Verifies the N+1 status and return the affected nodes.
97 e4f08c46 Iustin Pop
verifyN1 :: [Node.Node] -> [Node.Node]
98 e4f08c46 Iustin Pop
verifyN1 nl = filter Node.failN1 nl
99 e4f08c46 Iustin Pop
100 e4f08c46 Iustin Pop
{-| Add an instance and return the new node and instance maps. -}
101 e4f08c46 Iustin Pop
addInstance :: NodeList -> Instance.Instance ->
102 e4f08c46 Iustin Pop
               Node.Node -> Node.Node -> Maybe NodeList
103 e4f08c46 Iustin Pop
addInstance nl idata pri sec =
104 e4f08c46 Iustin Pop
  let pdx = Node.idx pri
105 e4f08c46 Iustin Pop
      sdx = Node.idx sec
106 e4f08c46 Iustin Pop
  in do
107 e4f08c46 Iustin Pop
      pnode <- Node.addPri pri idata
108 e4f08c46 Iustin Pop
      snode <- Node.addSec sec idata pdx
109 e4f08c46 Iustin Pop
      new_nl <- return $ Container.addTwo sdx snode
110 e4f08c46 Iustin Pop
                         pdx pnode nl
111 e4f08c46 Iustin Pop
      return new_nl
112 e4f08c46 Iustin Pop
113 e4f08c46 Iustin Pop
-- | Remove an instance and return the new node and instance maps.
114 e4f08c46 Iustin Pop
removeInstance :: NodeList -> Instance.Instance -> NodeList
115 e4f08c46 Iustin Pop
removeInstance nl idata =
116 e4f08c46 Iustin Pop
  let pnode = Instance.pnode idata
117 e4f08c46 Iustin Pop
      snode = Instance.snode idata
118 e4f08c46 Iustin Pop
      pn = Container.find pnode nl
119 e4f08c46 Iustin Pop
      sn = Container.find snode nl
120 e4f08c46 Iustin Pop
      new_nl = Container.addTwo
121 e4f08c46 Iustin Pop
               pnode (Node.removePri pn idata)
122 e4f08c46 Iustin Pop
               snode (Node.removeSec sn idata) nl in
123 e4f08c46 Iustin Pop
  new_nl
124 e4f08c46 Iustin Pop
125 e4f08c46 Iustin Pop
-- | Remove an instance and return the new node map.
126 e4f08c46 Iustin Pop
removeInstances :: NodeList -> [Instance.Instance] -> NodeList
127 e4f08c46 Iustin Pop
removeInstances = foldl' removeInstance
128 e4f08c46 Iustin Pop
129 e4f08c46 Iustin Pop
-- | Compute the total free disk and memory in the cluster.
130 e4f08c46 Iustin Pop
totalResources :: Container.Container Node.Node -> (Int, Int)
131 e4f08c46 Iustin Pop
totalResources nl =
132 e4f08c46 Iustin Pop
    foldl'
133 962367fe Iustin Pop
    (\ (mem, dsk) node -> (mem + (Node.f_mem node),
134 962367fe Iustin Pop
                           dsk + (Node.f_dsk node)))
135 e4f08c46 Iustin Pop
    (0, 0) (Container.elems nl)
136 e4f08c46 Iustin Pop
137 e4f08c46 Iustin Pop
{- | Compute a new version of a cluster given a solution.
138 e4f08c46 Iustin Pop
139 e4f08c46 Iustin Pop
This is not used for computing the solutions, but for applying a
140 e4f08c46 Iustin Pop
(known-good) solution to the original cluster for final display.
141 e4f08c46 Iustin Pop
142 e4f08c46 Iustin Pop
It first removes the relocated instances after which it places them on
143 e4f08c46 Iustin Pop
their new nodes.
144 e4f08c46 Iustin Pop
145 e4f08c46 Iustin Pop
 -}
146 e4f08c46 Iustin Pop
applySolution :: NodeList -> InstanceList -> [Placement] -> NodeList
147 e4f08c46 Iustin Pop
applySolution nl il sol =
148 c5c295bc Iustin Pop
    let odxes = map (\ (a, b, c, _) -> (Container.find a il,
149 c5c295bc Iustin Pop
                                        Node.idx (Container.find b nl),
150 c5c295bc Iustin Pop
                                        Node.idx (Container.find c nl))
151 e4f08c46 Iustin Pop
                    ) sol
152 e4f08c46 Iustin Pop
        idxes = (\ (x, _, _) -> x) (unzip3 odxes)
153 e4f08c46 Iustin Pop
        nc = removeInstances nl idxes
154 e4f08c46 Iustin Pop
    in
155 e4f08c46 Iustin Pop
      foldl' (\ nz (a, b, c) ->
156 e4f08c46 Iustin Pop
                 let new_p = Container.find b nz
157 e4f08c46 Iustin Pop
                     new_s = Container.find c nz in
158 e4f08c46 Iustin Pop
                 fromJust (addInstance nz a new_p new_s)
159 e4f08c46 Iustin Pop
           ) nc odxes
160 e4f08c46 Iustin Pop
161 e4f08c46 Iustin Pop
162 e4f08c46 Iustin Pop
-- First phase functions
163 e4f08c46 Iustin Pop
164 e4f08c46 Iustin Pop
{- | Given a list 1,2,3..n build a list of pairs [(1, [2..n]), (2,
165 e4f08c46 Iustin Pop
    [3..n]), ...]
166 e4f08c46 Iustin Pop
167 e4f08c46 Iustin Pop
-}
168 e4f08c46 Iustin Pop
genParts :: [a] -> Int -> [(a, [a])]
169 e4f08c46 Iustin Pop
genParts l count =
170 e4f08c46 Iustin Pop
    case l of
171 e4f08c46 Iustin Pop
      [] -> []
172 e4f08c46 Iustin Pop
      x:xs ->
173 e4f08c46 Iustin Pop
          if length l < count then
174 e4f08c46 Iustin Pop
              []
175 e4f08c46 Iustin Pop
          else
176 e4f08c46 Iustin Pop
              (x, xs) : (genParts xs count)
177 e4f08c46 Iustin Pop
178 e4f08c46 Iustin Pop
-- | Generates combinations of count items from the names list.
179 e4f08c46 Iustin Pop
genNames :: Int -> [b] -> [[b]]
180 e4f08c46 Iustin Pop
genNames count1 names1 =
181 e4f08c46 Iustin Pop
  let aux_fn count names current =
182 e4f08c46 Iustin Pop
          case count of
183 e4f08c46 Iustin Pop
            0 -> [current]
184 e4f08c46 Iustin Pop
            _ ->
185 e4f08c46 Iustin Pop
                concatMap
186 e4f08c46 Iustin Pop
                (\ (x, xs) -> aux_fn (count - 1) xs (x:current))
187 e4f08c46 Iustin Pop
                (genParts names count)
188 e4f08c46 Iustin Pop
  in
189 e4f08c46 Iustin Pop
    aux_fn count1 names1 []
190 e4f08c46 Iustin Pop
191 e4f08c46 Iustin Pop
{- | Computes the pair of bad nodes and instances.
192 e4f08c46 Iustin Pop
193 e4f08c46 Iustin Pop
The bad node list is computed via a simple 'verifyN1' check, and the
194 e4f08c46 Iustin Pop
bad instance list is the list of primary and secondary instances of
195 e4f08c46 Iustin Pop
those nodes.
196 e4f08c46 Iustin Pop
197 e4f08c46 Iustin Pop
-}
198 e4f08c46 Iustin Pop
computeBadItems :: NodeList -> InstanceList ->
199 e4f08c46 Iustin Pop
                   ([Node.Node], [Instance.Instance])
200 e4f08c46 Iustin Pop
computeBadItems nl il =
201 234d8af0 Iustin Pop
  let bad_nodes = verifyN1 $ filter (not . Node.offline) $ Container.elems nl
202 e4f08c46 Iustin Pop
      bad_instances = map (\idx -> Container.find idx il) $
203 e4f08c46 Iustin Pop
                      sort $ nub $ concat $
204 e4f08c46 Iustin Pop
                      map (\ n -> (Node.slist n) ++ (Node.plist n)) bad_nodes
205 e4f08c46 Iustin Pop
  in
206 e4f08c46 Iustin Pop
    (bad_nodes, bad_instances)
207 e4f08c46 Iustin Pop
208 e4f08c46 Iustin Pop
209 e4f08c46 Iustin Pop
{- | Checks if removal of instances results in N+1 pass.
210 e4f08c46 Iustin Pop
211 e4f08c46 Iustin Pop
Note: the check removal cannot optimize by scanning only the affected
212 e4f08c46 Iustin Pop
nodes, since the cluster is known to be not healthy; only the check
213 e4f08c46 Iustin Pop
placement can make this shortcut.
214 e4f08c46 Iustin Pop
215 e4f08c46 Iustin Pop
-}
216 e4f08c46 Iustin Pop
checkRemoval :: NodeList -> [Instance.Instance] -> Maybe Removal
217 e4f08c46 Iustin Pop
checkRemoval nl victims =
218 e4f08c46 Iustin Pop
  let nx = removeInstances nl victims
219 e4f08c46 Iustin Pop
      failN1 = verifyN1Check (Container.elems nx)
220 e4f08c46 Iustin Pop
  in
221 e4f08c46 Iustin Pop
    if failN1 then
222 e4f08c46 Iustin Pop
      Nothing
223 e4f08c46 Iustin Pop
    else
224 e4f08c46 Iustin Pop
      Just $ Removal nx victims
225 e4f08c46 Iustin Pop
226 e4f08c46 Iustin Pop
227 e4f08c46 Iustin Pop
-- | Computes the removals list for a given depth
228 669d7e3d Iustin Pop
computeRemovals :: NodeList
229 e4f08c46 Iustin Pop
                 -> [Instance.Instance]
230 e4f08c46 Iustin Pop
                 -> Int
231 669d7e3d Iustin Pop
                 -> [Maybe Removal]
232 e4f08c46 Iustin Pop
computeRemovals nl bad_instances depth =
233 e4f08c46 Iustin Pop
    map (checkRemoval nl) $ genNames depth bad_instances
234 e4f08c46 Iustin Pop
235 e4f08c46 Iustin Pop
-- Second phase functions
236 e4f08c46 Iustin Pop
237 e4f08c46 Iustin Pop
-- | Single-node relocation cost
238 e4f08c46 Iustin Pop
nodeDelta :: Int -> Int -> Int -> Int
239 e4f08c46 Iustin Pop
nodeDelta i p s =
240 e4f08c46 Iustin Pop
    if i == p || i == s then
241 e4f08c46 Iustin Pop
        0
242 e4f08c46 Iustin Pop
    else
243 e4f08c46 Iustin Pop
        1
244 e4f08c46 Iustin Pop
245 e4f08c46 Iustin Pop
{-| Compute best solution.
246 e4f08c46 Iustin Pop
247 e4f08c46 Iustin Pop
    This function compares two solutions, choosing the minimum valid
248 e4f08c46 Iustin Pop
    solution.
249 e4f08c46 Iustin Pop
-}
250 e4f08c46 Iustin Pop
compareSolutions :: Maybe Solution -> Maybe Solution -> Maybe Solution
251 e4f08c46 Iustin Pop
compareSolutions a b = case (a, b) of
252 e4f08c46 Iustin Pop
  (Nothing, x) -> x
253 e4f08c46 Iustin Pop
  (x, Nothing) -> x
254 e4f08c46 Iustin Pop
  (x, y) -> min x y
255 e4f08c46 Iustin Pop
256 e4f08c46 Iustin Pop
-- | Compute best table. Note that the ordering of the arguments is important.
257 e4f08c46 Iustin Pop
compareTables :: Table -> Table -> Table
258 e4f08c46 Iustin Pop
compareTables a@(Table _ _ a_cv _) b@(Table _ _ b_cv _ ) =
259 e4f08c46 Iustin Pop
    if a_cv > b_cv then b else a
260 e4f08c46 Iustin Pop
261 e4f08c46 Iustin Pop
-- | Check if a given delta is worse then an existing solution.
262 e4f08c46 Iustin Pop
tooHighDelta :: Maybe Solution -> Int -> Int -> Bool
263 e4f08c46 Iustin Pop
tooHighDelta sol new_delta max_delta =
264 e4f08c46 Iustin Pop
    if new_delta > max_delta && max_delta >=0 then
265 e4f08c46 Iustin Pop
        True
266 e4f08c46 Iustin Pop
    else
267 e4f08c46 Iustin Pop
        case sol of
268 e4f08c46 Iustin Pop
          Nothing -> False
269 e4f08c46 Iustin Pop
          Just (Solution old_delta _) -> old_delta <= new_delta
270 e4f08c46 Iustin Pop
271 e4f08c46 Iustin Pop
{-| Check if placement of instances still keeps the cluster N+1 compliant.
272 e4f08c46 Iustin Pop
273 e4f08c46 Iustin Pop
    This is the workhorse of the allocation algorithm: given the
274 e4f08c46 Iustin Pop
    current node and instance maps, the list of instances to be
275 e4f08c46 Iustin Pop
    placed, and the current solution, this will return all possible
276 e4f08c46 Iustin Pop
    solution by recursing until all target instances are placed.
277 e4f08c46 Iustin Pop
278 e4f08c46 Iustin Pop
-}
279 e4f08c46 Iustin Pop
checkPlacement :: NodeList            -- ^ The current node list
280 e4f08c46 Iustin Pop
               -> [Instance.Instance] -- ^ List of instances still to place
281 e4f08c46 Iustin Pop
               -> [Placement]         -- ^ Partial solution until now
282 e4f08c46 Iustin Pop
               -> Int                 -- ^ The delta of the partial solution
283 e4f08c46 Iustin Pop
               -> Maybe Solution      -- ^ The previous solution
284 e4f08c46 Iustin Pop
               -> Int                 -- ^ Abort if the we go above this delta
285 e4f08c46 Iustin Pop
               -> Maybe Solution      -- ^ The new solution
286 e4f08c46 Iustin Pop
checkPlacement nl victims current current_delta prev_sol max_delta =
287 e4f08c46 Iustin Pop
  let target = head victims
288 e4f08c46 Iustin Pop
      opdx = Instance.pnode target
289 e4f08c46 Iustin Pop
      osdx = Instance.snode target
290 e4f08c46 Iustin Pop
      vtail = tail victims
291 e4f08c46 Iustin Pop
      have_tail = (length vtail) > 0
292 e4f08c46 Iustin Pop
      nodes = Container.elems nl
293 c5c295bc Iustin Pop
      iidx = Instance.idx target
294 e4f08c46 Iustin Pop
  in
295 e4f08c46 Iustin Pop
    foldl'
296 e4f08c46 Iustin Pop
    (\ accu_p pri ->
297 e4f08c46 Iustin Pop
         let
298 e4f08c46 Iustin Pop
             pri_idx = Node.idx pri
299 e4f08c46 Iustin Pop
             upri_delta = current_delta + nodeDelta pri_idx opdx osdx
300 e4f08c46 Iustin Pop
             new_pri = Node.addPri pri target
301 e4f08c46 Iustin Pop
             fail_delta1 = tooHighDelta accu_p upri_delta max_delta
302 e4f08c46 Iustin Pop
         in
303 e4f08c46 Iustin Pop
           if fail_delta1 || isNothing(new_pri) then accu_p
304 e4f08c46 Iustin Pop
           else let pri_nl = Container.add pri_idx (fromJust new_pri) nl in
305 e4f08c46 Iustin Pop
                foldl'
306 e4f08c46 Iustin Pop
                (\ accu sec ->
307 e4f08c46 Iustin Pop
                     let
308 e4f08c46 Iustin Pop
                         sec_idx = Node.idx sec
309 e4f08c46 Iustin Pop
                         upd_delta = upri_delta +
310 e4f08c46 Iustin Pop
                                     nodeDelta sec_idx opdx osdx
311 e4f08c46 Iustin Pop
                         fail_delta2 = tooHighDelta accu upd_delta max_delta
312 e4f08c46 Iustin Pop
                         new_sec = Node.addSec sec target pri_idx
313 e4f08c46 Iustin Pop
                     in
314 e4f08c46 Iustin Pop
                       if sec_idx == pri_idx || fail_delta2 ||
315 e4f08c46 Iustin Pop
                          isNothing new_sec then accu
316 e4f08c46 Iustin Pop
                       else let
317 e4f08c46 Iustin Pop
                           nx = Container.add sec_idx (fromJust new_sec) pri_nl
318 c5c295bc Iustin Pop
                           upd_cv = compCV nx
319 c5c295bc Iustin Pop
                           plc = (iidx, pri_idx, sec_idx, upd_cv)
320 e4f08c46 Iustin Pop
                           c2 = plc:current
321 e4f08c46 Iustin Pop
                           result =
322 e4f08c46 Iustin Pop
                               if have_tail then
323 e4f08c46 Iustin Pop
                                   checkPlacement nx vtail c2 upd_delta
324 e4f08c46 Iustin Pop
                                                  accu max_delta
325 e4f08c46 Iustin Pop
                               else
326 e4f08c46 Iustin Pop
                                   Just (Solution upd_delta c2)
327 e4f08c46 Iustin Pop
                      in compareSolutions accu result
328 e4f08c46 Iustin Pop
                ) accu_p nodes
329 e4f08c46 Iustin Pop
    ) prev_sol nodes
330 e4f08c46 Iustin Pop
331 e4f08c46 Iustin Pop
-- | Apply a move
332 e4f08c46 Iustin Pop
applyMove :: NodeList -> Instance.Instance
333 e4f08c46 Iustin Pop
          -> IMove -> (Maybe NodeList, Instance.Instance, Int, Int)
334 00b51a14 Iustin Pop
-- Failover (f)
335 e4f08c46 Iustin Pop
applyMove nl inst Failover =
336 e4f08c46 Iustin Pop
    let old_pdx = Instance.pnode inst
337 e4f08c46 Iustin Pop
        old_sdx = Instance.snode inst
338 e4f08c46 Iustin Pop
        old_p = Container.find old_pdx nl
339 e4f08c46 Iustin Pop
        old_s = Container.find old_sdx nl
340 e4f08c46 Iustin Pop
        int_p = Node.removePri old_p inst
341 e4f08c46 Iustin Pop
        int_s = Node.removeSec old_s inst
342 b161386d Iustin Pop
        new_nl = do -- Maybe monad
343 b161386d Iustin Pop
          new_p <- Node.addPri int_s inst
344 b161386d Iustin Pop
          new_s <- Node.addSec int_p inst old_sdx
345 b161386d Iustin Pop
          return $ Container.addTwo old_pdx new_s old_sdx new_p nl
346 e4f08c46 Iustin Pop
    in (new_nl, Instance.setBoth inst old_sdx old_pdx, old_sdx, old_pdx)
347 e4f08c46 Iustin Pop
348 00b51a14 Iustin Pop
-- Replace the primary (f:, r:np, f)
349 e4f08c46 Iustin Pop
applyMove nl inst (ReplacePrimary new_pdx) =
350 e4f08c46 Iustin Pop
    let old_pdx = Instance.pnode inst
351 e4f08c46 Iustin Pop
        old_sdx = Instance.snode inst
352 e4f08c46 Iustin Pop
        old_p = Container.find old_pdx nl
353 e4f08c46 Iustin Pop
        old_s = Container.find old_sdx nl
354 e4f08c46 Iustin Pop
        tgt_n = Container.find new_pdx nl
355 e4f08c46 Iustin Pop
        int_p = Node.removePri old_p inst
356 e4f08c46 Iustin Pop
        int_s = Node.removeSec old_s inst
357 b161386d Iustin Pop
        new_nl = do -- Maybe monad
358 b161386d Iustin Pop
          new_p <- Node.addPri tgt_n inst
359 b161386d Iustin Pop
          new_s <- Node.addSec int_s inst new_pdx
360 b161386d Iustin Pop
          return $ Container.add new_pdx new_p $
361 b161386d Iustin Pop
                 Container.addTwo old_pdx int_p old_sdx new_s nl
362 e4f08c46 Iustin Pop
    in (new_nl, Instance.setPri inst new_pdx, new_pdx, old_sdx)
363 e4f08c46 Iustin Pop
364 00b51a14 Iustin Pop
-- Replace the secondary (r:ns)
365 e4f08c46 Iustin Pop
applyMove nl inst (ReplaceSecondary new_sdx) =
366 e4f08c46 Iustin Pop
    let old_pdx = Instance.pnode inst
367 e4f08c46 Iustin Pop
        old_sdx = Instance.snode inst
368 e4f08c46 Iustin Pop
        old_s = Container.find old_sdx nl
369 e4f08c46 Iustin Pop
        tgt_n = Container.find new_sdx nl
370 e4f08c46 Iustin Pop
        int_s = Node.removeSec old_s inst
371 b161386d Iustin Pop
        new_nl = Node.addSec tgt_n inst old_pdx >>=
372 b161386d Iustin Pop
                 \new_s -> return $ Container.addTwo new_sdx
373 b161386d Iustin Pop
                           new_s old_sdx int_s nl
374 e4f08c46 Iustin Pop
    in (new_nl, Instance.setSec inst new_sdx, old_pdx, new_sdx)
375 e4f08c46 Iustin Pop
376 00b51a14 Iustin Pop
-- Replace the secondary and failover (r:np, f)
377 79ac6b6f Iustin Pop
applyMove nl inst (ReplaceAndFailover new_pdx) =
378 79ac6b6f Iustin Pop
    let old_pdx = Instance.pnode inst
379 79ac6b6f Iustin Pop
        old_sdx = Instance.snode inst
380 79ac6b6f Iustin Pop
        old_p = Container.find old_pdx nl
381 79ac6b6f Iustin Pop
        old_s = Container.find old_sdx nl
382 79ac6b6f Iustin Pop
        tgt_n = Container.find new_pdx nl
383 79ac6b6f Iustin Pop
        int_p = Node.removePri old_p inst
384 79ac6b6f Iustin Pop
        int_s = Node.removeSec old_s inst
385 b161386d Iustin Pop
        new_nl = do -- Maybe monad
386 b161386d Iustin Pop
          new_p <- Node.addPri tgt_n inst
387 b161386d Iustin Pop
          new_s <- Node.addSec int_p inst new_pdx
388 b161386d Iustin Pop
          return $ Container.add new_pdx new_p $
389 b161386d Iustin Pop
                 Container.addTwo old_pdx new_s old_sdx int_s nl
390 79ac6b6f Iustin Pop
    in (new_nl, Instance.setBoth inst new_pdx old_pdx, new_pdx, old_pdx)
391 79ac6b6f Iustin Pop
392 19493d33 Iustin Pop
-- Failver and replace the secondary (f, r:ns)
393 19493d33 Iustin Pop
applyMove nl inst (FailoverAndReplace new_sdx) =
394 19493d33 Iustin Pop
    let old_pdx = Instance.pnode inst
395 19493d33 Iustin Pop
        old_sdx = Instance.snode inst
396 19493d33 Iustin Pop
        old_p = Container.find old_pdx nl
397 19493d33 Iustin Pop
        old_s = Container.find old_sdx nl
398 19493d33 Iustin Pop
        tgt_n = Container.find new_sdx nl
399 19493d33 Iustin Pop
        int_p = Node.removePri old_p inst
400 19493d33 Iustin Pop
        int_s = Node.removeSec old_s inst
401 b161386d Iustin Pop
        new_nl = do -- Maybe monad
402 b161386d Iustin Pop
          new_p <- Node.addPri int_s inst
403 b161386d Iustin Pop
          new_s <- Node.addSec tgt_n inst old_sdx
404 b161386d Iustin Pop
          return $ Container.add new_sdx new_s $
405 b161386d Iustin Pop
                 Container.addTwo old_sdx new_p old_pdx int_p nl
406 19493d33 Iustin Pop
    in (new_nl, Instance.setBoth inst old_sdx new_sdx, old_sdx, new_sdx)
407 19493d33 Iustin Pop
408 e4f08c46 Iustin Pop
checkSingleStep :: Table -- ^ The original table
409 e4f08c46 Iustin Pop
                -> Instance.Instance -- ^ The instance to move
410 e4f08c46 Iustin Pop
                -> Table -- ^ The current best table
411 e4f08c46 Iustin Pop
                -> IMove -- ^ The move to apply
412 e4f08c46 Iustin Pop
                -> Table -- ^ The final best table
413 e4f08c46 Iustin Pop
checkSingleStep ini_tbl target cur_tbl move =
414 e4f08c46 Iustin Pop
    let
415 e4f08c46 Iustin Pop
        Table ini_nl ini_il _ ini_plc = ini_tbl
416 0a0f2533 Iustin Pop
        (tmp_nl, new_inst, pri_idx, sec_idx) = applyMove ini_nl target move
417 e4f08c46 Iustin Pop
    in
418 e4f08c46 Iustin Pop
      if isNothing tmp_nl then cur_tbl
419 e4f08c46 Iustin Pop
      else
420 e4f08c46 Iustin Pop
          let tgt_idx = Instance.idx target
421 e4f08c46 Iustin Pop
              upd_nl = fromJust tmp_nl
422 e4f08c46 Iustin Pop
              upd_cvar = compCV upd_nl
423 e4f08c46 Iustin Pop
              upd_il = Container.add tgt_idx new_inst ini_il
424 0a0f2533 Iustin Pop
              upd_plc = (tgt_idx, pri_idx, sec_idx, upd_cvar):ini_plc
425 e4f08c46 Iustin Pop
              upd_tbl = Table upd_nl upd_il upd_cvar upd_plc
426 e4f08c46 Iustin Pop
          in
427 e4f08c46 Iustin Pop
            compareTables cur_tbl upd_tbl
428 e4f08c46 Iustin Pop
429 40d4eba0 Iustin Pop
-- | Given the status of the current secondary as a valid new node
430 40d4eba0 Iustin Pop
-- and the current candidate target node,
431 40d4eba0 Iustin Pop
-- generate the possible moves for a instance.
432 40d4eba0 Iustin Pop
possibleMoves :: Bool -> Int -> [IMove]
433 40d4eba0 Iustin Pop
possibleMoves True tdx =
434 40d4eba0 Iustin Pop
    [ReplaceSecondary tdx,
435 40d4eba0 Iustin Pop
     ReplaceAndFailover tdx,
436 40d4eba0 Iustin Pop
     ReplacePrimary tdx,
437 40d4eba0 Iustin Pop
     FailoverAndReplace tdx]
438 40d4eba0 Iustin Pop
439 40d4eba0 Iustin Pop
possibleMoves False tdx =
440 40d4eba0 Iustin Pop
    [ReplaceSecondary tdx,
441 40d4eba0 Iustin Pop
     ReplaceAndFailover tdx]
442 40d4eba0 Iustin Pop
443 40d4eba0 Iustin Pop
-- | Compute the best move for a given instance.
444 256810de Iustin Pop
checkInstanceMove :: [Int]             -- Allowed target node indices
445 256810de Iustin Pop
                  -> Table             -- Original table
446 256810de Iustin Pop
                  -> Instance.Instance -- Instance to move
447 256810de Iustin Pop
                  -> Table             -- Best new table for this instance
448 256810de Iustin Pop
checkInstanceMove nodes_idx ini_tbl target =
449 4e25d1c2 Iustin Pop
    let
450 4e25d1c2 Iustin Pop
        opdx = Instance.pnode target
451 4e25d1c2 Iustin Pop
        osdx = Instance.snode target
452 9dc6023f Iustin Pop
        nodes = filter (\idx -> idx /= opdx && idx /= osdx) nodes_idx
453 40d4eba0 Iustin Pop
        use_secondary = elem osdx nodes_idx
454 40d4eba0 Iustin Pop
        aft_failover = if use_secondary -- if allowed to failover
455 40d4eba0 Iustin Pop
                       then checkSingleStep ini_tbl target ini_tbl Failover
456 40d4eba0 Iustin Pop
                       else ini_tbl
457 40d4eba0 Iustin Pop
        all_moves = concatMap (possibleMoves use_secondary) nodes
458 4e25d1c2 Iustin Pop
    in
459 4e25d1c2 Iustin Pop
      -- iterate over the possible nodes for this instance
460 9dc6023f Iustin Pop
      foldl' (checkSingleStep ini_tbl target) aft_failover all_moves
461 4e25d1c2 Iustin Pop
462 e4f08c46 Iustin Pop
-- | Compute the best next move.
463 256810de Iustin Pop
checkMove :: [Int]               -- ^ Allowed target node indices
464 256810de Iustin Pop
          -> Table               -- ^ The current solution
465 e4f08c46 Iustin Pop
          -> [Instance.Instance] -- ^ List of instances still to move
466 256810de Iustin Pop
          -> Table               -- ^ The new solution
467 256810de Iustin Pop
checkMove nodes_idx ini_tbl victims =
468 4e25d1c2 Iustin Pop
    let Table _ _ _ ini_plc = ini_tbl
469 4e25d1c2 Iustin Pop
        -- iterate over all instances, computing the best move
470 256810de Iustin Pop
        best_tbl =
471 256810de Iustin Pop
            foldl'
472 7e7f6ca2 Iustin Pop
            (\ step_tbl elem ->
473 040afc35 Iustin Pop
                 if Instance.snode elem == Node.noSecondary then step_tbl
474 7e7f6ca2 Iustin Pop
                    else compareTables step_tbl $
475 7e7f6ca2 Iustin Pop
                         checkInstanceMove nodes_idx ini_tbl elem)
476 256810de Iustin Pop
            ini_tbl victims
477 aaaa0e43 Iustin Pop
        Table _ _ _ best_plc = best_tbl
478 0a0f2533 Iustin Pop
    in
479 0a0f2533 Iustin Pop
      if length best_plc == length ini_plc then -- no advancement
480 0a0f2533 Iustin Pop
          ini_tbl
481 0a0f2533 Iustin Pop
      else
482 7dfaafb1 Iustin Pop
          best_tbl
483 e4f08c46 Iustin Pop
484 e4f08c46 Iustin Pop
{- | Auxiliary function for solution computation.
485 e4f08c46 Iustin Pop
486 e4f08c46 Iustin Pop
We write this in an explicit recursive fashion in order to control
487 e4f08c46 Iustin Pop
early-abort in case we have met the min delta. We can't use foldr
488 e4f08c46 Iustin Pop
instead of explicit recursion since we need the accumulator for the
489 e4f08c46 Iustin Pop
abort decision.
490 e4f08c46 Iustin Pop
491 e4f08c46 Iustin Pop
-}
492 e4f08c46 Iustin Pop
advanceSolution :: [Maybe Removal] -- ^ The removal to process
493 e4f08c46 Iustin Pop
                -> Int             -- ^ Minimum delta parameter
494 e4f08c46 Iustin Pop
                -> Int             -- ^ Maximum delta parameter
495 e4f08c46 Iustin Pop
                -> Maybe Solution  -- ^ Current best solution
496 e4f08c46 Iustin Pop
                -> Maybe Solution  -- ^ New best solution
497 e4f08c46 Iustin Pop
advanceSolution [] _ _ sol = sol
498 e4f08c46 Iustin Pop
advanceSolution (Nothing:xs) m n sol = advanceSolution xs m n sol
499 e4f08c46 Iustin Pop
advanceSolution ((Just (Removal nx removed)):xs) min_d max_d prev_sol =
500 e4f08c46 Iustin Pop
    let new_sol = checkPlacement nx removed [] 0 prev_sol max_d
501 e4f08c46 Iustin Pop
        new_delta = solutionDelta $! new_sol
502 e4f08c46 Iustin Pop
    in
503 e4f08c46 Iustin Pop
      if new_delta >= 0 && new_delta <= min_d then
504 e4f08c46 Iustin Pop
          new_sol
505 e4f08c46 Iustin Pop
      else
506 e4f08c46 Iustin Pop
          advanceSolution xs min_d max_d new_sol
507 e4f08c46 Iustin Pop
508 e4f08c46 Iustin Pop
-- | Computes the placement solution.
509 e4f08c46 Iustin Pop
solutionFromRemovals :: [Maybe Removal] -- ^ The list of (possible) removals
510 e4f08c46 Iustin Pop
                     -> Int             -- ^ Minimum delta parameter
511 e4f08c46 Iustin Pop
                     -> Int             -- ^ Maximum delta parameter
512 e4f08c46 Iustin Pop
                     -> Maybe Solution  -- ^ The best solution found
513 e4f08c46 Iustin Pop
solutionFromRemovals removals min_delta max_delta =
514 e4f08c46 Iustin Pop
    advanceSolution removals min_delta max_delta Nothing
515 e4f08c46 Iustin Pop
516 e4f08c46 Iustin Pop
{- | Computes the solution at the given depth.
517 e4f08c46 Iustin Pop
518 e4f08c46 Iustin Pop
This is a wrapper over both computeRemovals and
519 e4f08c46 Iustin Pop
solutionFromRemovals. In case we have no solution, we return Nothing.
520 e4f08c46 Iustin Pop
521 e4f08c46 Iustin Pop
-}
522 e4f08c46 Iustin Pop
computeSolution :: NodeList        -- ^ The original node data
523 e4f08c46 Iustin Pop
                -> [Instance.Instance] -- ^ The list of /bad/ instances
524 e4f08c46 Iustin Pop
                -> Int             -- ^ The /depth/ of removals
525 e4f08c46 Iustin Pop
                -> Int             -- ^ Maximum number of removals to process
526 e4f08c46 Iustin Pop
                -> Int             -- ^ Minimum delta parameter
527 e4f08c46 Iustin Pop
                -> Int             -- ^ Maximum delta parameter
528 e4f08c46 Iustin Pop
                -> Maybe Solution  -- ^ The best solution found (or Nothing)
529 e4f08c46 Iustin Pop
computeSolution nl bad_instances depth max_removals min_delta max_delta =
530 e4f08c46 Iustin Pop
  let
531 e4f08c46 Iustin Pop
      removals = computeRemovals nl bad_instances depth
532 e4f08c46 Iustin Pop
      removals' = capRemovals removals max_removals
533 e4f08c46 Iustin Pop
  in
534 e4f08c46 Iustin Pop
    solutionFromRemovals removals' min_delta max_delta
535 e4f08c46 Iustin Pop
536 e4f08c46 Iustin Pop
-- Solution display functions (pure)
537 e4f08c46 Iustin Pop
538 e4f08c46 Iustin Pop
-- | Given the original and final nodes, computes the relocation description.
539 e4f08c46 Iustin Pop
computeMoves :: String -- ^ The instance name
540 e4f08c46 Iustin Pop
             -> String -- ^ Original primary
541 e4f08c46 Iustin Pop
             -> String -- ^ Original secondary
542 e4f08c46 Iustin Pop
             -> String -- ^ New primary
543 e4f08c46 Iustin Pop
             -> String -- ^ New secondary
544 e4f08c46 Iustin Pop
             -> (String, [String])
545 e4f08c46 Iustin Pop
                -- ^ Tuple of moves and commands list; moves is containing
546 e4f08c46 Iustin Pop
                -- either @/f/@ for failover or @/r:name/@ for replace
547 e4f08c46 Iustin Pop
                -- secondary, while the command list holds gnt-instance
548 e4f08c46 Iustin Pop
                -- commands (without that prefix), e.g \"@failover instance1@\"
549 e4f08c46 Iustin Pop
computeMoves i a b c d =
550 e4f08c46 Iustin Pop
    if c == a then {- Same primary -}
551 e4f08c46 Iustin Pop
        if d == b then {- Same sec??! -}
552 e4f08c46 Iustin Pop
            ("-", [])
553 e4f08c46 Iustin Pop
        else {- Change of secondary -}
554 e4f08c46 Iustin Pop
            (printf "r:%s" d,
555 e4f08c46 Iustin Pop
             [printf "replace-disks -n %s %s" d i])
556 e4f08c46 Iustin Pop
    else
557 e4f08c46 Iustin Pop
        if c == b then {- Failover and ... -}
558 e4f08c46 Iustin Pop
            if d == a then {- that's all -}
559 e0eb63f0 Iustin Pop
                ("f", [printf "migrate -f %s" i])
560 e4f08c46 Iustin Pop
            else
561 e4f08c46 Iustin Pop
                (printf "f r:%s" d,
562 e0eb63f0 Iustin Pop
                 [printf "migrate -f %s" i,
563 e4f08c46 Iustin Pop
                  printf "replace-disks -n %s %s" d i])
564 e4f08c46 Iustin Pop
        else
565 e4f08c46 Iustin Pop
            if d == a then {- ... and keep primary as secondary -}
566 e4f08c46 Iustin Pop
                (printf "r:%s f" c,
567 e4f08c46 Iustin Pop
                 [printf "replace-disks -n %s %s" c i,
568 e0eb63f0 Iustin Pop
                  printf "migrate -f %s" i])
569 e4f08c46 Iustin Pop
            else
570 e4f08c46 Iustin Pop
                if d == b then {- ... keep same secondary -}
571 e4f08c46 Iustin Pop
                    (printf "f r:%s f" c,
572 e0eb63f0 Iustin Pop
                     [printf "migrate -f %s" i,
573 e4f08c46 Iustin Pop
                      printf "replace-disks -n %s %s" c i,
574 e0eb63f0 Iustin Pop
                      printf "migrate -f %s" i])
575 e4f08c46 Iustin Pop
576 e4f08c46 Iustin Pop
                else {- Nothing in common -}
577 e4f08c46 Iustin Pop
                    (printf "r:%s f r:%s" c d,
578 e4f08c46 Iustin Pop
                     [printf "replace-disks -n %s %s" c i,
579 e0eb63f0 Iustin Pop
                      printf "migrate -f %s" i,
580 e4f08c46 Iustin Pop
                      printf "replace-disks -n %s %s" d i])
581 e4f08c46 Iustin Pop
582 ca8258d9 Iustin Pop
{-| Converts a placement to string format -}
583 ca8258d9 Iustin Pop
printSolutionLine :: InstanceList
584 740ec004 Iustin Pop
              -> NameList
585 740ec004 Iustin Pop
              -> NameList
586 ca8258d9 Iustin Pop
              -> Int
587 ca8258d9 Iustin Pop
              -> Int
588 ca8258d9 Iustin Pop
              -> Placement
589 ab271fc1 Iustin Pop
              -> Int
590 ca8258d9 Iustin Pop
              -> (String, [String])
591 ab271fc1 Iustin Pop
printSolutionLine il ktn kti nmlen imlen plc pos =
592 ca8258d9 Iustin Pop
    let
593 ca8258d9 Iustin Pop
        pmlen = (2*nmlen + 1)
594 ca8258d9 Iustin Pop
        (i, p, s, c) = plc
595 ca8258d9 Iustin Pop
        inst = Container.find i il
596 ca8258d9 Iustin Pop
        inam = fromJust $ lookup (Instance.idx inst) kti
597 ca8258d9 Iustin Pop
        npri = fromJust $ lookup p ktn
598 ca8258d9 Iustin Pop
        nsec = fromJust $ lookup s ktn
599 ca8258d9 Iustin Pop
        opri = fromJust $ lookup (Instance.pnode inst) ktn
600 ca8258d9 Iustin Pop
        osec = fromJust $ lookup (Instance.snode inst) ktn
601 ca8258d9 Iustin Pop
        (moves, cmds) =  computeMoves inam opri osec npri nsec
602 ca8258d9 Iustin Pop
        ostr = (printf "%s:%s" opri osec)::String
603 ca8258d9 Iustin Pop
        nstr = (printf "%s:%s" npri nsec)::String
604 ca8258d9 Iustin Pop
    in
605 ab271fc1 Iustin Pop
      (printf "  %3d. %-*s %-*s => %-*s %.8f a=%s"
606 ab271fc1 Iustin Pop
       pos imlen inam pmlen ostr
607 ca8258d9 Iustin Pop
       pmlen nstr c moves,
608 ca8258d9 Iustin Pop
       cmds)
609 ca8258d9 Iustin Pop
610 142538ff Iustin Pop
formatCmds :: [[String]] -> String
611 142538ff Iustin Pop
formatCmds cmd_strs =
612 e0eb63f0 Iustin Pop
    unlines $
613 142538ff Iustin Pop
    concat $ map (\(a, b) ->
614 e0eb63f0 Iustin Pop
        (printf "echo step %d" (a::Int)):
615 e0eb63f0 Iustin Pop
        (printf "check"):
616 e0eb63f0 Iustin Pop
        (map ("gnt-instance " ++) b)) $
617 142538ff Iustin Pop
        zip [1..] cmd_strs
618 142538ff Iustin Pop
619 e4f08c46 Iustin Pop
{-| Converts a solution to string format -}
620 e4f08c46 Iustin Pop
printSolution :: InstanceList
621 740ec004 Iustin Pop
              -> NameList
622 740ec004 Iustin Pop
              -> NameList
623 e4f08c46 Iustin Pop
              -> [Placement]
624 e4f08c46 Iustin Pop
              -> ([String], [[String]])
625 e4f08c46 Iustin Pop
printSolution il ktn kti sol =
626 671b85b9 Iustin Pop
    let
627 671b85b9 Iustin Pop
        mlen_fn = maximum . (map length) . snd . unzip
628 671b85b9 Iustin Pop
        imlen = mlen_fn kti
629 671b85b9 Iustin Pop
        nmlen = mlen_fn ktn
630 671b85b9 Iustin Pop
    in
631 ab271fc1 Iustin Pop
      unzip $ map (uncurry $ printSolutionLine il ktn kti nmlen imlen) $
632 ab271fc1 Iustin Pop
            zip sol [1..]
633 e4f08c46 Iustin Pop
634 e4f08c46 Iustin Pop
-- | Print the node list.
635 740ec004 Iustin Pop
printNodes :: NameList -> NodeList -> String
636 e4f08c46 Iustin Pop
printNodes ktn nl =
637 e4f08c46 Iustin Pop
    let snl = sortBy (compare `on` Node.idx) (Container.elems nl)
638 e4f08c46 Iustin Pop
        snl' = map (\ n -> ((fromJust $ lookup (Node.idx n) ktn), n)) snl
639 af53a5c4 Iustin Pop
        m_name = maximum . (map length) . fst . unzip $ snl'
640 af53a5c4 Iustin Pop
        helper = Node.list m_name
641 a1c6212e Iustin Pop
        header = printf
642 a1c6212e Iustin Pop
                 "%2s %-*s %5s %5s %5s %5s %5s %5s %5s %5s %3s %3s %7s %7s"
643 a1c6212e Iustin Pop
                 " F" m_name "Name"
644 a1c6212e Iustin Pop
                 "t_mem" "n_mem" "i_mem" "x_mem" "f_mem" "r_mem"
645 ced859f3 Iustin Pop
                 "t_dsk" "f_dsk"
646 ced859f3 Iustin Pop
                 "pri" "sec" "p_fmem" "p_fdsk"
647 ced859f3 Iustin Pop
    in unlines $ (header:map (uncurry helper) snl')
648 e4f08c46 Iustin Pop
649 e4f08c46 Iustin Pop
-- | Compute the mem and disk covariance.
650 19777638 Iustin Pop
compDetailedCV :: NodeList -> (Double, Double, Double, Double, Double)
651 e4f08c46 Iustin Pop
compDetailedCV nl =
652 0335fe4a Iustin Pop
    let
653 19777638 Iustin Pop
        all_nodes = Container.elems nl
654 19777638 Iustin Pop
        (offline, nodes) = partition Node.offline all_nodes
655 0335fe4a Iustin Pop
        mem_l = map Node.p_mem nodes
656 0335fe4a Iustin Pop
        dsk_l = map Node.p_dsk nodes
657 e4f08c46 Iustin Pop
        mem_cv = varianceCoeff mem_l
658 e4f08c46 Iustin Pop
        dsk_cv = varianceCoeff dsk_l
659 34a6e127 Iustin Pop
        n1_l = length $ filter Node.failN1 nodes
660 34a6e127 Iustin Pop
        n1_score = (fromIntegral n1_l) / (fromIntegral $ length nodes)
661 d6be0775 Iustin Pop
        res_l = map Node.p_rem nodes
662 d6be0775 Iustin Pop
        res_cv = varianceCoeff res_l
663 19777638 Iustin Pop
        offline_inst = sum . map (\n -> (length . Node.plist $ n) +
664 19777638 Iustin Pop
                                        (length . Node.slist $ n)) $ offline
665 19777638 Iustin Pop
        online_inst = sum . map (\n -> (length . Node.plist $ n) +
666 19777638 Iustin Pop
                                       (length . Node.slist $ n)) $ nodes
667 19777638 Iustin Pop
        off_score = (fromIntegral offline_inst) /
668 19777638 Iustin Pop
                    (fromIntegral $ online_inst + offline_inst)
669 19777638 Iustin Pop
    in (mem_cv, dsk_cv, n1_score, res_cv, off_score)
670 e4f08c46 Iustin Pop
671 e4f08c46 Iustin Pop
-- | Compute the 'total' variance.
672 e4f08c46 Iustin Pop
compCV :: NodeList -> Double
673 e4f08c46 Iustin Pop
compCV nl =
674 19777638 Iustin Pop
    let (mem_cv, dsk_cv, n1_score, res_cv, off_score) = compDetailedCV nl
675 19777638 Iustin Pop
    in mem_cv + dsk_cv + n1_score + res_cv + off_score
676 e4f08c46 Iustin Pop
677 e4f08c46 Iustin Pop
printStats :: NodeList -> String
678 e4f08c46 Iustin Pop
printStats nl =
679 19777638 Iustin Pop
    let (mem_cv, dsk_cv, n1_score, res_cv, off_score) = compDetailedCV nl
680 19777638 Iustin Pop
    in printf "f_mem=%.8f, r_mem=%.8f, f_dsk=%.8f, n1=%.3f, uf=%.3f"
681 19777638 Iustin Pop
       mem_cv res_cv dsk_cv n1_score off_score