d_engine_core/lib.rs
1//! # d-engine-core
2//!
3//! Pure Raft consensus algorithm - for building custom Raft-based systems
4//!
5//! ## ⚠️ Internal Crate - Not Ready for Standalone Use
6//!
7//! **Use [`d-engine`](https://crates.io/crates/d-engine) instead.**
8//!
9//! This crate contains the pure Raft consensus algorithm used internally by d-engine.
10//! The API is unstable before v1.0.
11//!
12//! ```toml
13//! # ❌ Don't use this directly
14//! [dependencies]
15//! d-engine-core = "0.2"
16//!
17//! # ✅ Use this instead
18//! [dependencies]
19//! d-engine = "0.2"
20//! ```
21//!
22//! ## For Contributors
23//!
24//! ## What this crate provides
25//!
26//! This crate focuses solely on the Raft consensus algorithm:
27//!
28//! - **Leader Election** - Automatic leader election with randomized timeouts
29//! - **Log Replication** - Reliable log replication to followers
30//! - **Membership Changes** - Dynamic cluster membership changes
31//! - **Snapshot Support** - Log compaction via snapshots
32//!
33//! Storage, networking, and state machine implementation are **your responsibility**.
34//!
35//! **Reference integration**: See how [d-engine-server](https://github.com/deventlab/d-engine/tree/main/d-engine-server) uses this crate.
36//!
37//! ## Future Vision
38//!
39//! **Post-1.0 goal**: Become a standalone Raft library with stable API.
40//!
41//! **Current status**: Internal to d-engine, API may change between minor versions.
42//!
43//! ## Key Traits
44//!
45//! - [`StorageEngine`] - Persistent storage for Raft logs
46//! - [`StateMachine`] - Application-specific state transitions
47//! - [`LogStore`] - Log entry persistence
48//! - [`MetaStore`] - Metadata persistence (term, voted_for)
49//!
50//! ## Documentation
51//!
52//! For comprehensive guides:
53//! - [Customize Storage Engine](https://docs.rs/d-engine/latest/d_engine/docs/server_guide/customize_storage_engine/index.html)
54//! - [Customize State Machine](https://docs.rs/d-engine/latest/d_engine/docs/server_guide/customize_state_machine/index.html)
55
56mod commit_handler;
57pub mod config;
58mod election;
59mod errors;
60mod event;
61mod maybe_clone_oneshot;
62mod membership;
63mod network;
64mod purge;
65mod raft;
66mod raft_context;
67mod raft_role;
68mod replication;
69mod state_machine_handler;
70mod storage;
71mod timer;
72mod type_config;
73mod utils;
74
75#[cfg(feature = "watch")]
76pub mod watch;
77
78pub use commit_handler::*;
79pub use config::*;
80pub use election::*;
81pub use errors::*;
82pub use event::*;
83pub use maybe_clone_oneshot::*;
84pub use membership::*;
85pub use network::*;
86pub use purge::*;
87pub use raft::*;
88pub use raft_context::*;
89pub use replication::*;
90pub use state_machine_handler::*;
91pub use storage::*;
92#[cfg(feature = "watch")]
93pub use watch::*;
94
95#[cfg(test)]
96mod raft_test;
97
98#[doc(hidden)]
99pub use raft_role::*;
100pub(crate) use timer::*;
101#[doc(hidden)]
102pub use type_config::*;
103#[doc(hidden)]
104pub use utils::*;
105
106#[cfg(test)]
107mod maybe_clone_oneshot_test;
108
109#[cfg(test)]
110mod errors_test;
111#[cfg(test)]
112mod raft_oneshot_test;
113
114#[cfg(any(test, feature = "test-utils"))]
115pub mod test_utils;
116
117#[cfg(any(test, feature = "test-utils"))]
118pub use test_utils::*;
119
120/// In raft, during any Leader to Peer communication,
121/// if received response term is bigger than Leader's,
122/// the current Leader need downgrade to follower
123/// and update its term to higher one.
124///
125/// e.g. Append Entries RPC
126/// e.g. Election: receive VoteResponse
127/// e.g. Sync cluster membership configure
128/// @return: true - found higher term;
129pub(crate) fn if_higher_term_found(
130 my_current_term: u64,
131 term: u64,
132 is_learner: bool,
133) -> bool {
134 //means I am fake leader or we should ignore learner's response
135 if !is_learner && my_current_term < term {
136 tracing::warn!("my_current_term: {} < term: {} ?", my_current_term, term);
137 return true;
138 }
139
140 false
141}
142
143/// Raft paper: 5.4.1 Election restriction
144///
145/// Raft determines which of two logs is more up-to-date by comparing the index and term of the last
146/// entries in the logs. If the logs have last entries with different terms, then the log with the
147/// later term is more up-to-date. If the logs end with the same term, then whichever log is longer
148/// is more up-to-date.
149#[tracing::instrument]
150pub(crate) fn is_target_log_more_recent(
151 my_last_log_index: u64,
152 my_last_log_term: u64,
153 target_last_log_index: u64,
154 target_last_log_term: u64,
155) -> bool {
156 (target_last_log_term > my_last_log_term)
157 || (target_last_log_term == my_last_log_term && target_last_log_index >= my_last_log_index)
158}
159
160#[derive(Debug, Clone, Copy)]
161pub enum QuorumStatus {
162 Confirmed, // Confirmed by the majority of nodes
163 LostQuorum, // Unable to obtain majority
164 NetworkError, // Network problem (can be retried)
165}