From 5d37d4c358b0ea6865672934df413dc6bb940c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=82=8E=E6=B3=BC?= Date: Sun, 2 Jul 2023 11:13:44 +0800 Subject: [PATCH] Change: move runtime config API to dedicated RuntimeConfigHandle --- openraft/src/raft/mod.rs | 29 +++++++--- openraft/src/raft/runtime_config_handle.rs | 53 +++++++++++++++++++ .../append_entries/t60_enable_heartbeat.rs | 2 +- .../t61_heartbeat_reject_vote.rs | 2 +- .../membership/t21_change_membership_cases.rs | 4 +- tests/tests/membership/t31_remove_leader.rs | 2 +- 6 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 openraft/src/raft/runtime_config_handle.rs diff --git a/openraft/src/raft/mod.rs b/openraft/src/raft/mod.rs index dedaee489..97c78296d 100644 --- a/openraft/src/raft/mod.rs +++ b/openraft/src/raft/mod.rs @@ -2,13 +2,13 @@ mod message; mod raft_inner; +mod runtime_config_handle; mod trigger; pub(in crate::raft) mod core_state; use std::fmt::Debug; use std::marker::PhantomData; -use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; @@ -50,6 +50,7 @@ use crate::metrics::RaftMetrics; use crate::metrics::Wait; use crate::network::RaftNetworkFactory; use crate::raft::raft_inner::RaftInner; +use crate::raft::runtime_config_handle::RuntimeConfigHandle; use crate::raft::trigger::Trigger; use crate::storage::RaftLogStorage; use crate::storage::RaftStateMachine; @@ -261,21 +262,33 @@ where }) } - /// Enable or disable raft internal ticker. + /// Return a handle to update runtime config. + /// + /// Such enabling/disabling heartbeat, election, etc. /// - /// The internal ticker triggers all timeout based event, e.g. election event or heartbeat - /// event. By disabling the ticker, a follower will not enter candidate again, a leader will - /// not send heartbeat. + /// Example: + /// ```ignore + /// let raft = Raft::new(...).await?; + /// raft.runtime_config().heartbeat(true); + /// ``` + pub fn runtime_config(&self) -> RuntimeConfigHandle { + RuntimeConfigHandle::new(self.inner.as_ref()) + } + + /// Enable or disable raft internal ticker. + #[deprecated(note = "use `Raft::runtime_config().tick()` instead")] pub fn enable_tick(&self, enabled: bool) { - self.inner.tick_handle.enable(enabled); + self.runtime_config().tick(enabled) } + #[deprecated(note = "use `Raft::runtime_config().heartbeat()` instead")] pub fn enable_heartbeat(&self, enabled: bool) { - self.inner.runtime_config.enable_heartbeat.store(enabled, Ordering::Relaxed); + self.runtime_config().heartbeat(enabled) } + #[deprecated(note = "use `Raft::runtime_config().elect()` instead")] pub fn enable_elect(&self, enabled: bool) { - self.inner.runtime_config.enable_elect.store(enabled, Ordering::Relaxed); + self.runtime_config().elect(enabled) } /// Return a handle to manually trigger raft actions, such as elect or build snapshot. diff --git a/openraft/src/raft/runtime_config_handle.rs b/openraft/src/raft/runtime_config_handle.rs new file mode 100644 index 000000000..eb0e6ea43 --- /dev/null +++ b/openraft/src/raft/runtime_config_handle.rs @@ -0,0 +1,53 @@ +//! RuntimeConfigHandle is an interface to change Raft runtime config. + +use std::sync::atomic::Ordering; + +use crate::raft::RaftInner; +use crate::storage::RaftLogStorage; +use crate::RaftNetworkFactory; +use crate::RaftTypeConfig; + +/// RuntimeConfigHandle is an interface to update runtime config. +/// +/// These config are mainly designed for testing purpose and special use cases. +/// Usually you don't need to change runtime config. +pub struct RuntimeConfigHandle<'r, C, N, LS> +where + C: RaftTypeConfig, + N: RaftNetworkFactory, + LS: RaftLogStorage, +{ + raft_inner: &'r RaftInner, +} + +impl<'r, C, N, LS> RuntimeConfigHandle<'r, C, N, LS> +where + C: RaftTypeConfig, + N: RaftNetworkFactory, + LS: RaftLogStorage, +{ + pub(in crate::raft) fn new(raft_inner: &'r RaftInner) -> Self { + Self { raft_inner } + } + + /// Enable or disable raft internal ticker. + /// + /// Disabling tick will disable election and heartbeat. + pub fn tick(&self, enabled: bool) { + self.raft_inner.tick_handle.enable(enabled); + } + + /// Enable or disable heartbeat message when a leader has no more log to replicate. + /// + /// Note that the follower's leader-lease will not be renewed if it does receive message from + /// the leader, and it will start election(if `Self::elect()` is enabled) when the lease timed + /// out. + pub fn heartbeat(&self, enabled: bool) { + self.raft_inner.runtime_config.enable_heartbeat.store(enabled, Ordering::Relaxed); + } + + /// Enable or disable election for a follower when its leader lease timed out. + pub fn elect(&self, enabled: bool) { + self.raft_inner.runtime_config.enable_elect.store(enabled, Ordering::Relaxed); + } +} diff --git a/tests/tests/append_entries/t60_enable_heartbeat.rs b/tests/tests/append_entries/t60_enable_heartbeat.rs index 2c5e72f8f..9e5b29e8f 100644 --- a/tests/tests/append_entries/t60_enable_heartbeat.rs +++ b/tests/tests/append_entries/t60_enable_heartbeat.rs @@ -27,7 +27,7 @@ async fn enable_heartbeat() -> Result<()> { let _ = log_index; let node0 = router.get_raft_handle(&0)?; - node0.enable_heartbeat(true); + node0.runtime_config().heartbeat(true); for _i in 0..3 { let now = ::Instant::now(); diff --git a/tests/tests/append_entries/t61_heartbeat_reject_vote.rs b/tests/tests/append_entries/t61_heartbeat_reject_vote.rs index d94c04f9a..d925c9154 100644 --- a/tests/tests/append_entries/t61_heartbeat_reject_vote.rs +++ b/tests/tests/append_entries/t61_heartbeat_reject_vote.rs @@ -74,7 +74,7 @@ async fn heartbeat_reject_vote() -> Result<()> { tracing::info!(log_index, "--- disable heartbeat, vote request will be granted"); { - node0.enable_heartbeat(false); + node0.runtime_config().heartbeat(false); sleep(Duration::from_millis(1500)).await; router.wait(&1, timeout()).log(Some(log_index), "no log is written").await?; diff --git a/tests/tests/membership/t21_change_membership_cases.rs b/tests/tests/membership/t21_change_membership_cases.rs index 7b9e0f9f1..e568a9610 100644 --- a/tests/tests/membership/t21_change_membership_cases.rs +++ b/tests/tests/membership/t21_change_membership_cases.rs @@ -148,7 +148,7 @@ async fn change_from_to(old: BTreeSet, change_members: BTreeSet, remove: &[MemNodeId]) -> any tracing::info!(log_index, "--- let a node in the new cluster elect"); { let n = router.get_raft_handle(new.iter().next().unwrap())?; - n.enable_elect(true); + n.runtime_config().elect(true); } tracing::info!(log_index, "--- wait for old leader or new leader"); diff --git a/tests/tests/membership/t31_remove_leader.rs b/tests/tests/membership/t31_remove_leader.rs index 588e74c14..7ae52c088 100644 --- a/tests/tests/membership/t31_remove_leader.rs +++ b/tests/tests/membership/t31_remove_leader.rs @@ -176,7 +176,7 @@ async fn remove_leader_access_new_cluster() -> Result<()> { tracing::info!(log_index, "--- elect node-2, handle write"); { let n2 = router.get_raft_handle(&2)?; - n2.enable_elect(true); + n2.runtime_config().elect(true); n2.wait(timeout()).state(ServerState::Leader, "node-2 elect itself").await?; log_index += 1;