diff --git a/src/lib.rs b/src/lib.rs index 4c99d8603..412fca4cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -305,7 +305,7 @@ pub use self::raft::{ pub use self::raft_log::{RaftLog, NO_LIMIT}; pub use self::raw_node::{is_empty_snap, Peer, RawNode, Ready, SnapshotStatus}; pub use self::read_only::{ReadOnlyOption, ReadState}; -pub use self::status::Status; +pub use self::status::{Status, StatusRef}; pub use self::storage::{RaftState, Storage}; pub mod prelude { @@ -335,7 +335,7 @@ pub mod prelude { pub use progress::Progress; - pub use status::Status; + pub use status::{Status, StatusRef}; pub use read_only::{ReadOnlyOption, ReadState}; } diff --git a/src/raft.rs b/src/raft.rs index 307c058a6..3928d0ec2 100644 --- a/src/raft.rs +++ b/src/raft.rs @@ -566,6 +566,13 @@ impl Raft { self.set_prs(prs); } + /// Broadcasts heartbeats to all the followers if it's leader. + pub fn ping(&mut self) { + if self.state == StateRole::Leader { + self.bcast_heartbeat(); + } + } + /// Sends RPC, without entries to all the peers. pub fn bcast_heartbeat(&mut self) { let ctx = self.read_only.last_pending_request_ctx(); diff --git a/src/raw_node.rs b/src/raw_node.rs index 09f4fb625..94da81d85 100644 --- a/src/raw_node.rs +++ b/src/raw_node.rs @@ -41,9 +41,9 @@ use protobuf::{self, RepeatedField}; use super::config::Config; use super::errors::{Error, Result}; use super::read_only::ReadState; -use super::Status; use super::Storage; use super::{Raft, SoftState, INVALID_ID}; +use super::{Status, StatusRef}; /// Represents a Peer node in the cluster. #[derive(Debug, Default)] @@ -286,6 +286,13 @@ impl RawNode { self.raft.step(m) } + /// Broadcast heartbeats to all the followers. + /// + /// If it's not leader, nothing will happen. + pub fn ping(&mut self) { + self.raft.ping() + } + /// ProposeConfChange proposes a config change. #[cfg_attr(feature = "cargo-clippy", allow(clippy::needless_pass_by_value))] pub fn propose_conf_change(&mut self, context: Vec, cc: ConfChange) -> Result<()> { @@ -423,6 +430,13 @@ impl RawNode { Status::new(&self.raft) } + /// Returns the current status of the given group. + /// + /// It's borrows the internal progress set instead of copying. + pub fn status_ref(&self) -> StatusRef { + StatusRef::new(&self.raft) + } + /// ReportUnreachable reports the given node is not reachable for the last send. pub fn report_unreachable(&mut self, id: u64) { let mut m = Message::new(); diff --git a/src/status.rs b/src/status.rs index 9851971cd..15f020696 100644 --- a/src/status.rs +++ b/src/status.rs @@ -28,7 +28,7 @@ use eraftpb::HardState; use fxhash::FxHashMap; -use progress::Progress; +use progress::{Progress, ProgressSet}; use raft::{Raft, SoftState, StateRole}; use storage::Storage; @@ -66,3 +66,35 @@ impl Status { s } } + +/// Represents the current status of the raft +#[derive(Default)] +pub struct StatusRef<'a> { + /// The ID of the current node. + pub id: u64, + /// The hardstate of the raft, representing voted state. + pub hs: HardState, + /// The softstate of the raft, representing proposed state. + pub ss: SoftState, + /// The index of the last entry to have been applied. + pub applied: u64, + /// The progress towards catching up and applying logs. + pub progress: Option<&'a ProgressSet>, +} + +impl<'a> StatusRef<'a> { + /// Gets the current raft status. + pub fn new(raft: &'a Raft) -> StatusRef<'a> { + let mut s = StatusRef { + id: raft.id, + ..Default::default() + }; + s.hs = raft.hard_state(); + s.ss = raft.soft_state(); + s.applied = raft.raft_log.get_applied(); + if s.ss.raft_state == StateRole::Leader { + s.progress = Some(raft.prs()); + } + s + } +}