use {
crate::{
PeerId,
groups::{
Command,
Cursor,
Index,
IndexRange,
StateMachine,
StateSync,
Term,
},
primitives::{Encoded, Short},
},
derive_more::Display,
serde::{Deserialize, Serialize},
};
#[derive(Clone, Display, Serialize, Deserialize)]
#[serde(bound = "")]
pub enum Message<M: StateMachine> {
#[display(
"AppendEntries[t={}/pos={}/n={}/c={}/{}]/",
_0.term, _0.prev_log_position, _0.entries.len(),
_0.leader_commit, Short(_0.leader)
)]
AppendEntries(AppendEntries<M::Command>),
#[display("AppendEntriesResponse[t={}/success={}]", _0.term, _0.vote)]
AppendEntriesResponse(AppendEntriesResponse),
#[display("RequestVote[t={}/log={}]@{}", _0.term, _0.log_position, Short(_0.candidate))]
RequestVote(RequestVote),
#[display("RequestVoteResponse[t={}/{}]", _0.term, _0.vote)]
RequestVoteResponse(RequestVoteResponse),
#[display("Forward(..)")]
Forward(Forward<M>),
#[display("StateSync(..)")]
StateSync(<M::StateSync as StateSync>::Message),
}
impl<M: StateMachine> Message<M> {
pub const fn term(&self) -> Option<Term> {
match self {
Self::AppendEntries(msg) => Some(msg.term),
Self::AppendEntriesResponse(msg) => Some(msg.term),
Self::RequestVote(msg) => Some(msg.term),
Self::RequestVoteResponse(msg) => Some(msg.term),
Self::Forward(_) | Self::StateSync(_) => None,
}
}
pub const fn leader(&self) -> Option<PeerId> {
match self {
Self::AppendEntries(msg) => Some(msg.leader),
Self::AppendEntriesResponse(_)
| Self::RequestVote(_)
| Self::RequestVoteResponse(_)
| Self::Forward(_)
| Self::StateSync(_) => None,
}
}
}
#[derive(Clone, Display, Serialize, Deserialize)]
#[display("{}[t{term}/log={log_position}]", Short(candidate))]
pub struct RequestVote {
pub term: Term,
pub candidate: PeerId,
pub log_position: Cursor,
}
#[derive(Debug, Clone, Display, Serialize, Deserialize)]
pub enum Vote {
Granted,
Denied,
Abstained,
}
#[derive(Debug, Clone, Display, Serialize, Deserialize)]
#[display("{vote}@{term}")]
pub struct RequestVoteResponse {
pub term: Term,
pub vote: Vote,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct LogEntry<C: Command> {
pub term: Term,
pub command: Encoded<C>,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct AppendEntries<C: Command> {
pub term: Term,
pub leader: PeerId,
pub prev_log_position: Cursor,
pub entries: Vec<LogEntry<C>>,
pub leader_commit: Index,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppendEntriesResponse {
pub term: Term,
pub last_log_index: Index,
pub vote: Vote,
}
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub enum Forward<M: StateMachine> {
Command {
commands: Vec<Encoded<M::Command>>,
request_id: Option<u64>,
},
CommandAck {
request_id: u64,
assigned: IndexRange,
},
Query {
query: Encoded<M::Query>,
request_id: u64,
},
QueryResponse {
request_id: u64,
result: Encoded<M::QueryResult>,
position: Index,
},
}