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