Statistics
| Branch: | Tag: | Revision:

root / src / Node.hs @ e4f08c46

History | View | Annotate | Download (6.4 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 Node
8
    (
9
      Node(failN1, idx, f_mem, f_disk, slist, plist)
10
    -- * Constructor
11
    , create
12
    -- ** Finalization after data loading
13
    , buildPeers
14
    , setIdx
15
    -- * Instance (re)location
16
    , removePri
17
    , removeSec
18
    , addPri
19
    , addSec
20
    -- * Statistics
21
    , normUsed
22
    -- * Formatting
23
    , list
24
    ) where
25

    
26
import Data.List
27
import Text.Printf (printf)
28

    
29
import qualified Container
30
import qualified Instance
31
import qualified PeerMap
32

    
33
import Utils
34

    
35
data Node = Node { t_mem :: Int -- ^ total memory (Mib)
36
                 , f_mem :: Int -- ^ free memory (MiB)
37
                 , t_disk :: Int -- ^ total disk space (MiB)
38
                 , f_disk :: Int -- ^ free disk space (MiB)
39
                 , plist :: [Int] -- ^ list of primary instance indices
40
                 , slist :: [Int] -- ^ list of secondary instance indices
41
                 , idx :: Int -- ^ internal index for book-keeping
42
                 , peers:: PeerMap.PeerMap -- ^ primary node to instance
43
                                           -- mapping
44
                 , failN1:: Bool -- ^ whether the node has failed n1
45
                 , maxRes :: Int -- ^ maximum memory needed for
46
                                   -- failover by primaries of this node
47
  } deriving (Show)
48

    
49
{- | Create a new node.
50

    
51
The index and the peers maps are empty, and will be need to be update
52
later via the 'setIdx' and 'buildPeers' functions.
53

    
54
-}
55
create :: String -> String -> String -> String -> [Int] -> [Int] -> Node
56
create mem_t_init mem_f_init disk_t_init disk_f_init
57
       plist_init slist_init = Node
58
    {
59
      t_mem = read mem_t_init,
60
      f_mem = read mem_f_init,
61
      t_disk = read disk_t_init,
62
      f_disk = read disk_f_init,
63
      plist = plist_init,
64
      slist = slist_init,
65
      failN1 = True,
66
      idx = -1,
67
      peers = PeerMap.empty,
68
      maxRes = 0
69
    }
70

    
71
-- | Changes the index.
72
-- This is used only during the building of the data structures.
73
setIdx :: Node -> Int -> Node
74
setIdx t i = t {idx = i}
75

    
76
-- | Given the rmem, free memory and disk, computes the failn1 status.
77
computeFailN1 :: Int -> Int -> Int -> Bool
78
computeFailN1 new_rmem new_mem new_disk =
79
    new_mem <= new_rmem || new_disk <= 0
80

    
81

    
82
-- | Computes the maximum reserved memory for peers from a peer map.
83
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
84
computeMaxRes new_peers = PeerMap.maxElem new_peers
85

    
86
-- | Builds the peer map for a given node.
87
buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
88
buildPeers t il num_nodes =
89
    let mdata = map
90
                (\i_idx -> let inst = Container.find i_idx il
91
                           in (Instance.pnode inst, Instance.mem inst))
92
                (slist t)
93
        pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
94
        new_rmem = computeMaxRes pmap
95
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_disk t)
96
    in t {peers=pmap, failN1 = new_failN1, maxRes = new_rmem}
97

    
98
-- | Removes a primary instance.
99
removePri :: Node -> Instance.Instance -> Node
100
removePri t inst =
101
    let iname = Instance.idx inst
102
        new_plist = delete iname (plist t)
103
        new_mem = f_mem t + Instance.mem inst
104
        new_disk = f_disk t + Instance.disk inst
105
        new_failn1 = computeFailN1 (maxRes t) new_mem new_disk
106
    in t {plist = new_plist, f_mem = new_mem, f_disk = new_disk,
107
          failN1 = new_failn1}
108

    
109
-- | Removes a secondary instance.
110
removeSec :: Node -> Instance.Instance -> Node
111
removeSec t inst =
112
    let iname = Instance.idx inst
113
        pnode = Instance.pnode inst
114
        new_slist = delete iname (slist t)
115
        new_disk = f_disk t + Instance.disk inst
116
        old_peers = peers t
117
        old_peem = PeerMap.find pnode old_peers
118
        new_peem =  old_peem - (Instance.mem inst)
119
        new_peers = PeerMap.add pnode new_peem old_peers
120
        old_rmem = maxRes t
121
        new_rmem = if old_peem < old_rmem then
122
                       old_rmem
123
                   else
124
                       computeMaxRes new_peers
125
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_disk
126
    in t {slist = new_slist, f_disk = new_disk, peers = new_peers,
127
          failN1 = new_failn1, maxRes = new_rmem}
128

    
129
-- | Adds a primary instance.
130
addPri :: Node -> Instance.Instance -> Maybe Node
131
addPri t inst =
132
    let iname = Instance.idx inst
133
        new_mem = f_mem t - Instance.mem inst
134
        new_disk = f_disk t - Instance.disk inst
135
        new_failn1 = computeFailN1 (maxRes t) new_mem new_disk in
136
      if new_failn1 then
137
        Nothing
138
      else
139
        let new_plist = iname:(plist t) in
140
        Just t {plist = new_plist, f_mem = new_mem, f_disk = new_disk,
141
                failN1 = new_failn1}
142

    
143
-- | Adds a secondary instance.
144
addSec :: Node -> Instance.Instance -> Int -> Maybe Node
145
addSec t inst pdx =
146
    let iname = Instance.idx inst
147
        old_peers = peers t
148
        new_disk = f_disk t - Instance.disk inst
149
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
150
        new_peers = PeerMap.add pdx new_peem old_peers
151
        new_rmem = max (maxRes t) new_peem
152
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_disk in
153
    if new_failn1 then
154
        Nothing
155
    else
156
        let new_slist = iname:(slist t) in
157
        Just t {slist = new_slist, f_disk = new_disk,
158
                peers = new_peers, failN1 = new_failn1,
159
                maxRes = new_rmem}
160

    
161
-- | Simple converter to string.
162
str :: Node -> String
163
str t =
164
    printf ("Node %d (mem=%5d MiB, disk=%5.2f GiB)\n  Primaries:" ++
165
            " %s\nSecondaries: %s")
166
      (idx t) (f_mem t) ((f_disk t) `div` 1024)
167
      (commaJoin (map show (plist t)))
168
      (commaJoin (map show (slist t)))
169

    
170
-- | String converter for the node list functionality.
171
list :: String -> Node -> String
172
list n t =
173
    let pl = plist t
174
        sl = slist t
175
        (mp, dp) = normUsed t
176
    in
177
      printf "  %s(%d)\t%5d\t%5d\t%3d\t%3d\t%s\t%s\t%.5f\t%.5f"
178
                 n (idx t) (f_mem t) ((f_disk t) `div` 1024)
179
                 (length pl) (length sl)
180
                 (commaJoin (map show pl))
181
                 (commaJoin (map show sl))
182
                 mp dp
183

    
184
-- | Normalize the usage status
185
-- This converts the used memory and disk values into a normalized integer
186
-- value, currently expresed as per mille of totals
187

    
188
normUsed :: Node -> (Double, Double)
189
normUsed n =
190
    let mp = (fromIntegral $ f_mem n) / (fromIntegral $ t_mem n)
191
        dp = (fromIntegral $ f_disk n) / (fromIntegral $ t_disk n)
192
    in (mp, dp)