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
use std::fmt;
use thiserror::Error;
use crate::{AppData, NodeId};
pub type RaftResult<T> = std::result::Result<T, RaftError>;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum RaftError {
#[error("{0}")]
RaftStorage(anyhow::Error),
#[error("{0}")]
RaftNetwork(anyhow::Error),
#[error("Raft is shutting down")]
ShuttingDown,
}
impl From<tokio::io::Error> for RaftError {
fn from(src: tokio::io::Error) -> Self {
RaftError::RaftStorage(src.into())
}
}
#[derive(Debug, Error)]
pub enum ClientReadError {
#[error("{0}")]
RaftError(#[from] RaftError),
#[error("the client read request must be forwarded to the cluster leader")]
ForwardToLeader(Option<NodeId>),
}
#[derive(Error)]
pub enum ClientWriteError<D: AppData> {
#[error("{0}")]
RaftError(#[from] RaftError),
#[error("the client write request must be forwarded to the cluster leader")]
ForwardToLeader(D, Option<NodeId>),
}
impl<D: AppData> fmt::Debug for ClientWriteError<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ClientWriteError::RaftError(err) => f.debug_tuple("RaftError").field(err).finish(),
ClientWriteError::ForwardToLeader(_req, node_id) => {
f.debug_tuple("ForwardToLeader").field(node_id).finish()
}
}
}
}
#[derive(Debug, Error, Eq, PartialEq)]
#[non_exhaustive]
pub enum ConfigError {
#[error(
"given values for election timeout min & max are invalid: max must be greater than min"
)]
InvalidElectionTimeoutMinMax,
#[error("the given value for max_payload_entries is too small, must be > 0")]
MaxPayloadEntriesTooSmall,
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum InitializeError {
#[error("{0}")]
RaftError(#[from] RaftError),
#[error("the requested action is not allowed due to the Raft node's current state")]
NotAllowed,
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ChangeConfigError {
#[error("{0}")]
RaftError(#[from] RaftError),
#[error("the cluster is already undergoing a configuration change")]
ConfigChangeInProgress,
#[error("the given config would leave the cluster in an inoperable state")]
InoperableConfig,
#[error("this node is not the Raft leader")]
NodeNotLeader(Option<NodeId>),
#[error("the proposed config change would have no effect, this is a no-op")]
Noop,
#[error("could not bring up the node to speed before adding it to cluster, thus gave up.")]
NodeFailedToCatchUp(NodeId),
}
impl<D: AppData> From<ClientWriteError<D>> for ChangeConfigError {
fn from(src: ClientWriteError<D>) -> Self {
match src {
ClientWriteError::RaftError(err) => Self::RaftError(err),
ClientWriteError::ForwardToLeader(_, id) => Self::NodeNotLeader(id),
}
}
}