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
56pub mod client;
57mod commit_handler;
58pub mod config;
59mod election;
60mod errors;
61mod event;
62mod maybe_clone_oneshot;
63mod membership;
64mod network;
65mod purge;
66mod raft;
67mod raft_context;
68mod raft_role;
69mod replication;
70mod state_machine_handler;
71mod timer;
72mod type_config;
73mod utils;
74
75pub mod storage;
76
77#[cfg(feature = "watch")]
78pub mod watch;
79
80pub use client::*;
81pub use commit_handler::*;
82pub use config::*;
83pub use election::*;
84pub use errors::*;
85pub use event::*;
86pub use maybe_clone_oneshot::*;
87pub use membership::*;
88pub use network::*;
89pub use purge::*;
90pub use raft::*;
91pub use raft_context::*;
92pub use replication::*;
93pub use state_machine_handler::*;
94pub use storage::*;
95#[cfg(feature = "watch")]
96pub use watch::*;
97
98#[cfg(test)]
99mod raft_test;
100
101#[doc(hidden)]
102pub use raft_role::*;
103pub(crate) use timer::*;
104#[doc(hidden)]
105pub use type_config::*;
106#[doc(hidden)]
107pub use utils::*;
108
109#[cfg(test)]
110mod maybe_clone_oneshot_test;
111
112#[cfg(test)]
113mod errors_test;
114#[cfg(test)]
115mod raft_oneshot_test;
116
117/// Internal test utilities - not part of public API
118#[cfg(any(test, feature = "__test_support"))]
119#[doc(hidden)]
120pub mod test_utils;
121
122#[cfg(any(test, feature = "__test_support"))]
123pub use test_utils::*;
124
125/// In raft, during any Leader to Peer communication,
126/// if received response term is bigger than Leader's,
127/// the current Leader need downgrade to follower
128/// and update its term to higher one.
129///
130/// e.g. Append Entries RPC
131/// e.g. Election: receive VoteResponse
132/// e.g. Sync cluster membership configure
133/// @return: true - found higher term;
134pub(crate) fn if_higher_term_found(
135 my_current_term: u64,
136 term: u64,
137 is_learner: bool,
138) -> bool {
139 //means I am fake leader or we should ignore learner's response
140 if !is_learner && my_current_term < term {
141 tracing::warn!("my_current_term: {} < term: {} ?", my_current_term, term);
142 return true;
143 }
144
145 false
146}
147
148/// Raft paper: 5.4.1 Election restriction
149///
150/// Raft determines which of two logs is more up-to-date by comparing the index and term of the last
151/// entries in the logs. If the logs have last entries with different terms, then the log with the
152/// later term is more up-to-date. If the logs end with the same term, then whichever log is longer
153/// is more up-to-date.
154#[tracing::instrument]
155pub(crate) fn is_target_log_more_recent(
156 my_last_log_index: u64,
157 my_last_log_term: u64,
158 target_last_log_index: u64,
159 target_last_log_term: u64,
160) -> bool {
161 (target_last_log_term > my_last_log_term)
162 || (target_last_log_term == my_last_log_term && target_last_log_index >= my_last_log_index)
163}
164
165#[derive(Debug, Clone, Copy)]
166pub enum QuorumStatus {
167 Confirmed, // Confirmed by the majority of nodes
168 LostQuorum, // Unable to obtain majority
169 NetworkError, // Network problem (can be retried)
170}