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) |