exocore_core/cell/
cell_nodes.rs1use std::{
2 collections::{HashMap, HashSet},
3 sync::{RwLockReadGuard, RwLockWriteGuard},
4};
5
6use exocore_protos::generated::exocore_core::cell_node_config;
7
8use super::{Cell, Error, LocalNode, Node, NodeId};
9
10pub trait CellNodes {
12 fn cell(&self) -> &Cell;
13 fn nodes_map(&self) -> &HashMap<NodeId, CellNode>;
14
15 fn local_node(&self) -> &LocalNode {
16 self.cell().local_node()
17 }
18
19 fn local_cell_node(&self) -> &CellNode {
20 let local_node = self.cell().local_node();
21 self.nodes_map()
22 .get(local_node.id())
23 .expect("Local node couldn't be found in cell nodes")
24 }
25
26 fn count(&self) -> usize {
27 self.nodes_map().len()
28 }
29
30 fn count_with_role(&self, role: CellNodeRole) -> usize {
31 self.nodes_map()
32 .values()
33 .filter(|cn| cn.has_role(role))
34 .count()
35 }
36
37 fn is_empty(&self) -> bool {
38 self.count() == 0
39 }
40
41 fn get(&self, node_id: &NodeId) -> Option<&CellNode> {
42 self.nodes_map().get(node_id)
43 }
44
45 fn has_quorum(&self, count: usize, role: Option<CellNodeRole>) -> bool {
46 let nb_nodes = if let Some(role) = role {
47 self.count_with_role(role)
48 } else {
49 self.count()
50 };
51
52 if nb_nodes == 0 {
53 false
54 } else {
55 count > nb_nodes / 2
56 }
57 }
58
59 fn to_owned(&self) -> CellNodesOwned {
60 CellNodesOwned {
61 cell: self.cell().clone(),
62 nodes: self.nodes_map().clone(),
63 }
64 }
65}
66
67#[derive(Clone)]
69pub struct CellNode {
70 node: Node,
71 roles: HashSet<CellNodeRole>,
72}
73
74impl CellNode {
75 pub fn new(node: Node) -> CellNode {
76 CellNode {
77 node,
78 roles: HashSet::new(),
79 }
80 }
81
82 pub fn node(&self) -> &Node {
83 &self.node
84 }
85
86 pub fn add_role(&mut self, role: CellNodeRole) {
87 self.roles.insert(role);
88 }
89
90 pub fn remove_role(&mut self, role: CellNodeRole) {
91 self.roles.remove(&role);
92 }
93
94 pub fn roles(&self) -> Vec<CellNodeRole> {
95 self.roles.iter().cloned().collect()
96 }
97
98 pub fn has_role(&self, role: CellNodeRole) -> bool {
99 self.roles.contains(&role)
100 }
101}
102
103pub struct CellNodesIter<'cn, N: CellNodes> {
107 nodes: &'cn N,
108}
109
110impl<'cn, N: CellNodes> CellNodesIter<'cn, N> {
111 pub fn all(&self) -> impl Iterator<Item = &CellNode> {
112 self.nodes.nodes_map().values()
113 }
114
115 pub fn all_except<'a>(
116 &'a self,
117 node_id: &'a NodeId,
118 ) -> impl Iterator<Item = &'a CellNode> + 'a {
119 self.nodes
120 .nodes_map()
121 .values()
122 .filter(move |n| n.node.id() != node_id)
123 }
124
125 pub fn all_except_local(&self) -> impl Iterator<Item = &CellNode> {
126 let local_node = self.nodes.cell().local_node();
127 self.all_except(local_node.id())
128 }
129
130 pub fn with_role(&self, role: CellNodeRole) -> impl Iterator<Item = &CellNode> {
131 self.nodes
132 .nodes_map()
133 .values()
134 .filter(move |cn| cn.has_role(role))
135 }
136}
137
138pub struct CellNodesRead<'cell> {
140 pub(crate) cell: &'cell Cell,
141 pub(crate) nodes: RwLockReadGuard<'cell, HashMap<NodeId, CellNode>>,
142}
143
144impl<'cell> CellNodesRead<'cell> {
145 pub fn iter(&self) -> CellNodesIter<CellNodesRead> {
146 CellNodesIter { nodes: self }
147 }
148}
149
150impl<'cell> CellNodes for CellNodesRead<'cell> {
151 fn cell(&self) -> &Cell {
152 self.cell
153 }
154
155 fn nodes_map(&self) -> &HashMap<NodeId, CellNode> {
156 &self.nodes
157 }
158}
159
160pub struct CellNodesWrite<'cell> {
162 pub(crate) cell: &'cell Cell,
163 pub(crate) nodes: RwLockWriteGuard<'cell, HashMap<NodeId, CellNode>>,
164}
165
166impl<'cell> CellNodesWrite<'cell> {
167 pub fn iter(&self) -> CellNodesIter<CellNodesWrite> {
168 CellNodesIter { nodes: self }
169 }
170
171 pub fn add(&mut self, node: Node) {
172 self.add_cell_node(CellNode {
173 node,
174 roles: HashSet::new(),
175 });
176 }
177
178 pub fn add_cell_node(&mut self, cell_node: CellNode) {
179 self.nodes.insert(cell_node.node.id().clone(), cell_node);
180 }
181
182 pub fn get_mut(&mut self, node_id: &NodeId) -> Option<&mut CellNode> {
183 self.nodes.get_mut(node_id)
184 }
185
186 pub fn local_cell_node_mut(&mut self) -> &mut CellNode {
187 let id = {
188 let local_node = self.cell().local_node();
189 local_node.id().clone()
190 };
191 self.nodes
192 .get_mut(&id)
193 .expect("Local node couldn't be found in cell nodes")
194 }
195}
196
197impl<'cell> CellNodes for CellNodesWrite<'cell> {
198 fn cell(&self) -> &Cell {
199 self.cell
200 }
201
202 fn nodes_map(&self) -> &HashMap<NodeId, CellNode> {
203 &self.nodes
204 }
205}
206
207pub struct CellNodesOwned {
209 pub(crate) cell: Cell,
210 pub(crate) nodes: HashMap<NodeId, CellNode>,
211}
212
213impl CellNodesOwned {
214 pub fn iter(&self) -> CellNodesIter<CellNodesOwned> {
215 CellNodesIter { nodes: self }
216 }
217}
218
219impl CellNodes for CellNodesOwned {
220 fn cell(&self) -> &Cell {
221 &self.cell
222 }
223
224 fn nodes_map(&self) -> &HashMap<NodeId, CellNode> {
225 &self.nodes
226 }
227}
228
229#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
231pub enum CellNodeRole {
232 Chain,
234
235 Store,
237
238 AppHost,
240}
241
242impl CellNodeRole {
243 pub fn from_config(config: cell_node_config::Role) -> Result<CellNodeRole, Error> {
244 match config {
245 cell_node_config::Role::ChainRole => Ok(CellNodeRole::Chain),
246 cell_node_config::Role::StoreRole => Ok(CellNodeRole::Store),
247 cell_node_config::Role::AppHostRole => Ok(CellNodeRole::AppHost),
248 cell_node_config::Role::InvalidRole => {
249 Err(Error::Cell(anyhow!("Invalid cell node role")))
250 }
251 }
252 }
253
254 pub fn to_config(&self) -> cell_node_config::Role {
255 match self {
256 CellNodeRole::Chain => cell_node_config::Role::ChainRole,
257 CellNodeRole::Store => cell_node_config::Role::StoreRole,
258 CellNodeRole::AppHost => cell_node_config::Role::AppHostRole,
259 }
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::{super::FullCell, *};
266
267 #[test]
268 fn nodes_add_get() {
269 let local_node = LocalNode::generate();
270 let full_cell = FullCell::generate(local_node.clone()).unwrap();
271
272 {
273 let nodes = full_cell.cell().nodes();
274 assert!(!nodes.is_empty());
275 assert_eq!(nodes.count(), 1); }
277
278 {
279 let mut nodes = full_cell.cell().nodes_mut();
280 nodes.add(Node::generate_temporary());
281 assert_eq!(nodes.count(), 2);
282 assert_eq!(nodes.iter().all().count(), 2);
283 }
284
285 {
286 let nodes = full_cell.cell().nodes();
287 assert_eq!(nodes.count(), 2);
288 assert_eq!(nodes.iter().all().count(), 2);
289 assert_eq!(nodes.iter().all_except(local_node.id()).count(), 1);
290 assert_ne!(
291 nodes.iter().all_except_local().next().unwrap().node.id(),
292 local_node.id()
293 );
294
295 assert!(nodes.get(local_node.id()).is_some());
296
297 let other_node = Node::generate_temporary();
298 assert!(nodes.get(other_node.id()).is_none());
299 }
300
301 {
302 let nodes = full_cell.cell().nodes().to_owned();
303 assert_eq!(nodes.count(), 2);
304 }
305 }
306
307 #[test]
308 fn nodes_quorum() {
309 let local_node = LocalNode::generate();
310 let full_cell = FullCell::generate(local_node).unwrap();
311
312 {
313 let nodes = full_cell.cell().nodes();
315 assert!(!nodes.has_quorum(0, None));
316 assert!(nodes.has_quorum(1, None));
317 assert!(!nodes.has_quorum(0, Some(CellNodeRole::Chain)));
318 assert!(!nodes.has_quorum(1, Some(CellNodeRole::Chain)));
319 }
320
321 {
322 let mut nodes = full_cell.cell().nodes_mut();
324 nodes.add(Node::generate_temporary());
325 assert!(!nodes.has_quorum(1, None));
326 assert!(nodes.has_quorum(2, None));
327 }
328
329 {
330 let mut nodes = full_cell.cell().nodes_mut();
332 nodes.add(Node::generate_temporary());
333 assert!(!nodes.has_quorum(1, None));
334 assert!(nodes.has_quorum(2, None));
335 }
336
337 {
338 let mut nodes = full_cell.cell().nodes_mut();
340 let ids = nodes
341 .iter()
342 .all()
343 .map(|n| n.node.id())
344 .cloned()
345 .collect::<Vec<_>>();
346 nodes
347 .get_mut(&ids[0])
348 .unwrap()
349 .add_role(CellNodeRole::Chain);
350 nodes
351 .get_mut(&ids[1])
352 .unwrap()
353 .add_role(CellNodeRole::Chain);
354
355 assert!(!nodes.has_quorum(1, Some(CellNodeRole::Chain)));
356 assert!(nodes.has_quorum(2, Some(CellNodeRole::Chain)));
357 }
358 }
359}