use std::{collections::BTreeMap, net::SocketAddr, time::SystemTime};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum MemberState {
Joining,
Up,
Leaving,
Exiting,
Down,
Removed,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Member {
pub node_id: String,
pub address: SocketAddr,
pub agent_addr: Option<SocketAddr>,
pub roles: Vec<String>,
pub state: MemberState,
pub unreachable: bool,
pub incarnation: u64,
pub seen_at: SystemTime,
pub unreachable_since: Option<SystemTime>,
}
impl Member {
#[must_use]
pub(crate) fn new(
node_id: String,
address: SocketAddr,
agent_addr: Option<SocketAddr>,
roles: Vec<String>,
state: MemberState,
incarnation: u64,
now: SystemTime,
) -> Self {
Self {
node_id,
address,
agent_addr,
roles,
state,
unreachable: false,
incarnation,
seen_at: now,
unreachable_since: None,
}
}
#[must_use]
pub fn has_role(&self, role: &str) -> bool {
self.roles.iter().any(|candidate| candidate == role)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ClusterState {
pub self_node: String,
pub members: BTreeMap<String, Member>,
}
impl ClusterState {
#[must_use]
pub(crate) fn new(self_member: Member) -> Self {
let self_node = self_member.node_id.clone();
let mut members = BTreeMap::new();
members.insert(self_member.node_id.clone(), self_member);
Self { self_node, members }
}
#[must_use]
pub fn member(&self, node_id: &str) -> Option<&Member> {
self.members.get(node_id)
}
#[must_use]
pub fn up_members(&self) -> Vec<&Member> {
self.members
.values()
.filter(|member| member.state == MemberState::Up && !member.unreachable)
.collect()
}
#[must_use]
pub fn placement_coordinator(&self) -> Option<&Member> {
self.up_members().into_iter().min_by(|left, right| {
left.incarnation
.cmp(&right.incarnation)
.then_with(|| left.node_id.cmp(&right.node_id))
})
}
#[must_use]
pub fn is_placement_coordinator(&self, node_id: &str) -> bool {
self.placement_coordinator()
.is_some_and(|member| member.node_id == node_id)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MemberEvent {
pub sequence: u64,
pub kind: MemberEventKind,
pub member: Member,
pub at: SystemTime,
}
impl MemberEvent {
#[must_use]
pub(crate) const fn new(
sequence: u64,
kind: MemberEventKind,
member: Member,
at: SystemTime,
) -> Self {
Self {
sequence,
kind,
member,
at,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MemberEventKind {
Initialized,
MemberJoining,
MemberUp,
MemberUpdated,
MemberUnreachable,
MemberReachable,
MemberLeaving,
MemberExiting,
MemberDown,
MemberRemoved,
MemberRejoined,
}