d_engine/
errors.rs

1use std::net::AddrParseError;
2
3use config::ConfigError;
4use thiserror::Error;
5use tokio::task::JoinError;
6
7use crate::proto::ClientRequestError;
8
9#[doc(hidden)]
10pub type Result<T> = std::result::Result<T, Error>;
11
12#[doc(hidden)]
13#[macro_export]
14macro_rules! define_error_mapping {
15    ($proto:ident, $app:ident; $($app_pattern:path => $proto_variant:path),+) => {
16        impl From<$app> for $proto {
17            fn from(e: $app) -> Self {
18                match e {
19                    $(
20                        $app_pattern => $proto_variant,
21                    )+
22                    _ => Self::Unknown,
23                }
24            }
25        }
26
27        impl From<$proto> for $app {
28            fn from(e: $proto) -> Self {
29                match e {
30                    $(
31                        $proto_variant => $app_pattern,
32                    )+
33                    _ => Self::ServerError,
34                }
35            }
36        }
37    };
38}
39
40/// Custom errors definition
41#[derive(Debug, Error)]
42pub enum Error {
43    /// General file IO error
44    #[error(transparent)]
45    IoError(#[from] std::io::Error),
46
47    /// Sled DB related error
48    #[error(transparent)]
49    SledError(#[from] sled::Error),
50
51    /// RPC framework tonic related error
52    #[error(transparent)]
53    TonicError(#[from] tonic::transport::Error),
54
55    /// General server error
56    #[error("General server error: {0}")]
57    GeneralServerError(String),
58
59    /// General server error without message
60    #[error("Server error")]
61    ServerError,
62
63    /// Bincode related error
64    #[error(transparent)]
65    BincodeError(#[from] bincode::Error),
66
67    /// Node start failed error
68    #[error("Node failed to start error")]
69    NodeFailedToStartError,
70
71    /// RPC connection error
72    #[error("Socket connect failed error")]
73    ConnectError,
74
75    /// Async task retry timeout error
76    #[error("Retry Timeout error")]
77    RetryTimeoutError,
78
79    /// State machine related error
80    #[error("State Machine error: {0}")]
81    StateMachinneError(String),
82
83    /// The request was sent to a follower or non-leader node; the client should retry with the
84    /// leader.
85    #[error("Dispatch client request leader error")]
86    NodeIsNotLeaderError,
87
88    /// The cluster has no known membership configuration; it may be unavailable or uninitialized.
89    #[error("Cluster is unavailable")]
90    ClusterMembershipNotFound,
91
92    /// Returned when the cluster has no elected leader or the leader is unknown.
93    /// This typically occurs during elections or network partitions.
94    #[error("No leader found")]
95    NoLeaderFound,
96
97    /// Returned when client `get_multi` is called without any keys.
98    #[error("No keys provided")]
99    EmptyKeys,
100
101    /// The response from the client response is invalid or missing expected data.
102    #[error("Invalid response")]
103    InvalidResponse,
104
105    /// Returned when the server response type does not match the expected variant for the
106    /// operation. Typically indicates a protocol mismatch or internal bug.
107    #[error("Invalid response type")]
108    InvalidResponseType,
109
110    /// Indicates failure to fetch or apply the latest cluster membership from the leader.
111    /// Additional context is included in the error message.
112    #[error("Failed to update cluster membership from leader, {0}")]
113    ClusterMembershipUpdateFailed(String),
114
115    /// Indicates that the Raft metadata for the given node ID was not found.
116    /// This usually occurs when the client or leader lacks an up-to-date cluster view,
117    /// or the node has not been properly registered in cluster membership.
118    ///
119    /// The `u32` parameter represents the node ID being queried.
120    #[error("Raft Metadata not found: {0}")]
121    ClusterMetadataNodeMetaNotFound(u32),
122
123    /// The follower could not confirm commitment of the log entry.
124    /// This may happen if the follower's log is not sufficiently up-to-date or quorum was not
125    /// reached.
126    #[error("AppendEntriesCommitNotConfirmed")]
127    AppendEntriesCommitNotConfirmed,
128
129    /// The current node rejected the AppendEntries request because it is not the leader.
130    /// Clients should redirect requests to the current cluster leader.
131    #[error("NotLeader")]
132    AppendEntriesNotLeader,
133
134    /// The target peer specified in the AppendEntries request was not found in the current cluster
135    /// view. This can occur if the membership view is outdated or the peer was removed.
136    #[error("No peer found")]
137    AppendEntriesNoPeerFound,
138
139    // The target peer failed to respond to the AppendEntries request within the expected timeout period.
140    /// Typically caused by network partitions, slow nodes, or overloaded peers.
141    #[error("ServerTimeoutResponding")]
142    AppendEntriesServerTimeoutResponding,
143
144    /// The node failed to win the election.
145    /// This could happen due to split vote, quorum not reached, or other election logic failure.
146    /// The error message may contain additional context such as vote count or term mismatch.
147    #[error("ElectionFailed: {0}")]
148    ElectionFailed(String),
149
150    /// Error occurred during a Raft state transition (e.g., follower → candidate, candidate →
151    /// leader). Propagates the underlying StateTransitionError.
152    #[error(transparent)]
153    StateTransitionError(#[from] StateTransitionError),
154
155    /// A message was received with a higher term than the local node's current term.
156    /// The node should step down and update its term accordingly.
157    #[error("Higher term found error: higher term = {0}")]
158    HigherTermFoundError(u64),
159
160    /// Receive Exist Signals
161    #[error("Exit")]
162    Exit,
163
164    /// Indicated RPC service stops serving
165    #[error("RPC server dies")]
166    RPCServerDies,
167
168    /// Indicate node is not ready to server request
169    #[error("Node is not ready error")]
170    ServerIsNotReadyError,
171
172    /// Receive status error from RPC service
173    #[error("Node status error: {0}")]
174    RPCServerStatusError(String),
175
176    /// The error is returned when the provided URI is invalid.
177    /// The error message will include the invalid URI for context.
178    #[error("invalid uri {0}")]
179    InvalidURI(String),
180
181    /// Indicates a failure to send a read request.
182    #[error("Failed to send read request error")]
183    FailedToSendReadRequestError,
184
185    /// Indicates a failure to send a write request.
186    #[error("Failed to send write request error")]
187    FailedToSendWriteRequestError,
188
189    /// A task retry failed, often due to reaching the maximum retry limit or encountering
190    /// persistent errors.
191    #[error("Task retry failed: {0}")]
192    RetryTaskFailed(String),
193
194    /// Address parsing error when invalid network address is encountered.
195    #[error(transparent)]
196    AddrParseError(#[from] AddrParseError),
197
198    /// Failed to set up a peer connection, possibly due to network or configuration issues.
199    /// The error message may contain more details about the failure.
200    #[error("Set peer connection failed: {0}")]
201    FailedSetPeerConnection(String),
202
203    /// General error indicating a configuration issue.
204    /// The error message will provide details about the specific configuration problem.
205    #[error(transparent)]
206    ConfigError(#[from] ConfigError),
207
208    /// Error encountered when sending a Tonic status via tokio.
209    /// The error message will include details about the status failure.
210    #[error("tokio send Tonic Status error: {0}")]
211    TokioSendStatusError(String),
212
213    //===== Role responbilitiies errors ====
214    /// The operation failed because the current node is not a leader.
215    #[error("Not Leader")]
216    NotLeader,
217
218    /// The operation failed because the node is a learner and cannot perform this action.
219    #[error("Learner can not handle")]
220    LearnerCanNot,
221
222    /// A generic error indicating an illegal state or operation.
223    #[error("Illegal")]
224    Illegal,
225
226    /// The error indicates that a state transition has failed.
227    #[error("Transition failed")]
228    TransitionFailed,
229
230    /// Error encountered when a tokio task join fails.
231    #[error(transparent)]
232    JoinError(#[from] JoinError),
233
234    //===== Client errors =====
235    //
236    /// General client request error
237    #[error("Client error: {0}")]
238    GeneralClientError(String),
239
240    //===== Config errors =====
241    //
242    /// Configuration is invalid. The error message will contain details about what is wrong with
243    /// the config.
244    #[error("Invalid config: {0}")]
245    InvalidConfig(String),
246}
247
248#[doc(hidden)]
249define_error_mapping!(
250    ClientRequestError, Error;
251    Error::AppendEntriesCommitNotConfirmed => ClientRequestError::CommitNotConfirmed,
252    Error::AppendEntriesNotLeader => ClientRequestError::NotLeader,
253    Error::AppendEntriesServerTimeoutResponding => ClientRequestError::ServerTimeout
254);
255
256#[derive(Debug, Error)]
257#[doc(hidden)]
258pub enum StateTransitionError {
259    #[error("Not enough votes to transition to leader.")]
260    NotEnoughVotes,
261
262    #[error("Invalid state transition.")]
263    InvalidTransition,
264
265    #[error("Lock error.")]
266    LockError,
267}