diff options
Diffstat (limited to 'src/swarm/reach.rs')
| -rw-r--r-- | src/swarm/reach.rs | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/src/swarm/reach.rs b/src/swarm/reach.rs index e6cee2f..d4949ef 100644 --- a/src/swarm/reach.rs +++ b/src/swarm/reach.rs @@ -35,6 +35,35 @@ use crate::state::{AppState, HelloState, Standing}; use crate::swarm::peer::announce_heads; use crate::swarm::{members, rtt, topology}; +/// The most members a node may say it reaches (`said`): more than it could hold +/// sessions with. +pub(crate) const MAX_REACHES: usize = 4096; + +/// A reach set as a neighbour said it (`Status::reaches`), with its round trips if +/// they match it: sorted by pair key (as we send ours: `measure`), so it can be looked +/// up by halving (`swarm::tree`); None if it is larger than `MAX_REACHES`. +pub(crate) fn said( + reaches: &[u64], + round_trips: Option<&[u8]>, +) -> Option<(Vec<u64>, Option<Vec<u8>>)> { + if reaches.len() > MAX_REACHES { + return None; + } + let round_trips = round_trips.filter(|round_trips| round_trips.len() == reaches.len()); + if reaches.windows(2).all(|pair| pair[0] < pair[1]) { + return Some((reaches.to_vec(), round_trips.map(<[u8]>::to_vec))); + } + let mut pairs: Vec<(u64, Option<u8>)> = reaches + .iter() + .enumerate() + .map(|(i, key)| (*key, round_trips.map(|round_trips| round_trips[i]))) + .collect(); + pairs.sort_unstable_by_key(|(key, _)| *key); + pairs.dedup_by_key(|(key, _)| *key); + let round_trips = round_trips.map(|_| pairs.iter().filter_map(|(_, rtt)| *rtt).collect()); + Some((pairs.into_iter().map(|(key, _)| key).collect(), round_trips)) +} + /// Whom we reach, as last told our neighbours, and our round trip to each. #[derive(Default)] pub(crate) struct Reach { @@ -160,3 +189,23 @@ pub(crate) async fn names(state: &AppState) -> HashMap<u64, String> { .map(|member| (topology::pair_key(&member), member)) .collect() } + +#[cfg(test)] +mod tests { + use super::*; + + /// A reach set comes sorted, its round trips along; too large, it is ignored. + #[test] + fn reach_sets_are_sorted_and_bounded() { + assert_eq!( + said(&[1, 3, 5], Some(&[9, 8, 7])), + Some((vec![1, 3, 5], Some(vec![9, 8, 7]))) + ); + assert_eq!( + said(&[5, 1, 3, 1], Some(&[7, 9, 8, 9])), + Some((vec![1, 3, 5], Some(vec![9, 8, 7]))) + ); + assert_eq!(said(&[2, 1], Some(&[1])), Some((vec![1, 2], None))); + assert_eq!(said(&vec![0; MAX_REACHES + 1], None), None); + } +} |
