checkpoint

This commit is contained in:
John Smith
2022-08-08 20:42:27 -04:00
parent 0204af263d
commit 6226845e9f
16 changed files with 345 additions and 219 deletions

View File

@@ -35,11 +35,14 @@ pub enum BucketEntryState {
Reliable,
}
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
struct LastConnectionKey(PeerScope, ProtocolType, AddressType);
#[derive(Debug)]
pub struct BucketEntryInner {
min_max_version: Option<(u8, u8)>,
seen_our_node_info: bool,
last_connection: Option<(ConnectionDescriptor, u64)>,
last_connections: BTreeMap<LastConnectionKey, (ConnectionDescriptor, u64)>,
opt_signed_node_info: Option<SignedNodeInfo>,
opt_local_node_info: Option<LocalNodeInfo>,
peer_stats: PeerStats,
@@ -162,16 +165,45 @@ impl BucketEntryInner {
})
}
pub fn set_last_connection(&mut self, last_connection: ConnectionDescriptor, timestamp: u64) {
self.last_connection = Some((last_connection, timestamp));
}
pub fn clear_last_connection(&mut self) {
self.last_connection = None;
}
pub fn last_connection(&self) -> Option<(ConnectionDescriptor, u64)> {
self.last_connection
fn descriptor_to_key(last_connection: ConnectionDescriptor) -> LastConnectionKey {
LastConnectionKey(
last_connection.peer_scope(),
last_connection.protocol_type(),
last_connection.address_type(),
)
}
// Stores a connection descriptor in this entry's table of last connections
pub fn set_last_connection(&mut self, last_connection: ConnectionDescriptor, timestamp: u64) {
let key = Self::descriptor_to_key(last_connection);
self.last_connections
.insert(key, (last_connection, timestamp));
}
// Clears the table of last connections to ensure we create new ones and drop any existing ones
pub fn clear_last_connections(&mut self) {
self.last_connections.clear();
}
// Gets the best 'last connection' that matches a set of protocol types and address types
pub fn last_connection(
&self,
dial_info_filter: Option<DialInfoFilter>,
) -> Option<(ConnectionDescriptor, u64)> {
// Iterate peer scopes and protocol types and address type in order to ensure we pick the preferred protocols if all else is the same
let dif = dial_info_filter.unwrap_or_default();
for ps in dif.peer_scope_set {
for pt in dif.protocol_type_set {
for at in dif.address_type_set {
let key = LastConnectionKey(ps, pt, at);
if let Some(v) = self.last_connections.get(&key) {
return Some(*v);
}
}
}
}
None
}
pub fn set_min_max_version(&mut self, min_max_version: (u8, u8)) {
self.min_max_version = Some(min_max_version);
}
@@ -429,7 +461,7 @@ impl BucketEntry {
inner: RwLock::new(BucketEntryInner {
min_max_version: None,
seen_our_node_info: false,
last_connection: None,
last_connections: BTreeMap::new(),
opt_signed_node_info: None,
opt_local_node_info: None,
peer_stats: PeerStats {

View File

@@ -383,45 +383,93 @@ impl RoutingTable {
out
}
fn make_relay_node_filter(&self) -> impl Fn(&BucketEntryInner) -> bool {
// Get all our outbound protocol/address types
let protocol_config = self.network_manager().get_protocol_config();
let outbound_dif = self
.network_manager()
.get_outbound_dial_info_filter(RoutingDomain::PublicInternet);
move |e: &BucketEntryInner| {
// Ensure this node is not on our local network
let has_local_dial_info = e
.local_node_info()
.map(|l| l.has_dial_info())
.unwrap_or(false);
if has_local_dial_info {
return false;
}
// Disqualify nodes that don't have all our outbound protocol types
let can_serve_as_relay = e
.node_info()
.map(|n| {
let dids =
n.all_filtered_dial_info_details(|did| did.matches_filter(&outbound_dif));
for pt in protocol_config.outbound {
for at in protocol_config.family_global {
let mut found = false;
for did in &dids {
if did.dial_info.protocol_type() == pt
&& did.dial_info.address_type() == at
{
found = true;
break;
}
}
if !found {
return false;
}
}
}
true
})
.unwrap_or(false);
if !can_serve_as_relay {
return false;
}
true
}
}
#[instrument(level = "trace", skip(self), ret)]
pub fn find_inbound_relay(&self, cur_ts: u64) -> Option<NodeRef> {
// Get relay filter function
let relay_node_filter = self.make_relay_node_filter();
// Go through all entries and find fastest entry that matches filter function
let inner = self.inner.read();
let inner = &*inner;
let mut best_inbound_relay: Option<(DHTKey, Arc<BucketEntry>)> = None;
// Iterate all known nodes for candidates
Self::with_entries(inner, cur_ts, BucketEntryState::Unreliable, |k, v| {
// Ensure this node is not on our local network
if v.with(|e| {
e.local_node_info()
.map(|l| l.has_dial_info())
.unwrap_or(false)
}) {
return Option::<()>::None;
}
// Ensure we have the node's status
if let Some(node_status) = v.with(|e| e.peer_stats().status.clone()) {
// Ensure the node will relay
if node_status.will_relay {
// Compare against previous candidate
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
// Less is faster
let better = v.with(|e| {
best_inbound_relay.1.with(|best| {
let v2 = v.clone();
v.with(|e| {
// Ensure we have the node's status
if let Some(node_status) = e.peer_stats().status.clone() {
// Ensure the node will relay
if node_status.will_relay {
// Compare against previous candidate
if let Some(best_inbound_relay) = best_inbound_relay.as_mut() {
// Less is faster
let better = best_inbound_relay.1.with(|best| {
BucketEntryInner::cmp_fastest_reliable(cur_ts, e, best)
== std::cmp::Ordering::Less
})
});
if better {
*best_inbound_relay = (k, v);
});
// Now apply filter function and see if this node should be included
if better && relay_node_filter(e) {
*best_inbound_relay = (k, v2);
}
} else if relay_node_filter(e) {
// Always store the first candidate
best_inbound_relay = Some((k, v2));
}
} else {
// Always store the first candidate
best_inbound_relay = Some((k, v));
}
}
}
});
// Don't end early, iterate through all entries
Option::<()>::None
});
// Return the best inbound relay noderef

View File

@@ -395,7 +395,7 @@ impl RoutingTable {
for bucket in &mut inner.buckets {
for entry in bucket.entries() {
entry.1.with_mut(|e| {
e.clear_last_connection();
e.clear_last_connections();
});
}
}

View File

@@ -228,24 +228,8 @@ impl NodeRef {
pub async fn last_connection(&self) -> Option<ConnectionDescriptor> {
// Get the last connection and the last time we saw anything with this connection
let (last_connection, last_seen) = self.operate(|e| {
if let Some((last_connection, connection_ts)) = e.last_connection() {
if let Some(last_seen_ts) = e.peer_stats().rpc_stats.last_seen_ts {
Some((last_connection, u64::max(last_seen_ts, connection_ts)))
} else {
Some((last_connection, connection_ts))
}
} else {
None
}
})?;
// Verify this connection matches the noderef filter
if let Some(filter) = &self.filter {
if !last_connection.matches_filter(filter) {
return None;
}
}
let (last_connection, last_seen) =
self.operate(|e| e.last_connection(self.filter.clone()))?;
// Should we check the connection table?
if last_connection.protocol_type().is_connection_oriented() {
@@ -263,8 +247,8 @@ impl NodeRef {
Some(last_connection)
}
pub fn clear_last_connection(&self) {
self.operate_mut(|e| e.clear_last_connection())
pub fn clear_last_connections(&self) {
self.operate_mut(|e| e.clear_last_connections())
}
pub fn set_last_connection(&self, connection_descriptor: ConnectionDescriptor, ts: u64) {