use crate::messaging::system::{MembershipState, SectionAuth};
use crate::routing::{
network_knowledge::{NodeState, SectionAuthorityProvider},
Peer,
};
use dashmap::{mapref::entry::Entry, DashMap};
use itertools::Itertools;
use std::{
cmp::Ordering,
collections::{BTreeMap, BTreeSet},
ops::Deref,
sync::Arc,
};
use xor_name::{Prefix, XorName};
#[derive(Clone, Default, Debug)]
pub(crate) struct SectionPeers {
members: Arc<DashMap<XorName, SectionAuth<NodeState>>>,
}
impl Eq for SectionPeers {}
impl PartialEq for SectionPeers {
fn eq(&self, other: &Self) -> bool {
let mut us: BTreeMap<XorName, SectionAuth<NodeState>> = BTreeMap::default();
let mut them: BTreeMap<XorName, SectionAuth<NodeState>> = BTreeMap::default();
for refmulti in self.members.iter() {
let (key, value) = refmulti.pair();
let _prev = us.insert(*key, value.clone());
}
for refmulti in other.members.iter() {
let (key, value) = refmulti.pair();
let _prev = them.insert(*key, value.clone());
}
us == them
}
}
impl<'a> IntoIterator for &'a SectionPeers {
type Item = dashmap::mapref::multiple::RefMulti<'a, XorName, SectionAuth<NodeState>>;
type IntoIter = dashmap::iter::Iter<'a, XorName, SectionAuth<NodeState>>;
fn into_iter(self) -> Self::IntoIter {
self.members.iter()
}
}
impl SectionPeers {
pub(crate) fn new(members: impl IntoIterator<Item = SectionAuth<NodeState>>) -> Self {
Self {
members: Arc::new(
members
.into_iter()
.map(|state| (state.name(), state))
.collect(),
),
}
}
pub(crate) fn iter(
&self,
) -> impl Iterator<Item = impl Deref<Target = SectionAuth<NodeState>> + '_> + '_ {
IntoIterator::into_iter(self)
}
pub(crate) fn all_members(&self) -> Vec<Peer> {
self.joined()
.into_iter()
.map(|info| info.peer().clone())
.collect()
}
pub(crate) fn joined(&self) -> Vec<NodeState> {
let mut joined = vec![];
let members = &*self.members;
for entry in members.into_iter() {
let (_, state) = entry.pair();
if state.state() == MembershipState::Joined {
joined.push(state.value.clone())
}
}
joined
}
pub(crate) fn mature(&self) -> Vec<Peer> {
self.joined()
.into_iter()
.filter(|info| info.is_mature())
.map(|info| info.peer().clone())
.collect()
}
pub(crate) fn get(&self, name: &XorName) -> Option<NodeState> {
self.members.get(name).map(|info| info.value.clone())
}
pub(crate) fn get_section_signed(&self, name: &XorName) -> Option<SectionAuth<NodeState>> {
if let Some(oneref) = self.members.get(name) {
return Some(oneref.value().clone());
}
None
}
pub(crate) fn elder_candidates(
&self,
elder_size: usize,
current_elders: &SectionAuthorityProvider,
excluded_names: &BTreeSet<XorName>,
) -> Vec<Peer> {
let mut candidates = vec![];
let members = &*self.members;
for entry in members.into_iter() {
let (name, info) = entry.pair();
if is_active(info, current_elders) && !excluded_names.contains(name) {
candidates.push(info.clone())
}
}
elder_candidates(elder_size, current_elders, candidates)
}
pub(crate) fn elder_candidates_matching_prefix(
&self,
prefix: &Prefix,
elder_size: usize,
current_elders: &SectionAuthorityProvider,
excluded_names: &BTreeSet<XorName>,
) -> Vec<Peer> {
let mut candidates = vec![];
let members = &*self.members;
for entry in members.into_iter() {
let (name, info) = entry.pair();
if info.state() == MembershipState::Joined
&& prefix.matches(name)
&& !excluded_names.contains(name)
{
candidates.push(info.clone())
}
}
elder_candidates(elder_size, current_elders, candidates)
}
pub(crate) fn is_joined(&self, name: &XorName) -> bool {
self.members
.get(name)
.map(|info| info.state() == MembershipState::Joined)
.unwrap_or(false)
}
pub(crate) fn is_relocated_to_our_section(&self, name: &XorName) -> bool {
for peer in self.members.iter() {
let state = peer.value();
if state.previous_name() == Some(*name) {
return true;
}
}
false
}
pub(crate) fn update(&self, new_info: SectionAuth<NodeState>) -> bool {
match self.members.entry(new_info.name()) {
Entry::Vacant(entry) => {
let _prev = entry.insert(new_info);
true
}
Entry::Occupied(mut entry) => {
match (entry.get().state(), new_info.state()) {
(MembershipState::Joined, MembershipState::Joined)
if new_info.age() > entry.get().age() => {}
(MembershipState::Joined, MembershipState::Left)
| (MembershipState::Joined, MembershipState::Relocated(_))
| (MembershipState::Relocated(_), MembershipState::Left) => {}
_ => return false,
};
let _prev = entry.insert(new_info);
true
}
}
}
pub(crate) fn retain(&self, prefix: &Prefix) {
self.members.retain(|name, _value| prefix.matches(name))
}
}
fn elder_candidates(
elder_size: usize,
current_elders: &SectionAuthorityProvider,
members: Vec<SectionAuth<NodeState>>,
) -> Vec<Peer> {
members
.into_iter()
.sorted_by(|lhs, rhs| cmp_elder_candidates(lhs, rhs, current_elders))
.map(|auth| auth.peer().clone())
.take(elder_size)
.collect()
}
fn cmp_elder_candidates(
lhs: &SectionAuth<NodeState>,
rhs: &SectionAuth<NodeState>,
current_elders: &SectionAuthorityProvider,
) -> Ordering {
cmp_elder_candidates_by_membership_state(&lhs.state(), &rhs.state())
.then_with(|| rhs.age().cmp(&lhs.age()))
.then_with(|| {
let lhs_is_elder = is_elder(lhs, current_elders);
let rhs_is_elder = is_elder(rhs, current_elders);
match (lhs_is_elder, rhs_is_elder) {
(true, false) => Ordering::Less,
(false, true) => Ordering::Greater,
_ => Ordering::Equal,
}
})
.then_with(|| lhs.sig.signature.cmp(&rhs.sig.signature))
}
fn cmp_elder_candidates_by_membership_state(
lhs: &MembershipState,
rhs: &MembershipState,
) -> Ordering {
use MembershipState::*;
match (lhs, rhs) {
(Joined, Joined) | (Relocated(_), Relocated(_)) => Ordering::Equal,
(Joined, Relocated(_)) | (_, Left) => Ordering::Less,
(Relocated(_), Joined) | (Left, _) => Ordering::Greater,
}
}
fn is_active(info: &NodeState, current_elders: &SectionAuthorityProvider) -> bool {
match info.state() {
MembershipState::Joined => true,
MembershipState::Relocated(_) if is_elder(info, current_elders) => true,
_ => false,
}
}
fn is_elder(info: &NodeState, current_elders: &SectionAuthorityProvider) -> bool {
current_elders.contains_elder(&info.name())
}