Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / Node.hs @ 00b15752

History | View | Annotate | Download (8.5 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
    ) where
30

    
31
import Data.List
32
import Text.Printf (printf)
33

    
34
import qualified Ganeti.HTools.Container as Container
35
import qualified Ganeti.HTools.Instance as Instance
36
import qualified Ganeti.HTools.PeerMap as PeerMap
37

    
38
import Ganeti.HTools.Utils
39

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

    
61
{- | Create a new node.
62

    
63
The index and the peers maps are empty, and will be need to be update
64
later via the 'setIdx' and 'buildPeers' functions.
65

    
66
-}
67
create :: Double -> Int -> Int -> Double -> Int -> Bool -> Node
68
create mem_t_init mem_n_init mem_f_init dsk_t_init dsk_f_init
69
       offline_init =
70
    Node
71
    {
72
      t_mem = mem_t_init,
73
      n_mem = mem_n_init,
74
      f_mem = mem_f_init,
75
      t_dsk = dsk_t_init,
76
      f_dsk = dsk_f_init,
77
      plist = [],
78
      slist = [],
79
      failN1 = True,
80
      idx = -1,
81
      peers = PeerMap.empty,
82
      r_mem = 0,
83
      p_mem = (fromIntegral mem_f_init) / mem_t_init,
84
      p_dsk = (fromIntegral dsk_f_init) / dsk_t_init,
85
      p_rem = 0,
86
      offline = offline_init,
87
      x_mem = 0
88
    }
89

    
90
-- | Changes the index.
91
-- This is used only during the building of the data structures.
92
setIdx :: Node -> Int -> Node
93
setIdx t i = t {idx = i}
94

    
95
-- | Sets the offline attribute
96
setOffline :: Node -> Bool -> Node
97
setOffline t val = t { offline = val }
98

    
99
-- | Sets the unnaccounted memory
100
setXmem :: Node -> Int -> Node
101
setXmem t val = t { x_mem = val }
102

    
103
-- | Sets the free memory
104
setFmem :: Node -> Int -> Node
105
setFmem t new_mem =
106
    let new_n1 = computeFailN1 (r_mem t) new_mem (f_dsk t)
107
        new_mp = (fromIntegral new_mem) / (t_mem t)
108
    in
109
      t { f_mem = new_mem, failN1 = new_n1, p_mem = new_mp }
110

    
111
-- | Given the rmem, free memory and disk, computes the failn1 status.
112
computeFailN1 :: Int -> Int -> Int -> Bool
113
computeFailN1 new_rmem new_mem new_dsk =
114
    new_mem <= new_rmem || new_dsk <= 0
115

    
116
-- | Given the new free memory and disk, fail if any of them is below zero.
117
failHealth :: Int -> Int -> Bool
118
failHealth new_mem new_dsk = new_mem <= 0 || new_dsk <= 0
119

    
120
-- | Computes the maximum reserved memory for peers from a peer map.
121
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
122
computeMaxRes new_peers = PeerMap.maxElem new_peers
123

    
124
-- | Builds the peer map for a given node.
125
buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
126
buildPeers t il num_nodes =
127
    let mdata = map
128
                (\i_idx -> let inst = Container.find i_idx il
129
                           in (Instance.pnode inst, Instance.mem inst))
130
                (slist t)
131
        pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
132
        new_rmem = computeMaxRes pmap
133
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
134
        new_prem = (fromIntegral new_rmem) / (t_mem t)
135
    in t {peers=pmap, failN1 = new_failN1, r_mem = new_rmem, p_rem = new_prem}
136

    
137
-- | Removes a primary instance.
138
removePri :: Node -> Instance.Instance -> Node
139
removePri t inst =
140
    let iname = Instance.idx inst
141
        new_plist = delete iname (plist t)
142
        new_mem = f_mem t + Instance.mem inst
143
        new_dsk = f_dsk t + Instance.dsk inst
144
        new_mp = (fromIntegral new_mem) / (t_mem t)
145
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
146
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk
147
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
148
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
149

    
150
-- | Removes a secondary instance.
151
removeSec :: Node -> Instance.Instance -> Node
152
removeSec t inst =
153
    let iname = Instance.idx inst
154
        pnode = Instance.pnode inst
155
        new_slist = delete iname (slist t)
156
        new_dsk = f_dsk t + Instance.dsk inst
157
        old_peers = peers t
158
        old_peem = PeerMap.find pnode old_peers
159
        new_peem =  old_peem - (Instance.mem inst)
160
        new_peers = PeerMap.add pnode new_peem old_peers
161
        old_rmem = r_mem t
162
        new_rmem = if old_peem < old_rmem then
163
                       old_rmem
164
                   else
165
                       computeMaxRes new_peers
166
        new_prem = (fromIntegral new_rmem) / (t_mem t)
167
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
168
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
169
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
170
          failN1 = new_failn1, r_mem = new_rmem, p_dsk = new_dp,
171
          p_rem = new_prem}
172

    
173
-- | Adds a primary instance.
174
addPri :: Node -> Instance.Instance -> Maybe Node
175
addPri t inst =
176
    let iname = Instance.idx inst
177
        new_mem = f_mem t - Instance.mem inst
178
        new_dsk = f_dsk t - Instance.dsk inst
179
        new_failn1 = computeFailN1 (r_mem t) new_mem new_dsk in
180
      if (failHealth new_mem new_dsk) || (new_failn1 && not (failN1 t)) then
181
        Nothing
182
      else
183
        let new_plist = iname:(plist t)
184
            new_mp = (fromIntegral new_mem) / (t_mem t)
185
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
186
        in
187
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
188
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
189

    
190
-- | Adds a secondary instance.
191
addSec :: Node -> Instance.Instance -> Int -> Maybe Node
192
addSec t inst pdx =
193
    let iname = Instance.idx inst
194
        old_peers = peers t
195
        old_mem = f_mem t
196
        new_dsk = f_dsk t - Instance.dsk inst
197
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
198
        new_peers = PeerMap.add pdx new_peem old_peers
199
        new_rmem = max (r_mem t) new_peem
200
        new_prem = (fromIntegral new_rmem) / (t_mem t)
201
        new_failn1 = computeFailN1 new_rmem old_mem new_dsk in
202
    if (failHealth old_mem new_dsk) || (new_failn1 && not (failN1 t)) then
203
        Nothing
204
    else
205
        let new_slist = iname:(slist t)
206
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
207
        in
208
        Just t {slist = new_slist, f_dsk = new_dsk,
209
                peers = new_peers, failN1 = new_failn1,
210
                r_mem = new_rmem, p_dsk = new_dp,
211
                p_rem = new_prem}
212

    
213
-- | Add a primary instance to a node without other updates
214
setPri :: Node -> Int -> Node
215
setPri t idx = t { plist = idx:(plist t) }
216

    
217
-- | Add a secondary instance to a node without other updates
218
setSec :: Node -> Int -> Node
219
setSec t idx = t { slist = idx:(slist t) }
220

    
221
-- | String converter for the node list functionality.
222
list :: Int -> String -> Node -> String
223
list mname n t =
224
    let pl = plist t
225
        sl = slist t
226
        mp = p_mem t
227
        dp = p_dsk t
228
        off = offline t
229
        fn = failN1 t
230
        tmem = t_mem t
231
        nmem = n_mem t
232
        xmem = x_mem t
233
        fmem = f_mem t
234
        imem = (truncate tmem) - nmem - xmem - fmem
235
    in
236
      printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d %3d %3d %.5f %.5f"
237
                 (if off then '-' else if fn then '*' else ' ')
238
                 mname n tmem nmem imem xmem fmem (r_mem t)
239
                 ((t_dsk t) / 1024) ((f_dsk t) `div` 1024)
240
                 (length pl) (length sl)
241
                 mp dp