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
131
132
133
134
//! Membership change operations and types.
//!
//! This module defines the various types of membership changes that can be performed
//! on a Raft cluster, such as adding voters, removing voters, or replacing the entire membership.
use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::fmt;
use display_more::DisplayBTreeSetExt;
use display_more::DisplaySliceExt;
use openraft_macros::since;
use crate::display_ext::DisplayBTreeMapDebugValueExt;
use crate::node::Node;
use crate::node::NodeId;
/// Defines various actions to change the membership, including adding or removing learners or
/// voters.
#[since(
version = "0.10.0",
change = "replaced `C: RaftTypeConfig` with `NID: NodeId, N: Node`"
)]
#[since(version = "0.8.0")]
#[derive(Debug, Clone)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize), serde(bound = ""))]
pub enum ChangeMembers<NID, N>
where
NID: NodeId,
N: Node,
{
/// Upgrade learners to voters.
///
/// The learners have to present or [`error::LearnerNotFound`](`crate::error::LearnerNotFound`)
/// error will be returned.
AddVoterIds(BTreeSet<NID>),
/// Add voters with corresponding nodes.
AddVoters(BTreeMap<NID, N>),
/// Remove voters, leave removed voters as learner or not.
RemoveVoters(BTreeSet<NID>),
/// Replace voter ids with a new set. The node of every new voter has to already be a learner.
ReplaceAllVoters(BTreeSet<NID>),
/// Add nodes to membership, as learners.
///
/// it **WON'T** replace existing node.
///
/// Prefer using this variant instead of `SetNodes` whenever possible, as `AddNodes` ensures
/// safety, whereas incorrect usage of `SetNodes` can result in a brain split.
/// See: [Update-Node](`crate::docs::cluster_control::dynamic_membership#update-node`)
AddNodes(BTreeMap<NID, N>),
/// Add or replace nodes in membership config.
///
/// it **WILL** replace an existing node.
///
/// Prefer using `AddNodes` instead of `SetNodes` whenever possible, as `AddNodes` ensures
/// safety, whereas incorrect usage of `SetNodes` can result in a brain split.
/// See: [Update-Node](`crate::docs::cluster_control::dynamic_membership#update-node`)
SetNodes(BTreeMap<NID, N>),
/// Remove nodes from membership.
///
/// If a node is still a voter, it returns
/// [`error::LearnerNotFound`](`crate::error::LearnerNotFound`) error.
RemoveNodes(BTreeSet<NID>),
/// Replace all nodes with a new set.
///
/// Every voter has to have a corresponding node in the new
/// set, otherwise it returns [`error::LearnerNotFound`](`crate::error::LearnerNotFound`) error.
ReplaceAllNodes(BTreeMap<NID, N>),
/// Apply multiple changes to membership config.
///
/// The changes are applied in the order they are given.
/// And it still finishes in a two-step joint config change.
Batch(Vec<ChangeMembers<NID, N>>),
}
/// Convert a series of ids to a `Replace` operation.
impl<NID, N, I> From<I> for ChangeMembers<NID, N>
where
NID: NodeId,
N: Node,
I: IntoIterator<Item = NID>,
{
fn from(r: I) -> Self {
let ids = r.into_iter().collect::<BTreeSet<NID>>();
ChangeMembers::ReplaceAllVoters(ids)
}
}
impl<NID, N> fmt::Display for ChangeMembers<NID, N>
where
NID: NodeId,
N: Node,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ChangeMembers::AddVoterIds(ids) => {
write!(f, "AddVoterIds({})", ids.display())
}
ChangeMembers::AddVoters(nodes) => {
write!(f, "AddVoters({})", nodes.display())
}
ChangeMembers::RemoveVoters(ids) => {
write!(f, "RemoveVoters({})", ids.display())
}
ChangeMembers::ReplaceAllVoters(ids) => {
write!(f, "ReplaceAllVoters({})", ids.display())
}
ChangeMembers::AddNodes(nodes) => {
write!(f, "AddNodes({})", nodes.display())
}
ChangeMembers::SetNodes(nodes) => {
write!(f, "SetNodes({})", nodes.display())
}
ChangeMembers::RemoveNodes(ids) => {
write!(f, "RemoveNodes({})", ids.display())
}
ChangeMembers::ReplaceAllNodes(nodes) => {
write!(f, "ReplaceAllNodes({})", nodes.display())
}
ChangeMembers::Batch(changes) => {
write!(f, "Batch({})", changes.as_slice().display_n(1024))
}
}
}
}