use rand_core::RngCore;
use std::collections::BTreeMap;
use crate::{topology::Module, Id, NodeData};
pub const CYCLON_MAX_GOSSIPING_LENGTH: usize = 128;
#[derive(Clone, Debug)]
pub struct Cyclon;
impl Cyclon {
fn select_random_gossips<'a, Rng>(
&self,
rng: &mut Rng,
known_nodes: &'a BTreeMap<Id, NodeData>,
) -> Vec<(&'a Id, &'a NodeData)>
where
Rng: RngCore,
{
let mut randomly_ordered_nodes: Vec<_> = known_nodes.iter().collect();
randomly_ordered_nodes.sort_by(|_, _| match rng.next_u32() % 3 {
0 => std::cmp::Ordering::Less,
1 => std::cmp::Ordering::Equal,
_ => std::cmp::Ordering::Greater,
});
randomly_ordered_nodes
}
}
impl Default for Cyclon {
fn default() -> Self {
Cyclon
}
}
impl Module for Cyclon {
fn name(&self) -> &'static str {
"cyclon"
}
fn select_gossips(
&self,
_our_node: &NodeData,
gossip_recipient: &NodeData,
known_nodes: &BTreeMap<Id, NodeData>,
) -> BTreeMap<Id, NodeData> {
let mut candidates = BTreeMap::new();
let mut rng = rand_os::OsRng::new().unwrap();
candidates.extend(
self.select_random_gossips(&mut rng, known_nodes)
.into_iter()
.filter(|(k, _)| k != &gossip_recipient.id())
.take(CYCLON_MAX_GOSSIPING_LENGTH)
.map(|(k, v)| (*k, v.clone())),
);
candidates
}
fn update(&mut self, _: &NodeData, _: &BTreeMap<Id, NodeData>) {
}
fn view(&self, known_nodes: &BTreeMap<Id, NodeData>, view: &mut BTreeMap<Id, NodeData>) {
let mut node_iterator = known_nodes.values();
let candidate = if let Some(candidate) = node_iterator.next() {
candidate
} else {
return;
};
let candidate = node_iterator.fold(candidate, |candidate, prospect| {
if candidate.last_gossip < prospect.last_gossip {
candidate
} else {
prospect
}
});
view.insert(*candidate.id(), candidate.clone());
}
}