use std::fmt;
use display_more::DisplayOptionExt;
use crate::RaftTypeConfig;
use crate::base::shared_id_generator::SharedIdGenerator;
use crate::display_ext::DisplayInstantExt;
use crate::engine::leader_log_ids::LeaderLogIds;
use crate::progress::Progress;
use crate::progress::VecProgress;
use crate::proposer::Leader;
use crate::quorum::QuorumSet;
use crate::type_config::alias::InstantOf;
use crate::type_config::alias::LogIdOf;
use crate::type_config::alias::VoteOf;
use crate::vote::RaftVote;
use crate::vote::raft_vote::RaftVoteExt;
#[derive(Clone, Debug)]
#[derive(PartialEq, Eq)]
pub(crate) struct Candidate<C, QS>
where
C: RaftTypeConfig,
QS: QuorumSet<C::NodeId>,
{
starting_time: InstantOf<C>,
vote: VoteOf<C>,
last_log_id: Option<LogIdOf<C>>,
progress: VecProgress<C::NodeId, bool, bool, QS>,
quorum_set: QS,
learner_ids: Vec<C::NodeId>,
progress_id_gen: SharedIdGenerator,
}
impl<C, QS> fmt::Display for Candidate<C, QS>
where
C: RaftTypeConfig,
QS: QuorumSet<C::NodeId> + fmt::Debug + 'static,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{{{}@{}, last_log_id:{} progress:{}}}",
self.vote,
self.starting_time.display(),
self.last_log_id.display(),
self.progress
)
}
}
impl<C, QS> Candidate<C, QS>
where
C: RaftTypeConfig,
QS: QuorumSet<C::NodeId> + fmt::Debug + Clone + 'static,
{
pub(crate) fn new(
starting_time: InstantOf<C>,
vote: VoteOf<C>,
last_log_id: Option<LogIdOf<C>>,
quorum_set: QS,
learner_ids: impl IntoIterator<Item = C::NodeId>,
progress_id_gen: SharedIdGenerator,
) -> Self {
Self {
starting_time,
vote,
last_log_id,
progress: VecProgress::new(quorum_set.clone(), [], || false),
quorum_set,
learner_ids: learner_ids.into_iter().collect::<Vec<_>>(),
progress_id_gen,
}
}
pub(crate) fn vote_ref(&self) -> &VoteOf<C> {
&self.vote
}
pub(crate) fn last_log_id(&self) -> Option<&LogIdOf<C>> {
self.last_log_id.as_ref()
}
pub(crate) fn progress(&self) -> &VecProgress<C::NodeId, bool, bool, QS> {
&self.progress
}
pub(crate) fn grant_by(&mut self, target: &C::NodeId) -> bool {
let granted = *self.progress.update(target, true).expect("target not in quorum set");
tracing::info!("{}: voting: {}", func_name!(), self);
granted
}
#[allow(dead_code)]
pub(crate) fn granters(&self) -> impl Iterator<Item = C::NodeId> + '_ {
self.progress().iter().filter(|item| item.val).map(|item| item.id.clone())
}
pub(crate) fn into_leader(self) -> Leader<C, QS> {
let vote = {
let vote = self.vote_ref().clone();
debug_assert!(!vote.is_committed());
vote.into_committed()
};
let last = self.last_log_id();
let last_leader_log_ids = last.cloned().map(LeaderLogIds::new_single);
Leader::new(
vote,
self.quorum_set.clone(),
self.learner_ids,
last_leader_log_ids, self.progress_id_gen,
)
}
}