Refactor AddressBook::update, add contains, get.

This also makes the quadratic `assert_consistency` check run only in
test configs.
This commit is contained in:
Henry de Valence 2019-10-18 11:04:38 -07:00 committed by Deirdre Connolly
parent 501db9fcc8
commit a8ef02c826
1 changed files with 36 additions and 31 deletions

View File

@ -26,6 +26,9 @@ pub struct AddressBook {
} }
impl AddressBook { impl AddressBook {
/// Check consistency of the address book invariants or panic, doing work
/// quadratic in the address book size.
#[cfg(test)]
fn assert_consistency(&self) { fn assert_consistency(&self) {
for (a, (t, s)) in self.by_addr.iter() { for (a, (t, s)) in self.by_addr.iter() {
for meta in self.by_time.iter().filter(|meta| meta.addr == *a) { for meta in self.by_time.iter().filter(|meta| meta.addr == *a) {
@ -36,47 +39,49 @@ impl AddressBook {
} }
} }
/// Update the address book with `event`, a [`MetaAddr`] representing /// Returns true if the address book has an entry for `addr`.
/// observation of a peer. pub fn contains_addr(&self, addr: &SocketAddr) -> bool {
pub fn update(&mut self, event: MetaAddr) { self.by_addr.contains_key(addr)
use std::collections::hash_map::Entry; }
/// Returns the entry corresponding to `addr`, or `None` if it does not exist.
pub fn get_by_addr(&self, addr: SocketAddr) -> Option<MetaAddr> {
let (last_seen, services) = self.by_addr.get(&addr).cloned()?;
Some(MetaAddr {
addr,
last_seen,
services,
})
}
/// Add `new` to the address book, updating the previous entry if `new` is
/// more recent or discarding `new` if it is stale.
pub fn update(&mut self, new: MetaAddr) {
trace!( trace!(
?event, ?new,
data.total = self.by_time.len(), data.total = self.by_time.len(),
data.recent = (self.by_time.len() - self.disconnected_peers().count()), data.recent = (self.by_time.len() - self.disconnected_peers().count()),
); );
//self.assert_consistency(); #[cfg(test)]
self.assert_consistency();
let MetaAddr { match self.get_by_addr(new.addr) {
addr, Some(prev) => {
services, if prev.last_seen > new.last_seen {
last_seen,
} = event;
match self.by_addr.entry(addr) {
Entry::Occupied(mut entry) => {
let (prev_last_seen, prev_services) = entry.get().clone();
// Ignore stale entries.
if prev_last_seen > last_seen {
return; return;
} else {
self.by_time
.take(&prev)
.expect("cannot have by_addr entry without by_time entry");
} }
self.by_time
.take(&MetaAddr {
addr,
services: prev_services,
last_seen: prev_last_seen,
})
.expect("cannot have by_addr entry without by_time entry");
entry.insert((last_seen, services));
self.by_time.insert(event);
}
Entry::Vacant(entry) => {
entry.insert((last_seen, services));
self.by_time.insert(event);
} }
None => {}
} }
//self.assert_consistency(); self.by_time.insert(new);
self.by_addr.insert(new.addr, (new.last_seen, new.services));
#[cfg(test)]
self.assert_consistency();
} }
/// Compute a cutoff time that can determine whether an entry /// Compute a cutoff time that can determine whether an entry