Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Node.hs @ 040afc35

History | View | Annotate | Download (8.8 kB)

1
{-| Module describing a node.
2

    
3
    All updates are functional (copy-based) and return a new node with
4
    updated value.
5
-}
6

    
7
module Ganeti.HTools.Node
8
    (
9
      Node(failN1, idx, t_mem, n_mem, f_mem, t_dsk, f_dsk,
10
           p_mem, p_dsk, p_rem,
11
           plist, slist, offline)
12
    -- * Constructor
13
    , create
14
    -- ** Finalization after data loading
15
    , buildPeers
16
    , setIdx
17
    , setOffline
18
    , setXmem
19
    , setFmem
20
    -- * Instance (re)location
21
    , removePri
22
    , removeSec
23
    , addPri
24
    , addSec
25
    , setPri
26
    , setSec
27
    -- * Formatting
28
    , list
29
    -- * Misc stuff
30
    , AssocList
31
    , noSecondary
32
    ) where
33

    
34
import Data.List
35
import Text.Printf (printf)
36

    
37
import qualified Ganeti.HTools.Container as Container
38
import qualified Ganeti.HTools.Instance as Instance
39
import qualified Ganeti.HTools.PeerMap as PeerMap
40

    
41
import Ganeti.HTools.Utils
42

    
43
data Node = Node { t_mem :: Double -- ^ total memory (MiB)
44
                 , n_mem :: Int    -- ^ node memory (MiB)
45
                 , f_mem :: Int    -- ^ free memory (MiB)
46
                 , x_mem :: Int    -- ^ unaccounted memory (MiB)
47
                 , t_dsk :: Double -- ^ total disk space (MiB)
48
                 , f_dsk :: Int    -- ^ free disk space (MiB)
49
                 , plist :: [Int]  -- ^ list of primary instance indices
50
                 , slist :: [Int]  -- ^ list of secondary instance indices
51
                 , idx :: Int      -- ^ internal index for book-keeping
52
                 , peers :: PeerMap.PeerMap -- ^ pnode to instance mapping
53
                 , failN1:: Bool   -- ^ whether the node has failed n1
54
                 , r_mem :: Int    -- ^ maximum memory needed for
55
                                   -- failover by primaries of this node
56
                 , p_mem :: Double -- ^ percent of free memory
57
                 , p_dsk :: Double -- ^ percent of free disk
58
                 , p_rem :: Double -- ^ percent of reserved memory
59
                 , offline :: Bool -- ^ whether the node should not be used
60
                                   -- for allocations and skipped from
61
                                   -- score computations
62
  } deriving (Show)
63

    
64
-- | A simple name for the int, node association list
65
type AssocList = [(Int, Node)]
66

    
67
-- | Constant node index for a non-moveable instance
68
noSecondary :: Int
69
noSecondary = -1
70

    
71
{- | Create a new node.
72

    
73
The index and the peers maps are empty, and will be need to be update
74
later via the 'setIdx' and 'buildPeers' functions.
75

    
76
-}
77
create :: Double -> Int -> Int -> Double -> Int -> Bool -> Node
78
create mem_t_init mem_n_init mem_f_init dsk_t_init dsk_f_init
79
       offline_init =
80
    Node
81
    {
82
      t_mem = mem_t_init,
83
      n_mem = mem_n_init,
84
      f_mem = mem_f_init,
85
      t_dsk = dsk_t_init,
86
      f_dsk = dsk_f_init,
87
      plist = [],
88
      slist = [],
89
      failN1 = True,
90
      idx = -1,
91
      peers = PeerMap.empty,
92
      r_mem = 0,
93
      p_mem = (fromIntegral mem_f_init) / mem_t_init,
94
      p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
95
      p_rem = 0,
96
      offline = offline_init,
97
      x_mem = 0
98
    }
99

    
100
-- | Changes the index.
101
-- This is used only during the building of the data structures.
102
setIdx :: Node -> Int -> Node
103
setIdx t i = t {idx = i}
104

    
105
-- | Sets the offline attribute
106
setOffline :: Node -> Bool -> Node
107
setOffline t val = t { offline = val }
108

    
109
-- | Sets the unnaccounted memory
110
setXmem :: Node -> Int -> Node
111
setXmem t val = t { x_mem = val }
112

    
113
-- | Sets the free memory
114
setFmem :: Node -> Int -> Node
115
setFmem t new_mem =
116
    let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
117
        new_mp = (fromIntegral new_mem) / (t_mem t)
118
    in
119
      t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
120

    
121
-- | Given the rmem, free memory and disk, computes the failn1 status.
122
computeFailN1 :: Int -> Int -> Int -> Bool
123
computeFailN1 new_rmem new_mem new_dsk =
124
    new_mem <= new_rmem || new_dsk <= 0
125

    
126
-- | Given the new free memory and disk, fail if any of them is below zero.
127
failHealth :: Int -> Int -> Bool
128
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
129

    
130
-- | Computes the maximum reserved memory for peers from a peer map.
131
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
132
computeMaxRes new_peers = PeerMap.maxElem new_peers
133

    
134
-- | Builds the peer map for a given node.
135
buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
136
buildPeers t il num_nodes =
137
    let mdata = map
138
                (\i_idx -> let inst = Container.find i_idx il
139
                           in (Instance.pnode inst, Instance.mem inst))
140
                (slist t)
141
        pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
142
        new_rmem = computeMaxRes pmap
143
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
144
        new_prem = (fromIntegral new_rmem) / (t_mem t)
145
    in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
146

    
147
-- | Removes a primary instance.
148
removePri :: Node -> Instance.Instance -> Node
149
removePri t inst =
150
    let iname = Instance.idx inst
151
        new_plist = delete iname (plist t)
152
        new_mem = f_mem t + Instance.mem inst
153
        new_dsk = f_dsk t + Instance.dsk inst
154
        new_mp = (fromIntegral new_mem) / (t_mem t)
155
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
156
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
157
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
158
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
159

    
160
-- | Removes a secondary instance.
161
removeSec :: Node -> Instance.Instance -> Node
162
removeSec t inst =
163
    let iname = Instance.idx inst
164
        pnode = Instance.pnode inst
165
        new_slist = delete iname (slist t)
166
        new_dsk = f_dsk t + Instance.dsk inst
167
        old_peers = peers t
168
        old_peem = PeerMap.find pnode old_peers
169
        new_peem =  old_peem - (Instance.mem inst)
170
        new_peers = PeerMap.add pnode new_peem old_peers
171
        old_rmem = r_mem t
172
        new_rmem = if old_peem < old_rmem then
173
                       old_rmem
174
                   else
175
                       computeMaxRes new_peers
176
        new_prem = (fromIntegral new_rmem) / (t_mem t)
177
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
178
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
179
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
180
          failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
181
          p_rem = new_prem}
182

    
183
-- | Adds a primary instance.
184
addPri :: Node -> Instance.Instance -> Maybe Node
185
addPri t inst =
186
    let iname = Instance.idx inst
187
        new_mem = f_mem t - Instance.mem inst
188
        new_dsk = f_dsk t - Instance.dsk inst
189
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
190
      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
191
        Nothing
192
      else
193
        let new_plist = iname:(plist t)
194
            new_mp = (fromIntegral new_mem) / (t_mem t)
195
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
196
        in
197
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
198
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
199

    
200
-- | Adds a secondary instance.
201
addSec :: Node -> Instance.Instance -> Int -> Maybe Node
202
addSec t inst pdx =
203
    let iname = Instance.idx inst
204
        old_peers = peers t
205
        old_mem = f_mem t
206
        new_dsk = f_dsk t - Instance.dsk inst
207
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
208
        new_peers = PeerMap.add pdx new_peem old_peers
209
        new_rmem = max (r_mem t) new_peem
210
        new_prem = (fromIntegral new_rmem) / (t_mem t)
211
        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
212
    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
213
        Nothing
214
    else
215
        let new_slist = iname:(slist t)
216
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
217
        in
218
        Just t {slist = new_slist, f_dsk = new_dsk,
219
                peers = new_peers, failN1 = new_failn1,
220
                r_mem = new_rmem, p_dsk = new_dp,
221
                p_rem = new_prem}
222

    
223
-- | Add a primary instance to a node without other updates
224
setPri :: Node -> Int -> Node
225
setPri t idx = t { plist = idx:(plist t) }
226

    
227
-- | Add a secondary instance to a node without other updates
228
setSec :: Node -> Int -> Node
229
setSec t idx = t { slist = idx:(slist t) }
230

    
231
-- | String converter for the node list functionality.
232
list :: Int -> String -> Node -> String
233
list mname n t =
234
    let pl = plist t
235
        sl = slist t
236
        mp = p_mem t
237
        dp = p_dsk t
238
        off = offline t
239
        fn = failN1 t
240
        tmem = t_mem t
241
        nmem = n_mem t
242
        xmem = x_mem t
243
        fmem = f_mem t
244
        imem = (truncate tmem) - nmem - xmem - fmem
245
    in
246
      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
247
                 (if off then '-' else if fn then '*' else ' ')
248
                 mname n tmem nmem imem xmem fmem (r_mem t)
249
                 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
250
                 (length pl) (length sl)
251
                 mp dp