Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change: move runtime config API to dedicated RuntimeConfigHandle #889

Merged
merged 1 commit into from
Jul 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading