Skip to content

Commit

Permalink
Merge pull request #889 from drmingdrmer/44-raft-ctl
Browse files Browse the repository at this point in the history
Change: move runtime config API to dedicated RuntimeConfigHandle
  • Loading branch information
drmingdrmer committed Jul 2, 2023
2 parents 4c488a6 + 5d37d4c commit 1f3fc69
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 13 deletions.
29 changes: 21 additions & 8 deletions openraft/src/raft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<C, N, LS> {
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.
Expand Down
53 changes: 53 additions & 0 deletions openraft/src/raft/runtime_config_handle.rs
Original file line number Diff line number Diff line change
@@ -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<C>,
LS: RaftLogStorage<C>,
{
raft_inner: &'r RaftInner<C, N, LS>,
}

impl<'r, C, N, LS> RuntimeConfigHandle<'r, C, N, LS>
where
C: RaftTypeConfig,
N: RaftNetworkFactory<C>,
LS: RaftLogStorage<C>,
{
pub(in crate::raft) fn new(raft_inner: &'r RaftInner<C, N, LS>) -> 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);
}
}
2 changes: 1 addition & 1 deletion tests/tests/append_entries/t60_enable_heartbeat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = <TokioRuntime as AsyncRuntime>::Instant::now();
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/append_entries/t61_heartbeat_reject_vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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?;
Expand Down
4 changes: 2 additions & 2 deletions tests/tests/membership/t21_change_membership_cases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ async fn change_from_to(old: BTreeSet<MemNodeId>, change_members: BTreeSet<MemNo
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");
Expand Down Expand Up @@ -354,7 +354,7 @@ async fn change_by_remove(old: BTreeSet<MemNodeId>, 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");
Expand Down
2 changes: 1 addition & 1 deletion tests/tests/membership/t31_remove_leader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit 1f3fc69

Please sign in to comment.