checkpoint
This commit is contained in:
@@ -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 {
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
Reference in New Issue
Block a user