mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-02 16:21:42 +00:00
Enforce a timeout on peer disconnect (#3757)
On heavily crowded networks, we are seeing many attempted connections to our node every second. Often these connections come from peers that have just been disconnected. This can be for a number of reasons including: - We have deemed them to be not as useful as other peers - They have performed poorly - They have dropped the connection with us - The connection was spontaneously lost - They were randomly removed because we have too many peers In all of these cases, if we have reached or exceeded our target peer limit, there is no desire to accept new connections immediately after the disconnect from these peers. In fact, it often costs us resources to handle the established connections and defeats some of the logic of dropping them in the first place. This PR adds a timeout, that prevents recently disconnected peers from reconnecting to us. Technically we implement a ban at the swarm layer to prevent immediate re connections for at least 10 minutes. I decided to keep this light, and use a time-based LRUCache which only gets updated during the peer manager heartbeat to prevent added stress of polling a delay map for what could be a large number of peers. This cache is bounded in time. An extra space bound could be added should people consider this a risk. Co-authored-by: Diva M <divma@protonmail.com>
This commit is contained in:
@@ -31,6 +31,77 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserts a key without removal of potentially expired elements.
|
||||
/// Returns true if the key does not already exist.
|
||||
pub fn raw_insert(&mut self, key: Key) -> bool {
|
||||
// check the cache before removing elements
|
||||
let is_new = self.map.insert(key.clone());
|
||||
|
||||
// add the new key to the list, if it doesn't already exist.
|
||||
if is_new {
|
||||
self.list.push_back(Element {
|
||||
key,
|
||||
inserted: Instant::now(),
|
||||
});
|
||||
} else {
|
||||
let position = self
|
||||
.list
|
||||
.iter()
|
||||
.position(|e| e.key == key)
|
||||
.expect("Key is not new");
|
||||
let mut element = self
|
||||
.list
|
||||
.remove(position)
|
||||
.expect("Position is not occupied");
|
||||
element.inserted = Instant::now();
|
||||
self.list.push_back(element);
|
||||
}
|
||||
#[cfg(test)]
|
||||
self.check_invariant();
|
||||
is_new
|
||||
}
|
||||
|
||||
/// Removes a key from the cache without purging expired elements. Returns true if the key
|
||||
/// existed.
|
||||
pub fn raw_remove(&mut self, key: &Key) -> bool {
|
||||
if self.map.remove(key) {
|
||||
let position = self
|
||||
.list
|
||||
.iter()
|
||||
.position(|e| &e.key == key)
|
||||
.expect("Key must exist");
|
||||
self.list
|
||||
.remove(position)
|
||||
.expect("Position is not occupied");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all expired elements and returns them
|
||||
pub fn remove_expired(&mut self) -> Vec<Key> {
|
||||
if self.list.is_empty() {
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
let mut removed_elements = Vec::new();
|
||||
let now = Instant::now();
|
||||
// remove any expired results
|
||||
while let Some(element) = self.list.pop_front() {
|
||||
if element.inserted + self.ttl > now {
|
||||
self.list.push_front(element);
|
||||
break;
|
||||
}
|
||||
self.map.remove(&element.key);
|
||||
removed_elements.push(element.key);
|
||||
}
|
||||
#[cfg(test)]
|
||||
self.check_invariant();
|
||||
|
||||
removed_elements
|
||||
}
|
||||
|
||||
// Inserts a new key. It first purges expired elements to do so.
|
||||
//
|
||||
// If the key was not present this returns `true`. If the value was already present this
|
||||
|
||||
Reference in New Issue
Block a user