first stab at #372

This commit is contained in:
Christien Rioux 2024-06-25 18:07:56 +00:00
parent 440195c267
commit bca3877024
3 changed files with 89 additions and 6 deletions

View File

@ -115,7 +115,11 @@ impl Bucket {
self.entries.iter()
}
pub(super) fn kick(&mut self, bucket_depth: usize) -> Option<BTreeSet<PublicKey>> {
pub(super) fn kick(
&mut self,
bucket_depth: usize,
closest_nodes: &BTreeSet<PublicKey>,
) -> Option<BTreeSet<PublicKey>> {
// Get number of entries to attempt to purge from bucket
let bucket_len = self.entries.len();
@ -167,6 +171,11 @@ impl Bucket {
continue;
}
// if this entry is one of our N closest entries, don't drop it
if closest_nodes.contains(&entry.0) {
continue;
}
// if no references, lets evict it
dead_node_ids.insert(entry.0);
}

View File

@ -358,9 +358,10 @@ impl RoutingTableInner {
"Starting routing table buckets purge. Table currently has {} nodes",
self.bucket_entry_count()
);
let closest_nodes = BTreeSet::new();
for ck in VALID_CRYPTO_KINDS {
for bucket in self.buckets.get_mut(&ck).unwrap().iter_mut() {
bucket.kick(0);
bucket.kick(0, &closest_nodes);
}
}
self.all_entries.remove_expired();
@ -396,11 +397,11 @@ impl RoutingTableInner {
/// Attempt to settle buckets and remove entries down to the desired number
/// which may not be possible due extant NodeRefs
pub fn kick_bucket(&mut self, bucket_index: BucketIndex) {
pub fn kick_bucket(&mut self, bucket_index: BucketIndex, closest_nodes: &BTreeSet<PublicKey>) {
let bucket = self.get_bucket_mut(bucket_index);
let bucket_depth = Self::bucket_depth(bucket_index);
if let Some(_dead_node_ids) = bucket.kick(bucket_depth) {
if let Some(_dead_node_ids) = bucket.kick(bucket_depth, closest_nodes) {
// Remove expired entries
self.all_entries.remove_expired();
@ -1252,7 +1253,7 @@ impl RoutingTableInner {
}
}
fn make_closest_noderef_sort(
pub(crate) fn make_closest_noderef_sort(
crypto: Crypto,
node_id: TypedKey,
) -> impl Fn(&NodeRefLocked, &NodeRefLocked) -> core::cmp::Ordering {
@ -1280,3 +1281,19 @@ fn make_closest_noderef_sort(
})
}
}
pub(crate) fn make_closest_node_id_sort(
crypto: Crypto,
node_id: TypedKey,
) -> impl Fn(&CryptoKey, &CryptoKey) -> core::cmp::Ordering {
let kind = node_id.kind;
// Get cryptoversion to check distance with
let vcrypto = crypto.get(kind).unwrap();
move |a: &CryptoKey, b: &CryptoKey| -> core::cmp::Ordering {
// distance is the next metric, closer nodes first
let da = vcrypto.distance(a, &node_id.value);
let db = vcrypto.distance(b, &node_id.value);
da.cmp(&db)
}
}

View File

@ -1,5 +1,11 @@
use super::*;
/// How many 'reliable' nodes closest to our own node id to keep
const KEEP_N_CLOSEST_RELIABLE_ENTRIES_COUNT: usize = 16;
/// How many 'unreliable' nodes closest to our own node id to keep
const KEEP_N_CLOSEST_UNRELIABLE_ENTRIES_COUNT: usize = 8;
impl RoutingTable {
// Kick the queued buckets in the routing table to free dead nodes if necessary
// Attempts to keep the size of the routing table down to the bucket depth
@ -15,8 +21,59 @@ impl RoutingTable {
.into_iter()
.collect();
let mut inner = self.inner.write();
// Get our closest nodes for each crypto kind
let mut closest_nodes_by_kind = BTreeMap::<CryptoKind, BTreeSet<PublicKey>>::new();
for kind in VALID_CRYPTO_KINDS {
let our_node_id = self.node_id(kind);
let Some(buckets) = inner.buckets.get(&kind) else {
continue;
};
let sort = make_closest_node_id_sort(self.crypto(), our_node_id);
let mut closest_nodes = BTreeSet::<CryptoKey>::new();
let mut closest_unreliable_count = 0usize;
let mut closest_reliable_count = 0usize;
// Iterate buckets backward, sort entries by closest distance first
'outer: for bucket in buckets.iter().rev() {
let mut entries = bucket.entries().collect::<Vec<_>>();
entries.sort_by(|a, b| sort(a.0, b.0));
for (key, entry) in entries {
let state = entry.with(&inner, |_rti, e| e.state(cur_ts));
match state {
BucketEntryState::Dead => {
// Do nothing with dead entries
}
BucketEntryState::Unreliable => {
// Add to closest unreliable nodes list
if closest_unreliable_count < KEEP_N_CLOSEST_UNRELIABLE_ENTRIES_COUNT {
closest_nodes.insert(*key);
closest_unreliable_count += 1;
}
}
BucketEntryState::Reliable => {
// Add to closest reliable nodes list
if closest_reliable_count < KEEP_N_CLOSEST_RELIABLE_ENTRIES_COUNT {
closest_nodes.insert(*key);
closest_reliable_count += 1;
}
}
}
if closest_unreliable_count == KEEP_N_CLOSEST_UNRELIABLE_ENTRIES_COUNT
&& closest_reliable_count == KEEP_N_CLOSEST_RELIABLE_ENTRIES_COUNT
{
break 'outer;
}
}
}
closest_nodes_by_kind.insert(kind, closest_nodes);
}
for bucket_index in kick_queue {
inner.kick_bucket(bucket_index)
inner.kick_bucket(bucket_index, &closest_nodes_by_kind[&bucket_index.0]);
}
Ok(())
}