use std::{collections::BTreeSet, matches};
use serde::{Deserialize, Serialize};
use super::NodeID;
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Membership {
pub voters: BTreeSet<NodeID>,
}
impl Membership {
pub fn from_iter(iter: impl IntoIterator<Item = NodeID>) -> Self {
Self { voters: iter.into_iter().collect() }
}
pub fn contains(&self, id: NodeID) -> bool {
self.voters.contains(&id)
}
pub fn len(&self) -> usize {
self.voters.len()
}
pub fn is_empty(&self) -> bool {
self.voters.is_empty()
}
pub fn quorum_size(&self) -> usize {
self.len() / 2 + 1
}
pub fn has_quorum(&self, matched: &BTreeSet<NodeID>) -> bool {
self.voters.intersection(matched).count() >= self.quorum_size()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum MembershipEntry {
Joint { old: Membership, new: Membership },
Simple(Membership),
}
impl MembershipEntry {
pub fn all_voters(&self) -> BTreeSet<NodeID> {
match self {
Self::Simple(m) => m.voters.clone(),
Self::Joint { old, new } => old.voters.union(&new.voters).copied().collect(),
}
}
pub fn target(&self) -> &Membership {
match self {
Self::Simple(m) => m,
Self::Joint { new, .. } => new,
}
}
pub fn is_joint(&self) -> bool {
matches!(self, Self::Joint { .. })
}
pub fn has_quorum(&self, matched: &BTreeSet<NodeID>) -> bool {
match self {
Self::Simple(m) => m.has_quorum(matched),
Self::Joint { old, new } => old.has_quorum(matched) && new.has_quorum(matched),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MembershipState {
pub active: MembershipEntry,
pub change_pending: bool,
}
impl MembershipState {
pub fn bootstrap(id: NodeID, peers: impl IntoIterator<Item = NodeID>) -> Self {
let mut voters = BTreeSet::new();
voters.insert(id);
voters.extend(peers);
Self { active: MembershipEntry::Simple(Membership { voters }), change_pending: false }
}
pub fn all_voters(&self) -> BTreeSet<NodeID> {
self.active.all_voters()
}
pub fn peers_of(&self, id: NodeID) -> BTreeSet<NodeID> {
let mut all = self.all_voters();
all.remove(&id);
all
}
pub fn has_quorum(&self, matched: &BTreeSet<NodeID>) -> bool {
self.active.has_quorum(matched)
}
pub fn apply_entry(&mut self, entry: &MembershipEntry) {
self.active = entry.clone();
self.change_pending = true;
}
pub fn on_commit(&mut self, entry: &MembershipEntry) {
match entry {
MembershipEntry::Joint { .. } => {
self.change_pending = true;
}
MembershipEntry::Simple(_) => {
self.change_pending = false;
}
}
}
}