reddb_server/replication/
mod.rs1pub mod bookmark;
24pub mod cascade;
25pub mod cdc;
26pub mod commit_policy;
27pub mod commit_waiter;
28pub mod control_plane;
29pub mod dst;
30pub mod election;
31pub mod failover;
32pub mod fence;
33pub mod flow_control;
34pub mod lease;
35pub mod logical;
36pub mod primary;
37pub mod quorum;
38pub mod reconnect;
39pub mod replica;
40pub mod rollback;
41pub mod scheduler;
42pub mod swap_db;
43pub mod topology_advertiser;
44pub mod witness;
45
46pub use bookmark::{BookmarkDecodeError, CausalBookmark};
47pub use cascade::{
48 plan_upstream, CascadeRefusal, CascadeRelay, CascadeUpstream, DownstreamSlot, ReplicaClass,
49 UpstreamChoice,
50};
51pub use commit_policy::CommitPolicy;
52pub use commit_waiter::{AwaitOutcome, CommitWaiter};
53pub use control_plane::{
54 ControlPlaneConsensus, ControlPlaneEntry, ControlPlaneEntryKind, ControlPlaneLogIndex,
55 ControlPlanePayload, ControlPlaneRole, MemberId, ProposeRefusal,
56};
57pub use election::{
58 quorum_threshold, randomized_election_timeout, ElectionCoordinator, ElectionOutcome,
59 ElectionRequest, ElectionTransport, FileLastVoteStore, LastVote, LastVoteError, LastVoteStore,
60 Member, MemberKind, MemoryLastVoteStore, RefusalReason, VoteDecision, VoteRequest, Voter,
61 VotingState,
62};
63pub use failover::{
64 FailoverCoordinator, FailoverError, FailoverMode, FailoverNode, FailoverOutcome,
65 FailoverRequest, FailoverTransport, NodeRole, RoleAssignment,
66};
67pub use fence::{
68 term_is_stale, FenceBoundary, FenceVerdict, FileTermStore, MemoryTermStore, StaleTermFenced,
69 StaleTermRejection, StreamHandshake, TermFence, TermStore, TermStoreError,
70};
71pub use flow_control::{Admission, FlowController};
72pub use lease::{LeaseError, LeaseStore, WriterLease};
73pub use quorum::{QuorumConfig, QuorumCoordinator, QuorumError};
74pub use rollback::{
75 DivergentTail, RollbackCoordinator, RollbackError, RollbackEvent, RollbackOutcome,
76 RollbackPlan, RollbackRequest, RollbackTransport, TailRecord,
77};
78pub use swap_db::{RebootstrapInProgress, SwapDb};
79pub use topology_advertiser::{
80 LagConfig, TopologyAdvertiser, TopologyAuthGate, DEFAULT_REPLICA_TIMEOUT_MS,
81 TOPOLOGY_READ_CAPABILITY,
82};
83pub use witness::{RuntimeProfile, WitnessSupervisor};
84
85pub const DEFAULT_REPLICATION_TERM: u64 = reddb_wire::replication::DEFAULT_REPLICATION_TERM;
86pub const DEFAULT_SLOT_RETENTION_MAX_LAG_LSN: u64 = 100_000;
87pub const DEFAULT_SLOT_IDLE_TIMEOUT_MS: u64 = 86_400_000;
88
89#[derive(Debug, Clone, PartialEq, Eq, Default)]
91pub enum ReplicationRole {
92 #[default]
94 Standalone,
95 Primary,
97 Replica {
99 primary_addr: String,
101 },
102}
103
104#[derive(Debug, Clone)]
106pub struct ReplicationConfig {
107 pub role: ReplicationRole,
108 pub term: u64,
110 pub poll_interval_ms: u64,
112 pub max_batch_size: usize,
114 pub region: String,
121 pub quorum: QuorumConfig,
123 pub slot_retention_max_lag_lsn: u64,
126 pub slot_idle_timeout_ms: u64,
128 pub replica_class: ReplicaClass,
134 pub cascade_from: Option<CascadeUpstream>,
138}
139
140impl ReplicationConfig {
141 pub fn standalone() -> Self {
142 Self {
143 role: ReplicationRole::Standalone,
144 term: DEFAULT_REPLICATION_TERM,
145 poll_interval_ms: 100,
146 max_batch_size: 1000,
147 region: "local".to_string(),
148 quorum: QuorumConfig::async_commit(),
149 slot_retention_max_lag_lsn: DEFAULT_SLOT_RETENTION_MAX_LAG_LSN,
150 slot_idle_timeout_ms: DEFAULT_SLOT_IDLE_TIMEOUT_MS,
151 replica_class: ReplicaClass::Voting,
152 cascade_from: None,
153 }
154 }
155
156 pub fn primary() -> Self {
157 Self {
158 role: ReplicationRole::Primary,
159 term: DEFAULT_REPLICATION_TERM,
160 poll_interval_ms: 100,
161 max_batch_size: 1000,
162 region: "local".to_string(),
163 quorum: QuorumConfig::async_commit(),
164 slot_retention_max_lag_lsn: DEFAULT_SLOT_RETENTION_MAX_LAG_LSN,
165 slot_idle_timeout_ms: DEFAULT_SLOT_IDLE_TIMEOUT_MS,
166 replica_class: ReplicaClass::Voting,
167 cascade_from: None,
168 }
169 }
170
171 pub fn replica(primary_addr: impl Into<String>) -> Self {
172 Self {
173 role: ReplicationRole::Replica {
174 primary_addr: primary_addr.into(),
175 },
176 term: DEFAULT_REPLICATION_TERM,
177 poll_interval_ms: 100,
178 max_batch_size: 1000,
179 region: "local".to_string(),
180 quorum: QuorumConfig::async_commit(),
181 slot_retention_max_lag_lsn: DEFAULT_SLOT_RETENTION_MAX_LAG_LSN,
182 slot_idle_timeout_ms: DEFAULT_SLOT_IDLE_TIMEOUT_MS,
183 replica_class: ReplicaClass::Voting,
184 cascade_from: None,
185 }
186 }
187
188 pub fn with_quorum(mut self, quorum: QuorumConfig) -> Self {
190 self.quorum = quorum;
191 self
192 }
193
194 pub fn with_region(mut self, region: impl Into<String>) -> Self {
196 self.region = region.into();
197 self
198 }
199
200 pub fn with_term(mut self, term: u64) -> Self {
202 self.term = term;
203 self
204 }
205
206 pub fn with_slot_retention_max_lag_lsn(mut self, max_lag_lsn: u64) -> Self {
207 self.slot_retention_max_lag_lsn = max_lag_lsn;
208 self
209 }
210
211 pub fn with_slot_idle_timeout_ms(mut self, timeout_ms: u64) -> Self {
212 self.slot_idle_timeout_ms = timeout_ms;
213 self
214 }
215
216 pub fn with_replica_class(mut self, class: ReplicaClass) -> Self {
218 self.replica_class = class;
219 self
220 }
221
222 pub fn cascading_from(mut self, node_id: impl Into<String>, addr: impl Into<String>) -> Self {
228 self.replica_class = ReplicaClass::AsyncReadReplica;
229 self.cascade_from = Some(CascadeUpstream::new(node_id, addr));
230 self
231 }
232
233 pub fn resolved_upstream(
240 &self,
241 self_node_id: &str,
242 ) -> (UpstreamChoice, Option<CascadeRefusal>) {
243 plan_upstream(self_node_id, self.replica_class, self.cascade_from.as_ref())
244 }
245}