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;
57pub mod command;
58mod commit_handler;
59pub mod config;
60mod election;
61mod errors;
62mod event;
63mod maybe_clone_oneshot;
64mod membership;
65mod network;
66mod purge;
67mod raft;
68mod raft_context;
69mod raft_role;
70mod replication;
71mod state_machine_handler;
72mod timer;
73mod type_config;
74mod utils;
75
76pub mod storage;
77
78#[cfg(feature = "watch")]
79pub mod watch;
80
81// ── User-facing public API ──────────────────────────────────────────────────
82pub use client::*;
83pub use command::*;
84pub use config::*;
85pub use errors::*;
86pub use storage::*;
87#[cfg(feature = "watch")]
88pub use watch::*;
89
90// Stable extension points — types developers need when implementing custom
91// storage engines, state machines, or transport layers.
92pub use membership::Membership;
93pub use network::Transport;
94pub use purge::PurgeExecutor;
95pub use raft::{LeaderInfo, Raft, SignalParams};
96pub use state_machine_handler::{SnapshotPolicy, StateMachineHandler};
97pub use type_config::TypeConfig;
98
99// ── Internal implementation details (not part of public API) ───────────────
100// These remain accessible to d-engine-server but are hidden from cargo doc.
101// Do not depend on these from external crates.
102#[doc(hidden)]
103pub use commit_handler::*;
104#[doc(hidden)]
105pub use election::*;
106#[doc(hidden)]
107pub use event::*;
108#[doc(hidden)]
109pub use maybe_clone_oneshot::*;
110#[doc(hidden)]
111pub use membership::*;
112#[doc(hidden)]
113pub use network::*;
114#[doc(hidden)]
115pub use purge::*;
116#[doc(hidden)]
117pub use raft_context::*;
118#[doc(hidden)]
119pub use raft_role::*;
120#[doc(hidden)]
121pub use replication::*;
122#[doc(hidden)]
123pub use state_machine_handler::*;
124#[doc(hidden)]
125pub use type_config::*;
126#[doc(hidden)]
127pub use utils::*;
128
129pub(crate) use timer::*;
130
131#[cfg(test)]
132mod command_test;
133#[cfg(test)]
134mod maybe_clone_oneshot_test;
135
136#[cfg(test)]
137mod errors_test;
138#[cfg(test)]
139mod raft_oneshot_test;
140
141/// Internal test utilities - not part of public API
142#[cfg(any(test, feature = "__test_support"))]
143#[doc(hidden)]
144pub mod test_utils;
145
146#[cfg(any(test, feature = "__test_support"))]
147pub use test_utils::*;
148
149/// In raft, during any Leader to Peer communication,
150/// if received response term is bigger than Leader's,
151/// the current Leader need downgrade to follower
152/// and update its term to higher one.
153///
154/// e.g. Append Entries RPC
155/// e.g. Election: receive VoteResponse
156/// e.g. Sync cluster membership configure
157/// @return: true - found higher term;
158pub(crate) fn if_higher_term_found(
159 my_current_term: u64,
160 term: u64,
161 is_learner: bool,
162) -> bool {
163 //means I am fake leader or we should ignore learner's response
164 if !is_learner && my_current_term < term {
165 tracing::warn!("my_current_term: {} < term: {} ?", my_current_term, term);
166 return true;
167 }
168
169 false
170}
171
172/// Raft paper: 5.4.1 Election restriction
173///
174/// Raft determines which of two logs is more up-to-date by comparing the index and term of the last
175/// entries in the logs. If the logs have last entries with different terms, then the log with the
176/// later term is more up-to-date. If the logs end with the same term, then whichever log is longer
177/// is more up-to-date.
178#[tracing::instrument]
179pub(crate) fn is_target_log_more_recent(
180 my_last_log_index: u64,
181 my_last_log_term: u64,
182 target_last_log_index: u64,
183 target_last_log_term: u64,
184) -> bool {
185 (target_last_log_term > my_last_log_term)
186 || (target_last_log_term == my_last_log_term && target_last_log_index >= my_last_log_index)
187}