1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Replication node types.
//!
/// The type of a node within a replication group.
///
/// Each node type determines what role the node can play in the group,
/// whether it participates in elections, and whether it stores data.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum NodeType {
/// An electable node that can serve as either master or replica.
/// Electable nodes participate in elections and store a complete
/// copy of the data.
Electable,
/// A monitor node that observes group state changes but does not
/// participate in elections or store data. Monitors receive
/// notifications about master changes and group membership.
Monitor,
/// A secondary node that replicates data from the master but
/// cannot be elected master. Secondary nodes do not participate
/// in elections or contribute to quorum calculations.
Secondary,
/// An arbiter node used for tie-breaking in elections. Arbiters
/// participate in elections and acknowledge transactions but do
/// not store a full copy of the data.
Arbiter,
}
impl NodeType {
/// Returns `true` if this node type can participate in elections.
///
/// Electable nodes and arbiters participate in elections.
pub fn is_electable(&self) -> bool {
matches!(self, NodeType::Electable | NodeType::Arbiter)
}
/// Returns `true` if this node type stores a full copy of the data.
///
/// Electable and secondary nodes are data nodes.
pub fn is_data_node(&self) -> bool {
matches!(self, NodeType::Electable | NodeType::Secondary)
}
/// Returns `true` if this node type can become master.
///
/// Only electable nodes can become master.
pub fn can_be_master(&self) -> bool {
matches!(self, NodeType::Electable)
}
}
impl std::fmt::Display for NodeType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NodeType::Electable => write!(f, "ELECTABLE"),
NodeType::Monitor => write!(f, "MONITOR"),
NodeType::Secondary => write!(f, "SECONDARY"),
NodeType::Arbiter => write!(f, "ARBITER"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_is_electable() {
assert!(NodeType::Electable.is_electable());
assert!(!NodeType::Monitor.is_electable());
assert!(!NodeType::Secondary.is_electable());
assert!(NodeType::Arbiter.is_electable());
}
#[test]
fn test_is_data_node() {
assert!(NodeType::Electable.is_data_node());
assert!(!NodeType::Monitor.is_data_node());
assert!(NodeType::Secondary.is_data_node());
assert!(!NodeType::Arbiter.is_data_node());
}
#[test]
fn test_can_be_master() {
assert!(NodeType::Electable.can_be_master());
assert!(!NodeType::Monitor.can_be_master());
assert!(!NodeType::Secondary.can_be_master());
assert!(!NodeType::Arbiter.can_be_master());
}
#[test]
fn test_display() {
assert_eq!(NodeType::Electable.to_string(), "ELECTABLE");
assert_eq!(NodeType::Monitor.to_string(), "MONITOR");
assert_eq!(NodeType::Secondary.to_string(), "SECONDARY");
assert_eq!(NodeType::Arbiter.to_string(), "ARBITER");
}
#[test]
fn test_clone_and_copy() {
let nt = NodeType::Electable;
let cloned = nt;
let copied = nt;
assert_eq!(nt, cloned);
assert_eq!(nt, copied);
}
#[test]
fn test_eq_and_hash() {
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(NodeType::Electable);
set.insert(NodeType::Monitor);
set.insert(NodeType::Secondary);
set.insert(NodeType::Arbiter);
assert_eq!(set.len(), 4);
// Duplicate insert should not increase size.
set.insert(NodeType::Electable);
assert_eq!(set.len(), 4);
}
#[test]
fn test_debug() {
let s = format!("{:?}", NodeType::Electable);
assert_eq!(s, "Electable");
}
}