mod authority;
mod error;
mod network_tests;
mod prefix;
mod xorable;
pub use self::authority::Authority;
pub use self::error::Error;
#[cfg(any(test, feature = "use-mock-crust"))]
pub use self::network_tests::verify_network_invariant;
pub use self::prefix::Prefix;
pub use self::xorable::Xorable;
use itertools::Itertools;
use std::{iter, mem};
use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet, btree_map, btree_set};
use std::collections::btree_map::Entry;
use std::fmt::{Binary, Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::hash::Hash;
pub type Sections<T> = BTreeMap<Prefix<T>, BTreeSet<T>>;
type MemberIter<'a, T> = btree_set::Iter<'a, T>;
type SectionIter<'a, T> = btree_map::Values<'a, Prefix<T>, BTreeSet<T>>;
type OtherSectionsIter<'a, T> = iter::FlatMap<SectionIter<'a, T>,
MemberIter<'a, T>,
FlatMapFn<'a, T>>;
type FlatMapFn<'a, T> = fn(&'a BTreeSet<T>) -> MemberIter<'a, T>;
const SPLIT_BUFFER: usize = 3;
pub struct Iter<'a, T: 'a + Binary + Clone + Copy + Default + Hash + Xorable> {
inner: iter::Chain<OtherSectionsIter<'a, T>, btree_set::Iter<'a, T>>,
our_name: T,
}
impl<'a, T: 'a + Binary + Clone + Copy + Default + Hash + Xorable> Iterator for Iter<'a, T> {
type Item = &'a T;
#[cfg_attr(feature="cargo-clippy", allow(while_let_on_iterator))]
fn next(&mut self) -> Option<&'a T> {
while let Some(name) = self.inner.next() {
if *name != self.our_name {
return Some(name);
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct OwnMergeDetails<T: Binary + Clone + Copy + Default + Hash + Xorable> {
pub sender_prefix: Prefix<T>,
pub merge_prefix: Prefix<T>,
pub sections: Sections<T>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct OtherMergeDetails<T: Binary + Clone + Copy + Default + Hash + Xorable> {
pub prefix: Prefix<T>,
pub section: BTreeSet<T>,
}
#[derive(Debug)]
pub struct RemovalDetails<T: Binary + Clone + Copy + Default + Hash + Xorable> {
pub name: T,
pub was_in_our_section: bool,
}
pub enum OwnMergeState<T: Binary + Clone + Copy + Default + Hash + Xorable> {
Ongoing,
Completed {
targets: BTreeSet<Prefix<T>>,
merge_details: OtherMergeDetails<T>,
},
AlreadyMerged,
}
#[derive(Clone, Eq, PartialEq)]
pub struct RoutingTable<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> {
min_section_size: usize,
our_name: T,
our_prefix: Prefix<T>,
our_section: BTreeSet<T>,
sections: Sections<T>,
}
impl<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> RoutingTable<T> {
pub fn new(our_name: T, min_section_size: usize) -> Self {
let mut our_section = BTreeSet::new();
our_section.insert(our_name);
RoutingTable {
our_name: our_name,
min_section_size: min_section_size,
our_section: our_section,
our_prefix: Default::default(),
sections: BTreeMap::new(),
}
}
pub fn add_prefixes(&mut self, prefixes: Vec<Prefix<T>>) -> Result<(), Error> {
if !self.sections.is_empty() {
return Err(Error::InvariantViolation);
}
for prefix in prefixes {
if prefix.matches(&self.our_name) {
self.our_prefix = prefix;
} else if self.sections.insert(prefix, BTreeSet::new()).is_some() {
return Err(Error::InvariantViolation);
};
}
let our_section = mem::replace(&mut self.our_section, BTreeSet::new());
for name in our_section {
if self.get_section_mut(&name).map_or(true, |section| !section.insert(name)) {
return Err(Error::InvariantViolation);
}
}
self.check_invariant(true, true)
}
pub fn our_prefix(&self) -> &Prefix<T> {
&self.our_prefix
}
pub fn our_section(&self) -> &BTreeSet<T> {
&self.our_section
}
pub fn all_sections(&self) -> Sections<T> {
self.sections
.clone()
.into_iter()
.chain(iter::once((self.our_prefix, self.our_section.clone())))
.collect()
}
pub fn section_with_prefix(&self, prefix: &Prefix<T>) -> Option<&BTreeSet<T>> {
if *prefix == self.our_prefix {
Some(&self.our_section)
} else {
self.sections.get(prefix)
}
}
pub fn len(&self) -> usize {
self.sections.values().fold(0, |acc, section| acc + section.len()) +
self.our_section.len() - 1
}
pub fn is_empty(&self) -> bool {
self.our_section.len() == 1 && self.sections.values().all(BTreeSet::is_empty)
}
pub fn min_section_size(&self) -> usize {
self.min_section_size
}
pub fn min_split_size(&self) -> usize {
self.min_section_size + SPLIT_BUFFER
}
pub fn has(&self, name: &T) -> bool {
self.get_section(name).map_or(false, |section| section.contains(name))
}
pub fn iter(&self) -> Iter<T> {
let iter: fn(_) -> _ = BTreeSet::iter;
Iter {
inner: self.sections
.values()
.flat_map(iter)
.chain(self.our_section.iter()),
our_name: self.our_name,
}
}
pub fn network_size_estimate(&self) -> (u64, bool) {
let known_prefixes = self.prefixes();
let is_exact = Prefix::default().is_covered_by(known_prefixes.iter());
let network_fraction: f64 =
known_prefixes.iter().map(|p| 1.0 / (p.bit_count() as f64).exp2()).sum();
let network_size = (self.len() + 1) as f64 / network_fraction;
(network_size.ceil() as u64, is_exact)
}
pub fn other_prefixes(&self) -> BTreeSet<Prefix<T>> {
self.sections
.keys()
.cloned()
.collect()
}
pub fn prefixes(&self) -> BTreeSet<Prefix<T>> {
self.sections
.keys()
.cloned()
.chain(iter::once(self.our_prefix))
.collect()
}
pub fn close_names(&self, name: &T) -> Option<BTreeSet<T>> {
if self.our_prefix.matches(name) {
Some(self.our_section().clone())
} else {
None
}
}
pub fn other_close_names(&self, name: &T) -> Option<BTreeSet<T>> {
if self.our_prefix.matches(name) {
let mut section = self.our_section.clone();
section.remove(&self.our_name);
Some(section)
} else {
None
}
}
pub fn is_closest(&self, name: &T, count: usize) -> bool {
self.closest_names(name, count).is_some()
}
fn closest_known_names(&self, name: &T, count: usize) -> Vec<&T> {
self.sections
.iter()
.chain(iter::once((&self.our_prefix, &self.our_section)))
.sorted_by(|&(pfx0, _), &(pfx1, _)| pfx0.cmp_distance(pfx1, name))
.into_iter()
.flat_map(|(_, section)| {
section.iter().sorted_by(|name0, name1| name.cmp_distance(name0, name1))
})
.take(count)
.collect_vec()
}
pub fn closest_names(&self, name: &T, count: usize) -> Option<Vec<&T>> {
let result = self.closest_known_names(name, count);
if result.contains(&&self.our_name) {
Some(result)
} else {
None
}
}
pub fn other_closest_names(&self, name: &T, count: usize) -> Option<Vec<&T>> {
self.closest_names(name, count).map(|mut result| {
result.retain(|name| *name != &self.our_name);
result
})
}
pub fn is_in_our_section(&self, name: &T) -> bool {
self.our_section.contains(name)
}
pub fn need_to_add(&self, name: &T) -> Result<(), Error> {
if *name == self.our_name {
return Err(Error::OwnNameDisallowed);
}
if let Some(section) = self.get_section(name) {
if section.contains(name) {
Err(Error::AlreadyExists)
} else {
Ok(())
}
} else {
Err(Error::PeerNameUnsuitable)
}
}
pub fn should_join_our_section(&self, name: &T) -> Result<(), Error> {
if !self.our_prefix.matches(name) {
return Err(Error::PeerNameUnsuitable);
}
if self.our_section.contains(name) {
return Err(Error::AlreadyExists);
}
Ok(())
}
pub fn validate_joining_node(&self, name: &T) -> Result<(), Error> {
if !self.our_prefix.matches(name) {
return Err(Error::PeerNameUnsuitable);
}
if self.our_section.contains(name) {
return Err(Error::AlreadyExists);
}
Ok(())
}
pub fn add(&mut self, name: T, want_to_merge: bool) -> Result<bool, Error> {
if name == self.our_name {
return Err(Error::OwnNameDisallowed);
}
if let Some(section) = self.get_section_mut(&name) {
if !section.insert(name) {
return Err(Error::AlreadyExists);
}
} else {
return Err(Error::PeerNameUnsuitable);
}
let split_size = self.min_split_size();
let close_to_merging_with_us = |(prefix, section): (&Prefix<T>, &BTreeSet<T>)| {
prefix.popped().is_compatible(&self.our_prefix) && section.len() < split_size
};
if want_to_merge || self.sections.iter().any(close_to_merging_with_us) {
return Ok(false);
}
let new_size = self.our_section
.iter()
.filter(|name| self.our_name.common_prefix(name) > self.our_prefix.bit_count())
.count();
Ok(new_size >= split_size && self.our_section().len() >= split_size + new_size)
}
pub fn split(&mut self, prefix: Prefix<T>) -> (Vec<T>, Option<Prefix<T>>) {
let mut result = vec![];
if prefix == self.our_prefix {
result = self.split_our_section();
return (result, Some(self.our_prefix));
}
if let Some(to_split) = self.sections.remove(&prefix) {
let prefix0 = prefix.pushed(false);
let prefix1 = prefix.pushed(true);
let (section0, section1) =
to_split.into_iter().partition::<BTreeSet<_>, _>(|name| prefix0.matches(name));
for (pfx, section) in vec![(prefix0, section0), (prefix1, section1)] {
if self.our_prefix.is_neighbour(&pfx) {
self.insert_new_section(pfx, section);
} else {
result.extend(section);
}
}
}
(result, None)
}
pub fn add_prefix(&mut self, prefix: Prefix<T>) -> Vec<T> {
let mut result = vec![];
if self.our_prefix == prefix || self.sections.contains_key(&prefix) {
return result; }
while let Some(&shorter_pfx) =
self.sections
.keys()
.chain(iter::once(&self.our_prefix))
.find(|p| p.is_compatible(&prefix) && p.bit_count() < prefix.bit_count()) {
let (dropped_nodes, _opt_our_pfx) = self.split(shorter_pfx);
result.extend(dropped_nodes);
}
let mut our_prefix = self.our_prefix;
while !our_prefix.is_neighbour(&prefix) && !our_prefix.is_compatible(&prefix) {
our_prefix = our_prefix.popped();
}
self.merge(&our_prefix);
self.merge(&prefix);
self.add_missing_prefixes();
result
}
pub fn remove(&mut self, name: &T) -> Result<RemovalDetails<T>, Error> {
let removal_details = RemovalDetails {
name: *name,
was_in_our_section: self.our_prefix.matches(name),
};
if removal_details.was_in_our_section {
if self.our_name == *name {
return Err(Error::OwnNameDisallowed);
}
if !self.our_section.remove(name) {
return Err(Error::NoSuchPeer);
}
} else if let Some(prefix) = self.find_section_prefix(name) {
if let Some(section) = self.sections.get_mut(&prefix) {
if !section.remove(name) {
return Err(Error::NoSuchPeer);
}
}
} else {
return Err(Error::NoSuchPeer);
}
Ok(removal_details)
}
pub fn should_merge(&self,
we_want_to_merge: bool,
they_want_to_merge: bool)
-> Option<OwnMergeDetails<T>> {
let bit_count = self.our_prefix.bit_count();
let doesnt_need_to_merge_with_us = |(prefix, section): (&Prefix<T>, &BTreeSet<T>)| {
!prefix.popped().is_compatible(&self.our_prefix) ||
section.len() >= self.min_section_size
};
if bit_count == 0 || we_want_to_merge ||
!self.sections.contains_key(&self.our_prefix.with_flipped_bit(bit_count - 1)) {
return None; }
if !they_want_to_merge && self.our_section.len() >= self.min_section_size &&
self.sections.iter().all(doesnt_need_to_merge_with_us) {
return None; }
let merge_prefix = self.our_prefix.popped();
Some(OwnMergeDetails {
sender_prefix: self.our_prefix,
merge_prefix: merge_prefix,
sections: self.all_sections(),
})
}
pub fn merge_own_section(&mut self, merge_details: OwnMergeDetails<T>) -> OwnMergeState<T> {
if !self.our_prefix.is_compatible(&merge_details.merge_prefix) ||
self.our_prefix.bit_count() != merge_details.merge_prefix.bit_count() + 1 {
debug!("{:?}: Attempt to call merge_own_section() for an already merged prefix {:?}",
self.our_name,
merge_details.merge_prefix);
return OwnMergeState::AlreadyMerged;
}
for prefix in merge_details.sections.keys() {
if *prefix == self.our_prefix || self.sections.contains_key(prefix) {
continue; } else if self.our_prefix.is_compatible(prefix) ||
self.sections.keys().any(|pfx| prefix.is_compatible(pfx)) {
error!("{:?} Received unsuitable prefix {:?} in OwnSectionMerge.",
self.our_name,
prefix);
} else {
self.insert_new_section(*prefix, BTreeSet::new());
}
}
if merge_details.sender_prefix != self.our_prefix {
self.finish_merging_own_section(merge_details.merge_prefix)
} else {
OwnMergeState::Ongoing
}
}
pub fn merge_other_section(&mut self, merge_details: OtherMergeDetails<T>) -> BTreeSet<T> {
if self.our_prefix.is_compatible(&merge_details.prefix) {
return BTreeSet::new();
}
let should_merge = |prefix: &Prefix<T>| {
prefix.is_compatible(&merge_details.prefix) &&
prefix.bit_count() > merge_details.prefix.bit_count()
};
if self.sections.keys().any(should_merge) {
self.merge(&merge_details.prefix);
merge_details.section
.difference(unwrap!(self.sections.get(&merge_details.prefix)))
.cloned()
.collect()
} else {
BTreeSet::new()
}
}
pub fn targets(&self,
dst: &Authority<T>,
exclude: T,
route: usize)
-> Result<BTreeSet<T>, Error> {
let candidates = |target_name: &T| {
self.closest_known_names(target_name, self.min_section_size)
.into_iter()
.filter(|name| **name != self.our_name)
.cloned()
.collect::<BTreeSet<T>>()
};
let closest_section = match *dst {
Authority::ManagedNode(ref target_name) |
Authority::Client { proxy_node_name: ref target_name, .. } => {
if *target_name == self.our_name {
return Ok(BTreeSet::new());
}
if self.has(target_name) {
return Ok(iter::once(*target_name).collect());
}
candidates(target_name)
}
Authority::ClientManager(ref target_name) |
Authority::NaeManager(ref target_name) |
Authority::NodeManager(ref target_name) => {
if let Some(group) = self.other_closest_names(target_name, self.min_section_size) {
return Ok(group.into_iter().cloned().collect());
}
candidates(target_name)
}
Authority::Section(ref target_name) => {
let (prefix, section) = self.closest_section(target_name);
if *prefix == self.our_prefix {
let mut section = section.clone();
section.remove(&self.our_name);
return Ok(section);
}
candidates(target_name)
}
Authority::PrefixSection(ref prefix) => {
if prefix.is_compatible(&self.our_prefix) {
if prefix.is_covered_by(self.prefixes().iter()) {
let is_compatible = |(pfx, section)| if prefix.is_compatible(pfx) {
Some(section)
} else {
None
};
return Ok(self.sections
.iter()
.filter_map(is_compatible)
.flat_map(BTreeSet::iter)
.chain(self.our_section.iter().filter(|name| {
**name !=
self.our_name
}))
.cloned()
.collect());
} else {
return Err(Error::CannotRoute);
}
}
candidates(&prefix.lower_bound())
}
};
Ok(iter::once(self.get_routeth_node(&closest_section, dst.name(), Some(exclude), route)?)
.collect())
}
pub fn in_authority(&self, auth: &Authority<T>) -> bool {
match *auth {
Authority::Client { .. } => false,
Authority::ManagedNode(ref name) => self.our_name == *name,
Authority::ClientManager(ref name) |
Authority::NaeManager(ref name) |
Authority::NodeManager(ref name) => self.is_closest(name, self.min_section_size),
Authority::Section(ref name) => self.our_prefix.matches(name),
Authority::PrefixSection(ref prefix) => self.our_prefix.is_compatible(prefix),
}
}
pub fn get_section(&self, name: &T) -> Option<&BTreeSet<T>> {
if self.our_prefix.matches(name) {
return Some(&self.our_section);
}
if let Some(prefix) = self.find_section_prefix(name) {
return self.sections.get(&prefix);
}
None
}
pub fn our_name(&self) -> &T {
&self.our_name
}
pub fn is_valid(&self) -> bool {
self.check_invariant(false, false).is_ok()
}
pub fn find_section_prefix(&self, name: &T) -> Option<Prefix<T>> {
if self.our_prefix.matches(name) {
return Some(self.our_prefix);
}
self.sections
.keys()
.find(|&prefix| prefix.matches(name))
.cloned()
}
pub fn assign_to_min_len_prefix(&self, name: &T) -> T {
let target_prefix = iter::once(&self.our_prefix)
.chain(self.sections.keys())
.min_by_key(|prefix| prefix.bit_count())
.unwrap_or(&self.our_prefix);
target_prefix.substituted_in(*name)
}
fn split_our_section(&mut self) -> Vec<T> {
let next_bit = self.our_name.bit(self.our_prefix.bit_count());
let other_prefix = self.our_prefix.pushed(!next_bit);
self.our_prefix = self.our_prefix.pushed(next_bit);
let (our_new_section, other_section) =
self.our_section.iter().partition::<BTreeSet<_>, _>(|name| {
self.our_prefix.matches(name)
});
self.our_section = our_new_section;
let sections_to_remove = self.sections
.keys()
.filter(|prefix| !prefix.is_neighbour(&self.our_prefix))
.cloned()
.collect_vec();
self.insert_new_section(other_prefix, other_section);
sections_to_remove.into_iter()
.filter_map(|prefix| self.sections.remove(&prefix))
.flat_map(BTreeSet::into_iter)
.collect()
}
fn insert_new_section(&mut self, prefix: Prefix<T>, section: BTreeSet<T>) {
match self.sections.entry(prefix) {
Entry::Vacant(entry) => {
let _section_ref = entry.insert(section);
}
Entry::Occupied(entry) => {
error!("{:?} Inserting section {:?}, but already has members {:?}. This is a bug!",
self.our_name,
prefix,
entry.get());
entry.into_mut().extend(section);
}
}
}
fn finish_merging_own_section(&mut self, merge_prefix: Prefix<T>) -> OwnMergeState<T> {
self.merge(&merge_prefix);
self.add_missing_prefixes();
let targets = self.sections
.keys()
.cloned()
.chain((0..merge_prefix.bit_count()).map(|i| merge_prefix.with_flipped_bit(i)))
.collect();
let other_details = OtherMergeDetails {
prefix: merge_prefix,
section: self.our_section().clone(),
};
OwnMergeState::Completed {
targets: targets,
merge_details: other_details,
}
}
fn merge(&mut self, new_prefix: &Prefix<T>) {
let original_sections = mem::replace(&mut self.sections, Sections::new());
let (sections_to_merge, sections) = original_sections.into_iter()
.partition::<BTreeMap<_, _>, _>(|&(prefix, _)| new_prefix.is_compatible(&prefix));
self.sections = sections;
let merged_names = sections_to_merge.into_iter().flat_map(|(_, names)| names).collect();
if self.our_prefix.is_compatible(new_prefix) {
self.our_section.extend(merged_names);
self.our_prefix = *new_prefix;
} else {
self.insert_new_section(*new_prefix, merged_names);
}
}
fn add_missing_prefixes(&mut self) {
let mut missing_pfxs = (0..self.our_prefix.bit_count())
.map(|i| self.our_prefix.with_flipped_bit(i))
.collect_vec();
while let Some(pfx) = missing_pfxs.pop() {
if !pfx.is_covered_by(self.sections.keys()) {
if self.sections.keys().any(|p| pfx.is_compatible(p)) {
missing_pfxs.push(pfx.pushed(true));
missing_pfxs.push(pfx.pushed(false));
} else {
self.insert_new_section(pfx, BTreeSet::new());
}
}
}
}
fn get_section_mut(&mut self, name: &T) -> Option<&mut BTreeSet<T>> {
if self.our_prefix.matches(name) {
return Some(&mut self.our_section);
}
if let Some(prefix) = self.find_section_prefix(name) {
return self.sections.get_mut(&prefix);
}
None
}
fn closest_section(&self, name: &T) -> (&Prefix<T>, &BTreeSet<T>) {
let mut result = (&self.our_prefix, &self.our_section);
for (prefix, section) in &self.sections {
if !section.is_empty() && result.0.cmp_distance(prefix, name) == Ordering::Greater {
result = (prefix, section)
}
}
result
}
fn get_routeth_name<'a, U: IntoIterator<Item = &'a T>>(names: U,
dst_name: &T,
route: usize)
-> &'a T {
let sorted_names =
names.into_iter().sorted_by(|&lhs, &rhs| dst_name.cmp_distance(lhs, rhs));
sorted_names[route % sorted_names.len()]
}
fn get_routeth_node(&self,
section: &BTreeSet<T>,
target: T,
exclude: Option<T>,
route: usize)
-> Result<T, Error> {
let names = if let Some(exclude) = exclude {
section.iter().filter(|&x| *x != exclude).collect_vec()
} else {
section.iter().collect_vec()
};
if names.is_empty() {
return Err(Error::CannotRoute);
}
Ok(*RoutingTable::get_routeth_name(names, &target, route))
}
fn check_invariant(&self,
allow_small_sections: bool,
show_warnings: bool)
-> Result<(), Error> {
let warn = |log_msg: String| -> Result<(), Error> {
if show_warnings {
warn!("{}", log_msg);
}
Err(Error::InvariantViolation)
};
if !self.our_prefix.matches(&self.our_name) {
return warn(format!("Our prefix does not match our name: {:?}", self));
}
if self.sections.contains_key(&self.our_prefix) {
return warn(format!("Our own section is in the sections map: {:?}", self));
}
let has_enough_nodes = self.len() >= self.min_section_size;
if has_enough_nodes && self.our_section.len() < self.min_section_size {
return warn(format!("Minimum section size not met for section {:?}: {:?}",
self.our_prefix,
self));
}
for name in &self.our_section {
if !self.our_prefix.matches(name) {
return warn(format!("Name {} doesn't match section prefix {:?}: {:?}",
name.debug_binary(),
self.our_prefix,
self));
}
}
for (prefix, section) in &self.sections {
if has_enough_nodes && section.len() < self.min_section_size {
if section.len() <= 1 && allow_small_sections {
continue;
}
return warn(format!("Minimum group size not met for group {:?}: {:?}",
prefix,
self));
}
for name in section {
if !prefix.matches(name) {
return warn(format!("Name {} doesn't match section prefix {:?}: {:?}",
name.debug_binary(),
prefix,
self));
}
}
}
let all_are_neighbours = self.sections.keys().all(|&x| self.our_prefix.is_neighbour(&x));
let all_neighbours_covered = {
let prefixes = self.prefixes();
(0..self.our_prefix.bit_count()).all(|i| {
self.our_prefix
.with_flipped_bit(i)
.is_covered_by(&prefixes)
})
};
if !all_are_neighbours {
return warn(format!("Some sections in the RT aren't neighbours of our section: {:?}",
self));
}
if !all_neighbours_covered {
return warn(format!("Some neighbours aren't fully covered by the RT: {:?}", self));
}
Ok(())
}
#[cfg(any(test, feature = "use-mock-crust"))]
pub fn verify_invariant(&self) {
unwrap!(self.check_invariant(false, true),
"Invariant not satisfied for RT: {:?}",
self);
}
#[cfg(test)]
fn num_of_sections(&self) -> usize {
self.sections.len()
}
}
impl<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> Binary for RoutingTable<T> {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
writeln!(formatter, "RoutingTable {{")?;
writeln!(formatter, "\tmin_section_size: {},", self.min_section_size)?;
writeln!(formatter,
"\tour_name: {:?} ({}),",
self.our_name,
self.our_name.debug_binary())?;
writeln!(formatter, "\tour_prefix: {:?}", self.our_prefix)?;
let sections = self.sections
.iter()
.chain(iter::once((&self.our_prefix, &self.our_section)))
.collect::<BTreeSet<_>>();
for (section_index, &(prefix, section)) in sections.iter().enumerate() {
write!(formatter,
"\tsection {} with {:?}: {{\n",
section_index,
prefix)?;
for (name_index, name) in section.iter().enumerate() {
let comma = if name_index == section.len() - 1 {
""
} else {
","
};
writeln!(formatter,
"\t\t{:?} ({}){}",
name,
name.debug_binary(),
comma)?;
}
let comma = if section_index == sections.len() - 1 {
""
} else {
","
};
writeln!(formatter, "\t}}{}", comma)?;
}
write!(formatter, "}}")
}
}
impl<T: Binary + Clone + Copy + Debug + Default + Hash + Xorable> Debug for RoutingTable<T> {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
Binary::fmt(self, formatter)
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::SPLIT_BUFFER;
use itertools::Itertools;
use std::collections::BTreeSet;
use std::str::FromStr;
#[test]
fn small() {
let name = 123u32;
let table = RoutingTable::new(name, 6);
assert_eq!(*table.our_name(), name);
assert_eq!(table.len(), 0);
assert!(table.is_empty());
assert_eq!(table.iter().count(), 0);
}
fn add_sequential_entries(table: &mut RoutingTable<u16>, name: &mut u16) {
for _ in 1..table.min_split_size() {
assert_eq!(table.add(*name, false), Ok(false));
table.verify_invariant();
*name += 1;
}
}
#[test]
fn test_routing_sections() {
assert!(SPLIT_BUFFER < 3818,
"Given the chosen values for 'our_name' and RT type (u16), this requires the \
SPLIT_BUFFER to be less than 3818.");
let our_name = 0b_0001_0001_0001_0001u16;
let mut table = RoutingTable::new(our_name, 5);
table.verify_invariant();
let mut expected_rt_len = 0; let mut section_00_name = our_name + 1;
let mut section_10_name = our_name.with_flipped_bit(0);
add_sequential_entries(&mut table, &mut section_00_name);
add_sequential_entries(&mut table, &mut section_10_name);
expected_rt_len += 2 * (table.min_split_size() - 1);
assert_eq!(table.add(section_10_name, false), Ok(true));
expected_rt_len += 1;
let mut expected_own_prefix = Prefix::new(0, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(expected_own_prefix);
expected_own_prefix = Prefix::new(1, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert_eq!(unwrap!(our_new_prefix), expected_own_prefix);
assert!(nodes_to_drop.is_empty());
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 2);
assert_eq!(table.our_section().len(), table.min_split_size());
let mut section_01_name = our_name.with_flipped_bit(1);
let mut section_11_name = section_10_name.with_flipped_bit(1);
add_sequential_entries(&mut table, &mut section_01_name);
add_sequential_entries(&mut table, &mut section_11_name);
expected_rt_len += 2 * (table.min_split_size() - 1);
assert_eq!(table.add(section_01_name, false), Ok(true));
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(expected_own_prefix);
expected_own_prefix = Prefix::new(2, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert_eq!(unwrap!(our_new_prefix), expected_own_prefix);
assert!(nodes_to_drop.is_empty());
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 3);
assert_eq!(table.our_section().len(), table.min_split_size());
assert_eq!(table.add(section_11_name, false), Ok(false));
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(Prefix::new(1, section_11_name));
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert!(our_new_prefix.is_none());
assert_eq!(nodes_to_drop.len(), table.min_split_size());
let mut drop_prefix = Prefix::new(2, section_11_name);
assert!(nodes_to_drop.iter().all(|name| drop_prefix.matches(name)));
expected_rt_len -= nodes_to_drop.len();
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 3);
assert_eq!(table.our_section().len(), table.min_split_size());
let mut section_001_name = our_name.with_flipped_bit(2);
let mut section_011_name = section_001_name.with_flipped_bit(1);
add_sequential_entries(&mut table, &mut section_001_name);
add_sequential_entries(&mut table, &mut section_011_name);
expected_rt_len += 2 * (table.min_split_size() - 1);
assert_eq!(table.add(section_011_name, false), Ok(false));
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(Prefix::new(2, section_011_name));
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert!(our_new_prefix.is_none());
assert!(nodes_to_drop.is_empty());
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 4);
assert_eq!(table.our_section().len(), 2 * table.min_split_size() - 1);
assert_eq!(table.add(section_001_name, false), Ok(true));
expected_rt_len += 1;
assert_eq!(*table.our_prefix(), expected_own_prefix);
let (nodes_to_drop, our_new_prefix) = table.split(expected_own_prefix);
expected_own_prefix = Prefix::new(3, our_name);
assert_eq!(*table.our_prefix(), expected_own_prefix);
assert_eq!(unwrap!(our_new_prefix), expected_own_prefix);
assert_eq!(nodes_to_drop.len(), table.min_split_size());
drop_prefix = Prefix::new(3, section_011_name);
assert!(nodes_to_drop.iter().all(|name| drop_prefix.matches(name)));
expected_rt_len -= nodes_to_drop.len();
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.all_sections().len(), 4);
assert_eq!(table.our_section().len(), table.min_split_size());
assert_eq!(table.add(section_001_name, false),
Err(Error::AlreadyExists));
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.add(our_name, false), Err(Error::OwnNameDisallowed));
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert_eq!(table.add(nodes_to_drop[0], false),
Err(Error::PeerNameUnsuitable));
table.verify_invariant();
assert_eq!(table.len(), expected_rt_len);
assert!(table.is_in_our_section(&our_name));
assert!(table.is_in_our_section(&(section_00_name - 1)));
assert!(!table.is_in_our_section(§ion_001_name));
assert!(!table.is_in_our_section(§ion_10_name));
let our_section = table.our_section().clone();
assert!(our_section.contains(&our_name));
assert_eq!(unwrap!(table.close_names(&our_name)), our_section);
assert_eq!(unwrap!(table.close_names(§ion_00_name)), our_section);
assert!(table.close_names(§ion_001_name).is_none());
assert!(table.close_names(§ion_10_name).is_none());
let our_section_without_us =
our_section.into_iter().filter(|name| *name != our_name).collect::<BTreeSet<_>>();
assert_eq!(unwrap!(table.other_close_names(&our_name)),
our_section_without_us);
assert_eq!(unwrap!(table.other_close_names(§ion_00_name)),
our_section_without_us);
assert!(table.other_close_names(§ion_001_name).is_none());
assert!(table.other_close_names(§ion_10_name).is_none());
assert_eq!(table.need_to_add(§ion_001_name),
Err(Error::AlreadyExists));
assert_eq!(table.need_to_add(&our_name), Err(Error::OwnNameDisallowed));
assert_eq!(table.need_to_add(&nodes_to_drop[0]),
Err(Error::PeerNameUnsuitable));
assert_eq!(table.need_to_add(&(section_001_name + 1)), Ok(()));
}
#[test]
fn test_closest_names() {
let our_name = 0u16;
let mut table = RoutingTable::new(our_name, 8);
unwrap!(table.add(0x8000, false));
unwrap!(table.add(0x4000, false));
unwrap!(table.add(0x2000, false));
unwrap!(table.add(0x1000, false));
unwrap!(table.add(0x0800, false));
unwrap!(table.add(0x0400, false));
unwrap!(table.add(0x0200, false));
unwrap!(table.add(0x0100, false));
unwrap!(table.add(0x0080, false));
unwrap!(table.add(0x0040, false));
let mut name = 0xFFFF;
assert!(table.closest_names(&name, 10).is_none());
assert!(table.other_closest_names(&name, 10).is_none());
assert!(table.closest_names(&name, 11).is_some());
let result = unwrap!(table.other_closest_names(&name, 11));
assert_eq!(result.len(), 10);
name = 0x01FF;
assert!(table.closest_names(&name, 3).is_none());
let result = unwrap!(table.closest_names(&name, 4));
assert_eq!(result.len(), 4);
assert_eq!(*result[0], 0x0100);
assert_eq!(*result[1], 0x0080);
assert_eq!(*result[2], 0x0040);
assert_eq!(*result[3], 0x0000);
let result = unwrap!(table.other_closest_names(&name, 4));
assert_eq!(result.len(), 3);
assert_eq!(*result[0], 0x0100);
assert_eq!(*result[1], 0x0080);
assert_eq!(*result[2], 0x0040);
}
#[test]
fn test_add_prefix() {
let our_name = 0u8;
let mut table = RoutingTable::new(our_name, 1);
for i in 1..0x10 {
unwrap!(table.add(i * 0x10, false));
}
assert_eq!(prefixes_from_strs(vec![""]), table.prefixes());
assert_eq!(Vec::<u8>::new(),
table.add_prefix(unwrap!(Prefix::from_str("01"))));
assert_eq!(prefixes_from_strs(vec!["1", "00", "01"]), table.prefixes());
assert_eq!(vec![0xc0, 0xd0, 0xe0, 0xf0u8],
table.add_prefix(unwrap!(Prefix::from_str("111"))).into_iter().sorted());
assert_eq!(prefixes_from_strs(vec!["110", "111", "10", "0"]),
table.prefixes());
assert_eq!(Vec::<u8>::new(),
table.add_prefix(unwrap!(Prefix::from_str("0"))));
assert_eq!(prefixes_from_strs(vec!["110", "111", "10", "0"]),
table.prefixes());
assert_eq!(Vec::<u8>::new(),
table.add_prefix(unwrap!(Prefix::from_str(""))));
assert_eq!(prefixes_from_strs(vec![""]), table.prefixes());
}
fn prefixes_from_strs(strs: Vec<&str>) -> BTreeSet<Prefix<u8>> {
strs.into_iter().map(|s| unwrap!(Prefix::from_str(s))).collect()
}
}