Statistics
| Branch: | Tag: | Revision:

root / src / Node.hs @ 38f63ae6

History | View | Annotate | Download (7 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_dsk, p_mem, p_dsk, 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
    , setPri
21
    , setSec
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 :: Double -- ^ total memory (Mib)
36
                 , f_mem :: Int    -- ^ free memory (MiB)
37
                 , t_dsk :: Double -- ^ total disk space (MiB)
38
                 , f_dsk :: 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
                 , p_mem :: Double
48
                 , p_dsk :: Double
49
  } deriving (Show)
50

    
51
{- | Create a new node.
52

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

    
56
-}
57
create :: String -> String -> String -> String -> Node
58
create mem_t_init mem_f_init dsk_t_init dsk_f_init =
59
    let mem_t = read mem_t_init
60
        mem_f = read mem_f_init
61
        dsk_t = read dsk_t_init
62
        dsk_f = read dsk_f_init
63
    in
64
      Node
65
      {
66
       t_mem = read mem_t_init,
67
       f_mem = read mem_f_init,
68
       t_dsk = read dsk_t_init,
69
       f_dsk = read dsk_f_init,
70
       plist = [],
71
       slist = [],
72
       failN1 = True,
73
       idx = -1,
74
       peers = PeerMap.empty,
75
       maxRes = 0,
76
       p_mem = (fromIntegral mem_f) / (fromIntegral mem_t),
77
       p_dsk = (fromIntegral dsk_f) / (fromIntegral dsk_t)
78
      }
79

    
80
-- | Changes the index.
81
-- This is used only during the building of the data structures.
82
setIdx :: Node -> Int -> Node
83
setIdx t i = t {idx = i}
84

    
85
-- | Given the rmem, free memory and disk, computes the failn1 status.
86
computeFailN1 :: Int -> Int -> Int -> Bool
87
computeFailN1 new_rmem new_mem new_dsk =
88
    new_mem <= new_rmem || new_dsk <= 0
89

    
90
-- | Computes the maximum reserved memory for peers from a peer map.
91
computeMaxRes :: PeerMap.PeerMap -> PeerMap.Elem
92
computeMaxRes new_peers = PeerMap.maxElem new_peers
93

    
94
-- | Builds the peer map for a given node.
95
buildPeers :: Node -> Container.Container Instance.Instance -> Int -> Node
96
buildPeers t il num_nodes =
97
    let mdata = map
98
                (\i_idx -> let inst = Container.find i_idx il
99
                           in (Instance.pnode inst, Instance.mem inst))
100
                (slist t)
101
        pmap = PeerMap.accumArray (+) 0 (0, num_nodes - 1) mdata
102
        new_rmem = computeMaxRes pmap
103
        new_failN1 = computeFailN1 new_rmem (f_mem t) (f_dsk t)
104
    in t {peers=pmap, failN1 = new_failN1, maxRes = new_rmem}
105

    
106
-- | Removes a primary instance.
107
removePri :: Node -> Instance.Instance -> Node
108
removePri t inst =
109
    let iname = Instance.idx inst
110
        new_plist = delete iname (plist t)
111
        new_mem = f_mem t + Instance.mem inst
112
        new_dsk = f_dsk t + Instance.dsk inst
113
        new_mp = (fromIntegral new_mem) / (t_mem t)
114
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
115
        new_failn1 = computeFailN1 (maxRes t) new_mem new_dsk
116
    in t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
117
          failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
118

    
119
-- | Removes a secondary instance.
120
removeSec :: Node -> Instance.Instance -> Node
121
removeSec t inst =
122
    let iname = Instance.idx inst
123
        pnode = Instance.pnode inst
124
        new_slist = delete iname (slist t)
125
        new_dsk = f_dsk t + Instance.dsk inst
126
        old_peers = peers t
127
        old_peem = PeerMap.find pnode old_peers
128
        new_peem =  old_peem - (Instance.mem inst)
129
        new_peers = PeerMap.add pnode new_peem old_peers
130
        old_rmem = maxRes t
131
        new_rmem = if old_peem < old_rmem then
132
                       old_rmem
133
                   else
134
                       computeMaxRes new_peers
135
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk
136
        new_dp = (fromIntegral new_dsk) / (t_dsk t)
137
    in t {slist = new_slist, f_dsk = new_dsk, peers = new_peers,
138
          failN1 = new_failn1, maxRes = new_rmem, p_dsk = new_dp}
139

    
140
-- | Adds a primary instance.
141
addPri :: Node -> Instance.Instance -> Maybe Node
142
addPri t inst =
143
    let iname = Instance.idx inst
144
        new_mem = f_mem t - Instance.mem inst
145
        new_dsk = f_dsk t - Instance.dsk inst
146
        new_failn1 = computeFailN1 (maxRes t) new_mem new_dsk in
147
      if new_failn1 then
148
        Nothing
149
      else
150
        let new_plist = iname:(plist t)
151
            new_mp = (fromIntegral new_mem) / (t_mem t)
152
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
153
        in
154
        Just t {plist = new_plist, f_mem = new_mem, f_dsk = new_dsk,
155
                failN1 = new_failn1, p_mem = new_mp, p_dsk = new_dp}
156

    
157
-- | Adds a secondary instance.
158
addSec :: Node -> Instance.Instance -> Int -> Maybe Node
159
addSec t inst pdx =
160
    let iname = Instance.idx inst
161
        old_peers = peers t
162
        new_dsk = f_dsk t - Instance.dsk inst
163
        new_peem = PeerMap.find pdx old_peers + Instance.mem inst
164
        new_peers = PeerMap.add pdx new_peem old_peers
165
        new_rmem = max (maxRes t) new_peem
166
        new_failn1 = computeFailN1 new_rmem (f_mem t) new_dsk in
167
    if new_failn1 then
168
        Nothing
169
    else
170
        let new_slist = iname:(slist t)
171
            new_dp = (fromIntegral new_dsk) / (t_dsk t)
172
        in
173
        Just t {slist = new_slist, f_dsk = new_dsk,
174
                peers = new_peers, failN1 = new_failn1,
175
                maxRes = new_rmem, p_dsk = new_dp}
176

    
177
-- | Add a primary instance to a node without other updates
178
setPri :: Node -> Int -> Node
179
setPri t idx = t { plist = idx:(plist t) }
180

    
181
-- | Add a secondary instance to a node without other updates
182
setSec :: Node -> Int -> Node
183
setSec t idx = t { slist = idx:(slist t) }
184

    
185
-- | Simple converter to string.
186
str :: Node -> String
187
str t =
188
    printf ("Node %d (mem=%5d MiB, disk=%5.2f GiB)\n  Primaries:" ++
189
            " %s\nSecondaries: %s")
190
      (idx t) (f_mem t) ((f_dsk t) `div` 1024)
191
      (commaJoin (map show (plist t)))
192
      (commaJoin (map show (slist t)))
193

    
194
-- | String converter for the node list functionality.
195
list :: String -> Node -> String
196
list n t =
197
    let pl = plist t
198
        sl = slist t
199
        mp = p_mem t
200
        dp = p_dsk t
201
    in
202
      printf "  %s(%d)\t%5d\t%5d\t%3d\t%3d\t%s\t%s\t%.5f\t%.5f"
203
                 n (idx t) (f_mem t) ((f_dsk t) `div` 1024)
204
                 (length pl) (length sl)
205
                 (commaJoin (map show pl))
206
                 (commaJoin (map show sl))
207
                 mp dp