From 4a567cd631cc6bdd220904b1af6fdf524192769b Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 15 Apr 2024 17:39:50 +0100 Subject: [PATCH 1/4] refactor: extract PeerList Extract a type for a collection of peers. The performance adter the exatract is similar: ```output Requests out: 415067.21/second Responses in: 369397.08/second - Connect responses: 183049.81 - Announce responses: 182717.15 - Scrape responses: 3630.12 - Error responses: 0.00 Peers per announce response: 0.00 Announce responses per info hash: - p10: 1 - p25: 1 - p50: 1 - p75: 1 - p90: 2 - p95: 3 - p99: 104 - p99.9: 297 - p100: 375 ``` --- packages/torrent-repository/src/entry/mod.rs | 68 ++++++++++++++++++- .../torrent-repository/src/entry/single.rs | 32 ++------- .../src/repository/dash_map_mutex_std.rs | 5 +- .../src/repository/rw_lock_std.rs | 6 +- .../src/repository/rw_lock_std_mutex_std.rs | 5 +- .../src/repository/rw_lock_std_mutex_tokio.rs | 5 +- .../src/repository/rw_lock_tokio.rs | 6 +- .../src/repository/rw_lock_tokio_mutex_std.rs | 5 +- .../repository/rw_lock_tokio_mutex_tokio.rs | 5 +- .../src/repository/skip_map_mutex_std.rs | 5 +- 10 files changed, 88 insertions(+), 54 deletions(-) diff --git a/packages/torrent-repository/src/entry/mod.rs b/packages/torrent-repository/src/entry/mod.rs index d72ff254..ee80305e 100644 --- a/packages/torrent-repository/src/entry/mod.rs +++ b/packages/torrent-repository/src/entry/mod.rs @@ -82,8 +82,72 @@ pub trait EntryAsync { #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Torrent { /// The swarm: a network of peers that are all trying to download the torrent associated to this entry - // #[serde(skip)] - pub(crate) peers: std::collections::BTreeMap>, + pub(crate) peers: PeerList, /// The number of peers that have ever completed downloading the torrent associated to this entry pub(crate) downloaded: u32, } + +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct PeerList { + peers: std::collections::BTreeMap>, +} + +impl PeerList { + fn len(&self) -> usize { + self.peers.len() + } + + fn is_empty(&self) -> bool { + self.peers.is_empty() + } + + fn insert(&mut self, key: peer::Id, value: Arc) -> Option> { + self.peers.insert(key, value) + } + + fn remove(&mut self, key: &peer::Id) -> Option> { + self.peers.remove(key) + } + + fn retain(&mut self, f: F) + where + F: FnMut(&peer::Id, &mut Arc) -> bool, + { + self.peers.retain(f); + } + + fn seeders_and_leechers(&self) -> (usize, usize) { + let seeders = self.peers.values().filter(|peer| peer.is_seeder()).count(); + let leechers = self.len() - seeders; + + (seeders, leechers) + } + + fn get_peers(&self, limit: Option) -> Vec> { + match limit { + Some(limit) => self.peers.values().take(limit).cloned().collect(), + None => self.peers.values().cloned().collect(), + } + } + + fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { + match limit { + Some(limit) => self + .peers + .values() + // Take peers which are not the client peer + .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) + // Limit the number of peers on the result + .take(limit) + .cloned() + .collect(), + None => self + .peers + .values() + // Take peers which are not the client peer + .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) + .cloned() + .collect(), + } + } +} diff --git a/packages/torrent-repository/src/entry/single.rs b/packages/torrent-repository/src/entry/single.rs index a38b5402..36d04c3c 100644 --- a/packages/torrent-repository/src/entry/single.rs +++ b/packages/torrent-repository/src/entry/single.rs @@ -13,13 +13,12 @@ use crate::EntrySingle; impl Entry for EntrySingle { #[allow(clippy::cast_possible_truncation)] fn get_swarm_metadata(&self) -> SwarmMetadata { - let complete: u32 = self.peers.values().filter(|peer| peer.is_seeder()).count() as u32; - let incomplete: u32 = self.peers.len() as u32 - complete; + let (seeders, leechers) = self.peers.seeders_and_leechers(); SwarmMetadata { downloaded: self.downloaded, - complete, - incomplete, + complete: seeders as u32, + incomplete: leechers as u32, } } @@ -42,32 +41,13 @@ impl Entry for EntrySingle { fn get_peers_len(&self) -> usize { self.peers.len() } + fn get_peers(&self, limit: Option) -> Vec> { - match limit { - Some(limit) => self.peers.values().take(limit).cloned().collect(), - None => self.peers.values().cloned().collect(), - } + self.peers.get_peers(limit) } fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { - match limit { - Some(limit) => self - .peers - .values() - // Take peers which are not the client peer - .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) - // Limit the number of peers on the result - .take(limit) - .cloned() - .collect(), - None => self - .peers - .values() - // Take peers which are not the client peer - .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) - .cloned() - .collect(), - } + self.peers.get_peers_for_client(client, limit) } fn upsert_peer(&mut self, peer: &peer::Peer) -> bool { diff --git a/packages/torrent-repository/src/repository/dash_map_mutex_std.rs b/packages/torrent-repository/src/repository/dash_map_mutex_std.rs index b398b09d..2aba7e54 100644 --- a/packages/torrent-repository/src/repository/dash_map_mutex_std.rs +++ b/packages/torrent-repository/src/repository/dash_map_mutex_std.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::sync::Arc; use dashmap::DashMap; @@ -10,7 +9,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, EntrySync}; +use crate::entry::{Entry, EntrySync, PeerList}; use crate::{EntryMutexStd, EntrySingle}; #[derive(Default, Debug)] @@ -82,7 +81,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_std.rs b/packages/torrent-repository/src/repository/rw_lock_std.rs index af48428e..7d8055fc 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeMap; - use torrust_tracker_configuration::TrackerPolicy; use torrust_tracker_primitives::info_hash::InfoHash; use torrust_tracker_primitives::pagination::Pagination; @@ -8,7 +6,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::Entry; +use crate::entry::{Entry, PeerList}; use crate::{EntrySingle, TorrentsRwLockStd}; #[derive(Default, Debug)] @@ -102,7 +100,7 @@ where } let entry = EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *downloaded, }; diff --git a/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs b/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs index 74cdc447..629f3484 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::sync::Arc; use torrust_tracker_configuration::TrackerPolicy; @@ -9,7 +8,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, EntrySync}; +use crate::entry::{Entry, EntrySync, PeerList}; use crate::{EntryMutexStd, EntrySingle, TorrentsRwLockStdMutexStd}; impl TorrentsRwLockStdMutexStd { @@ -97,7 +96,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs index 83ac02c9..3cc0f53a 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::iter::zip; use std::pin::Pin; use std::sync::Arc; @@ -13,7 +12,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, EntryAsync}; +use crate::entry::{Entry, EntryAsync, PeerList}; use crate::{EntryMutexTokio, EntrySingle, TorrentsRwLockStdMutexTokio}; impl TorrentsRwLockStdMutexTokio { @@ -106,7 +105,7 @@ where let entry = EntryMutexTokio::new( EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_tokio.rs index b95f1e31..0a481fdd 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeMap; - use torrust_tracker_configuration::TrackerPolicy; use torrust_tracker_primitives::info_hash::InfoHash; use torrust_tracker_primitives::pagination::Pagination; @@ -8,7 +6,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::Entry; +use crate::entry::{Entry, PeerList}; use crate::{EntrySingle, TorrentsRwLockTokio}; #[derive(Default, Debug)] @@ -106,7 +104,7 @@ where } let entry = EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, }; diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs index bde95994..d3b17c2d 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::sync::Arc; use torrust_tracker_configuration::TrackerPolicy; @@ -9,7 +8,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, EntrySync}; +use crate::entry::{Entry, EntrySync, PeerList}; use crate::{EntryMutexStd, EntrySingle, TorrentsRwLockTokioMutexStd}; impl TorrentsRwLockTokioMutexStd { @@ -97,7 +96,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs index 1d002e31..875a890e 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::sync::Arc; use torrust_tracker_configuration::TrackerPolicy; @@ -9,7 +8,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, EntryAsync}; +use crate::entry::{Entry, EntryAsync, PeerList}; use crate::{EntryMutexTokio, EntrySingle, TorrentsRwLockTokioMutexTokio}; impl TorrentsRwLockTokioMutexTokio { @@ -100,7 +99,7 @@ where let entry = EntryMutexTokio::new( EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/skip_map_mutex_std.rs b/packages/torrent-repository/src/repository/skip_map_mutex_std.rs index ef3e7e47..b3c71a4d 100644 --- a/packages/torrent-repository/src/repository/skip_map_mutex_std.rs +++ b/packages/torrent-repository/src/repository/skip_map_mutex_std.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::sync::Arc; use crossbeam_skiplist::SkipMap; @@ -10,7 +9,7 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, EntrySync}; +use crate::entry::{Entry, EntrySync, PeerList}; use crate::{EntryMutexStd, EntrySingle}; #[derive(Default, Debug)] @@ -76,7 +75,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: PeerList::default(), downloaded: *completed, } .into(), From 922afda1e689faa62a54cb29ccc6bd7619a4f018 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 15 Apr 2024 17:48:08 +0100 Subject: [PATCH 2/4] refactor: rename field from peers to swarm --- packages/torrent-repository/src/entry/mod.rs | 4 ++-- .../torrent-repository/src/entry/single.rs | 20 +++++++++---------- .../src/repository/dash_map_mutex_std.rs | 2 +- .../src/repository/rw_lock_std.rs | 2 +- .../src/repository/rw_lock_std_mutex_std.rs | 2 +- .../src/repository/rw_lock_std_mutex_tokio.rs | 2 +- .../src/repository/rw_lock_tokio.rs | 2 +- .../src/repository/rw_lock_tokio_mutex_std.rs | 2 +- .../repository/rw_lock_tokio_mutex_tokio.rs | 2 +- .../src/repository/skip_map_mutex_std.rs | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/torrent-repository/src/entry/mod.rs b/packages/torrent-repository/src/entry/mod.rs index ee80305e..648ded98 100644 --- a/packages/torrent-repository/src/entry/mod.rs +++ b/packages/torrent-repository/src/entry/mod.rs @@ -81,8 +81,8 @@ pub trait EntryAsync { /// The tracker keeps one entry like this for every torrent. #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Torrent { - /// The swarm: a network of peers that are all trying to download the torrent associated to this entry - pub(crate) peers: PeerList, + /// A network of peers that are all trying to download the torrent associated to this entry + pub(crate) swarm: PeerList, /// The number of peers that have ever completed downloading the torrent associated to this entry pub(crate) downloaded: u32, } diff --git a/packages/torrent-repository/src/entry/single.rs b/packages/torrent-repository/src/entry/single.rs index 36d04c3c..169ee2fb 100644 --- a/packages/torrent-repository/src/entry/single.rs +++ b/packages/torrent-repository/src/entry/single.rs @@ -13,7 +13,7 @@ use crate::EntrySingle; impl Entry for EntrySingle { #[allow(clippy::cast_possible_truncation)] fn get_swarm_metadata(&self) -> SwarmMetadata { - let (seeders, leechers) = self.peers.seeders_and_leechers(); + let (seeders, leechers) = self.swarm.seeders_and_leechers(); SwarmMetadata { downloaded: self.downloaded, @@ -27,7 +27,7 @@ impl Entry for EntrySingle { return true; } - if policy.remove_peerless_torrents && self.peers.is_empty() { + if policy.remove_peerless_torrents && self.swarm.is_empty() { return false; } @@ -35,19 +35,19 @@ impl Entry for EntrySingle { } fn peers_is_empty(&self) -> bool { - self.peers.is_empty() + self.swarm.is_empty() } fn get_peers_len(&self) -> usize { - self.peers.len() + self.swarm.len() } fn get_peers(&self, limit: Option) -> Vec> { - self.peers.get_peers(limit) + self.swarm.get_peers(limit) } fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { - self.peers.get_peers_for_client(client, limit) + self.swarm.get_peers_for_client(client, limit) } fn upsert_peer(&mut self, peer: &peer::Peer) -> bool { @@ -55,10 +55,10 @@ impl Entry for EntrySingle { match peer::ReadInfo::get_event(peer) { AnnounceEvent::Stopped => { - drop(self.peers.remove(&peer::ReadInfo::get_id(peer))); + drop(self.swarm.remove(&peer::ReadInfo::get_id(peer))); } AnnounceEvent::Completed => { - let previous = self.peers.insert(peer::ReadInfo::get_id(peer), Arc::new(*peer)); + let previous = self.swarm.insert(peer::ReadInfo::get_id(peer), Arc::new(*peer)); // Don't count if peer was not previously known and not already completed. if previous.is_some_and(|p| p.event != AnnounceEvent::Completed) { self.downloaded += 1; @@ -66,7 +66,7 @@ impl Entry for EntrySingle { } } _ => { - drop(self.peers.insert(peer::ReadInfo::get_id(peer), Arc::new(*peer))); + drop(self.swarm.insert(peer::ReadInfo::get_id(peer), Arc::new(*peer))); } } @@ -74,7 +74,7 @@ impl Entry for EntrySingle { } fn remove_inactive_peers(&mut self, current_cutoff: DurationSinceUnixEpoch) { - self.peers + self.swarm .retain(|_, peer| peer::ReadInfo::get_updated(peer) > current_cutoff); } } diff --git a/packages/torrent-repository/src/repository/dash_map_mutex_std.rs b/packages/torrent-repository/src/repository/dash_map_mutex_std.rs index 2aba7e54..7bc60dbc 100644 --- a/packages/torrent-repository/src/repository/dash_map_mutex_std.rs +++ b/packages/torrent-repository/src/repository/dash_map_mutex_std.rs @@ -81,7 +81,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_std.rs b/packages/torrent-repository/src/repository/rw_lock_std.rs index 7d8055fc..800b1b31 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std.rs @@ -100,7 +100,7 @@ where } let entry = EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *downloaded, }; diff --git a/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs b/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs index 629f3484..9fefc911 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs @@ -96,7 +96,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs index 3cc0f53a..31ccf2a5 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs @@ -105,7 +105,7 @@ where let entry = EntryMutexTokio::new( EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_tokio.rs index 0a481fdd..0987b064 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio.rs @@ -104,7 +104,7 @@ where } let entry = EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, }; diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs index d3b17c2d..77a82e44 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs @@ -96,7 +96,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs index 875a890e..fc760801 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs @@ -99,7 +99,7 @@ where let entry = EntryMutexTokio::new( EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/src/repository/skip_map_mutex_std.rs b/packages/torrent-repository/src/repository/skip_map_mutex_std.rs index b3c71a4d..7f84dae2 100644 --- a/packages/torrent-repository/src/repository/skip_map_mutex_std.rs +++ b/packages/torrent-repository/src/repository/skip_map_mutex_std.rs @@ -75,7 +75,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: PeerList::default(), + swarm: PeerList::default(), downloaded: *completed, } .into(), From 42f1b309a68d746f221ed377133cb9f2fa5e6208 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 15 Apr 2024 17:58:20 +0100 Subject: [PATCH 3/4] refactor: extract mod peer_list --- packages/torrent-repository/src/entry/mod.rs | 69 +---------------- .../torrent-repository/src/entry/peer_list.rs | 74 +++++++++++++++++++ .../src/repository/dash_map_mutex_std.rs | 3 +- .../src/repository/rw_lock_std.rs | 3 +- .../src/repository/rw_lock_std_mutex_std.rs | 3 +- .../src/repository/rw_lock_std_mutex_tokio.rs | 3 +- .../src/repository/rw_lock_tokio.rs | 3 +- .../src/repository/rw_lock_tokio_mutex_std.rs | 3 +- .../repository/rw_lock_tokio_mutex_tokio.rs | 3 +- .../src/repository/skip_map_mutex_std.rs | 3 +- 10 files changed, 93 insertions(+), 74 deletions(-) create mode 100644 packages/torrent-repository/src/entry/peer_list.rs diff --git a/packages/torrent-repository/src/entry/mod.rs b/packages/torrent-repository/src/entry/mod.rs index 648ded98..40fa4efd 100644 --- a/packages/torrent-repository/src/entry/mod.rs +++ b/packages/torrent-repository/src/entry/mod.rs @@ -2,13 +2,15 @@ use std::fmt::Debug; use std::net::SocketAddr; use std::sync::Arc; -//use serde::{Deserialize, Serialize}; use torrust_tracker_configuration::TrackerPolicy; use torrust_tracker_primitives::swarm_metadata::SwarmMetadata; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch}; +use self::peer_list::PeerList; + pub mod mutex_std; pub mod mutex_tokio; +pub mod peer_list; pub mod single; pub trait Entry { @@ -86,68 +88,3 @@ pub struct Torrent { /// The number of peers that have ever completed downloading the torrent associated to this entry pub(crate) downloaded: u32, } - -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct PeerList { - peers: std::collections::BTreeMap>, -} - -impl PeerList { - fn len(&self) -> usize { - self.peers.len() - } - - fn is_empty(&self) -> bool { - self.peers.is_empty() - } - - fn insert(&mut self, key: peer::Id, value: Arc) -> Option> { - self.peers.insert(key, value) - } - - fn remove(&mut self, key: &peer::Id) -> Option> { - self.peers.remove(key) - } - - fn retain(&mut self, f: F) - where - F: FnMut(&peer::Id, &mut Arc) -> bool, - { - self.peers.retain(f); - } - - fn seeders_and_leechers(&self) -> (usize, usize) { - let seeders = self.peers.values().filter(|peer| peer.is_seeder()).count(); - let leechers = self.len() - seeders; - - (seeders, leechers) - } - - fn get_peers(&self, limit: Option) -> Vec> { - match limit { - Some(limit) => self.peers.values().take(limit).cloned().collect(), - None => self.peers.values().cloned().collect(), - } - } - - fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { - match limit { - Some(limit) => self - .peers - .values() - // Take peers which are not the client peer - .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) - // Limit the number of peers on the result - .take(limit) - .cloned() - .collect(), - None => self - .peers - .values() - // Take peers which are not the client peer - .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) - .cloned() - .collect(), - } - } -} diff --git a/packages/torrent-repository/src/entry/peer_list.rs b/packages/torrent-repository/src/entry/peer_list.rs new file mode 100644 index 00000000..4af9b1d7 --- /dev/null +++ b/packages/torrent-repository/src/entry/peer_list.rs @@ -0,0 +1,74 @@ +use std::net::SocketAddr; +use std::sync::Arc; + +use torrust_tracker_primitives::peer; + +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct PeerList { + peers: std::collections::BTreeMap>, +} + +impl PeerList { + #[must_use] + pub fn len(&self) -> usize { + self.peers.len() + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.peers.is_empty() + } + + pub fn insert(&mut self, key: peer::Id, value: Arc) -> Option> { + self.peers.insert(key, value) + } + + pub fn remove(&mut self, key: &peer::Id) -> Option> { + self.peers.remove(key) + } + + pub fn retain(&mut self, f: F) + where + F: FnMut(&peer::Id, &mut Arc) -> bool, + { + self.peers.retain(f); + } + + #[must_use] + pub fn seeders_and_leechers(&self) -> (usize, usize) { + let seeders = self.peers.values().filter(|peer| peer.is_seeder()).count(); + let leechers = self.len() - seeders; + + (seeders, leechers) + } + + #[must_use] + pub fn get_peers(&self, limit: Option) -> Vec> { + match limit { + Some(limit) => self.peers.values().take(limit).cloned().collect(), + None => self.peers.values().cloned().collect(), + } + } + + #[must_use] + pub fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { + match limit { + Some(limit) => self + .peers + .values() + // Take peers which are not the client peer + .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) + // Limit the number of peers on the result + .take(limit) + .cloned() + .collect(), + None => self + .peers + .values() + // Take peers which are not the client peer + .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) + .cloned() + .collect(), + } + } +} diff --git a/packages/torrent-repository/src/repository/dash_map_mutex_std.rs b/packages/torrent-repository/src/repository/dash_map_mutex_std.rs index 7bc60dbc..a3820520 100644 --- a/packages/torrent-repository/src/repository/dash_map_mutex_std.rs +++ b/packages/torrent-repository/src/repository/dash_map_mutex_std.rs @@ -9,7 +9,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, EntrySync, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::{Entry, EntrySync}; use crate::{EntryMutexStd, EntrySingle}; #[derive(Default, Debug)] diff --git a/packages/torrent-repository/src/repository/rw_lock_std.rs b/packages/torrent-repository/src/repository/rw_lock_std.rs index 800b1b31..0d96a237 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std.rs @@ -6,7 +6,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::Entry; use crate::{EntrySingle, TorrentsRwLockStd}; #[derive(Default, Debug)] diff --git a/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs b/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs index 9fefc911..76d5e8f1 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std_mutex_std.rs @@ -8,7 +8,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, EntrySync, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::{Entry, EntrySync}; use crate::{EntryMutexStd, EntrySingle, TorrentsRwLockStdMutexStd}; impl TorrentsRwLockStdMutexStd { diff --git a/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs index 31ccf2a5..e527d6b5 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std_mutex_tokio.rs @@ -12,7 +12,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, EntryAsync, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::{Entry, EntryAsync}; use crate::{EntryMutexTokio, EntrySingle, TorrentsRwLockStdMutexTokio}; impl TorrentsRwLockStdMutexTokio { diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_tokio.rs index 0987b064..c360106b 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio.rs @@ -6,7 +6,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::Entry; use crate::{EntrySingle, TorrentsRwLockTokio}; #[derive(Default, Debug)] diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs index 77a82e44..9fce79b4 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_std.rs @@ -8,7 +8,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, EntrySync, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::{Entry, EntrySync}; use crate::{EntryMutexStd, EntrySingle, TorrentsRwLockTokioMutexStd}; impl TorrentsRwLockTokioMutexStd { diff --git a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs index fc760801..c7e0d405 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio_mutex_tokio.rs @@ -8,7 +8,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::RepositoryAsync; -use crate::entry::{Entry, EntryAsync, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::{Entry, EntryAsync}; use crate::{EntryMutexTokio, EntrySingle, TorrentsRwLockTokioMutexTokio}; impl TorrentsRwLockTokioMutexTokio { diff --git a/packages/torrent-repository/src/repository/skip_map_mutex_std.rs b/packages/torrent-repository/src/repository/skip_map_mutex_std.rs index 7f84dae2..bc9ecd06 100644 --- a/packages/torrent-repository/src/repository/skip_map_mutex_std.rs +++ b/packages/torrent-repository/src/repository/skip_map_mutex_std.rs @@ -9,7 +9,8 @@ use torrust_tracker_primitives::torrent_metrics::TorrentsMetrics; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch, PersistentTorrents}; use super::Repository; -use crate::entry::{Entry, EntrySync, PeerList}; +use crate::entry::peer_list::PeerList; +use crate::entry::{Entry, EntrySync}; use crate::{EntryMutexStd, EntrySingle}; #[derive(Default, Debug)] From 40182b49e0c221ed85fb78f4243cc180cc96ed1e Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Tue, 16 Apr 2024 12:00:28 +0100 Subject: [PATCH 4/4] test: add tests for PeerList type --- packages/primitives/src/peer.rs | 39 +++ .../torrent-repository/src/entry/peer_list.rs | 249 ++++++++++++++++-- .../torrent-repository/src/entry/single.rs | 11 +- 3 files changed, 276 insertions(+), 23 deletions(-) diff --git a/packages/primitives/src/peer.rs b/packages/primitives/src/peer.rs index f5b009f2..ab755950 100644 --- a/packages/primitives/src/peer.rs +++ b/packages/primitives/src/peer.rs @@ -362,6 +362,38 @@ pub mod fixture { } impl PeerBuilder { + #[allow(dead_code)] + #[must_use] + pub fn seeder() -> Self { + let peer = Peer { + peer_id: Id(*b"-qB00000000000000001"), + peer_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 8080), + updated: DurationSinceUnixEpoch::new(1_669_397_478_934, 0), + uploaded: NumberOfBytes(0), + downloaded: NumberOfBytes(0), + left: NumberOfBytes(0), + event: AnnounceEvent::Completed, + }; + + Self { peer } + } + + #[allow(dead_code)] + #[must_use] + pub fn leecher() -> Self { + let peer = Peer { + peer_id: Id(*b"-qB00000000000000002"), + peer_addr: SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 8080), + updated: DurationSinceUnixEpoch::new(1_669_397_478_934, 0), + uploaded: NumberOfBytes(0), + downloaded: NumberOfBytes(0), + left: NumberOfBytes(10), + event: AnnounceEvent::Started, + }; + + Self { peer } + } + #[allow(dead_code)] #[must_use] pub fn with_peer_id(mut self, peer_id: &Id) -> Self { @@ -390,6 +422,13 @@ pub mod fixture { self } + #[allow(dead_code)] + #[must_use] + pub fn last_updated_on(mut self, updated: DurationSinceUnixEpoch) -> Self { + self.peer.updated = updated; + self + } + #[allow(dead_code)] #[must_use] pub fn build(self) -> Peer { diff --git a/packages/torrent-repository/src/entry/peer_list.rs b/packages/torrent-repository/src/entry/peer_list.rs index 4af9b1d7..3f69edbb 100644 --- a/packages/torrent-repository/src/entry/peer_list.rs +++ b/packages/torrent-repository/src/entry/peer_list.rs @@ -1,7 +1,13 @@ +//! A peer list. use std::net::SocketAddr; use std::sync::Arc; -use torrust_tracker_primitives::peer; +use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch}; + +// code-review: the current implementation uses the peer Id as the ``BTreeMap`` +// key. That would allow adding two identical peers except for the Id. +// For example, two peers with the same socket address but a different peer Id +// would be allowed. That would lead to duplicated peers in the tracker responses. #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct PeerList { @@ -19,31 +25,26 @@ impl PeerList { self.peers.is_empty() } - pub fn insert(&mut self, key: peer::Id, value: Arc) -> Option> { - self.peers.insert(key, value) + pub fn upsert(&mut self, value: Arc) -> Option> { + self.peers.insert(value.peer_id, value) } pub fn remove(&mut self, key: &peer::Id) -> Option> { self.peers.remove(key) } - pub fn retain(&mut self, f: F) - where - F: FnMut(&peer::Id, &mut Arc) -> bool, - { - self.peers.retain(f); + pub fn remove_inactive_peers(&mut self, current_cutoff: DurationSinceUnixEpoch) { + self.peers + .retain(|_, peer| peer::ReadInfo::get_updated(peer) > current_cutoff); } #[must_use] - pub fn seeders_and_leechers(&self) -> (usize, usize) { - let seeders = self.peers.values().filter(|peer| peer.is_seeder()).count(); - let leechers = self.len() - seeders; - - (seeders, leechers) + pub fn get(&self, peer_id: &peer::Id) -> Option<&Arc> { + self.peers.get(peer_id) } #[must_use] - pub fn get_peers(&self, limit: Option) -> Vec> { + pub fn get_all(&self, limit: Option) -> Vec> { match limit { Some(limit) => self.peers.values().take(limit).cloned().collect(), None => self.peers.values().cloned().collect(), @@ -51,13 +52,21 @@ impl PeerList { } #[must_use] - pub fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { + pub fn seeders_and_leechers(&self) -> (usize, usize) { + let seeders = self.peers.values().filter(|peer| peer.is_seeder()).count(); + let leechers = self.len() - seeders; + + (seeders, leechers) + } + + #[must_use] + pub fn get_peers_excluding_addr(&self, peer_addr: &SocketAddr, limit: Option) -> Vec> { match limit { Some(limit) => self .peers .values() // Take peers which are not the client peer - .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) + .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *peer_addr) // Limit the number of peers on the result .take(limit) .cloned() @@ -66,9 +75,215 @@ impl PeerList { .peers .values() // Take peers which are not the client peer - .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *client) + .filter(|peer| peer::ReadInfo::get_address(peer.as_ref()) != *peer_addr) .cloned() .collect(), } } } + +#[cfg(test)] +mod tests { + + mod it_should { + use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + use std::sync::Arc; + + use torrust_tracker_primitives::peer::fixture::PeerBuilder; + use torrust_tracker_primitives::peer::{self}; + use torrust_tracker_primitives::DurationSinceUnixEpoch; + + use crate::entry::peer_list::PeerList; + + #[test] + fn be_empty_when_no_peers_have_been_inserted() { + let peer_list = PeerList::default(); + + assert!(peer_list.is_empty()); + } + + #[test] + fn have_zero_length_when_no_peers_have_been_inserted() { + let peer_list = PeerList::default(); + + assert_eq!(peer_list.len(), 0); + } + + #[test] + fn allow_inserting_a_new_peer() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + assert_eq!(peer_list.upsert(peer.into()), None); + } + + #[test] + fn allow_updating_a_preexisting_peer() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + peer_list.upsert(peer.into()); + + assert_eq!(peer_list.upsert(peer.into()), Some(Arc::new(peer))); + } + + #[test] + fn allow_getting_all_peers() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + peer_list.upsert(peer.into()); + + assert_eq!(peer_list.get_all(None), [Arc::new(peer)]); + } + + #[test] + fn allow_getting_one_peer_by_id() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + peer_list.upsert(peer.into()); + + assert_eq!(peer_list.get(&peer.peer_id), Some(Arc::new(peer)).as_ref()); + } + + #[test] + fn increase_the_number_of_peers_after_inserting_a_new_one() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + peer_list.upsert(peer.into()); + + assert_eq!(peer_list.len(), 1); + } + + #[test] + fn decrease_the_number_of_peers_after_removing_one() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + peer_list.upsert(peer.into()); + + peer_list.remove(&peer.peer_id); + + assert!(peer_list.is_empty()); + } + + #[test] + fn allow_removing_an_existing_peer() { + let mut peer_list = PeerList::default(); + + let peer = PeerBuilder::default().build(); + + peer_list.upsert(peer.into()); + + peer_list.remove(&peer.peer_id); + + assert_eq!(peer_list.get(&peer.peer_id), None); + } + + #[test] + fn allow_getting_all_peers_excluding_peers_with_a_given_address() { + let mut peer_list = PeerList::default(); + + let peer1 = PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .with_peer_addr(&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 6969)) + .build(); + peer_list.upsert(peer1.into()); + + let peer2 = PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000002")) + .with_peer_addr(&SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 6969)) + .build(); + peer_list.upsert(peer2.into()); + + assert_eq!(peer_list.get_peers_excluding_addr(&peer2.peer_addr, None), [Arc::new(peer1)]); + } + + #[test] + fn return_the_number_of_seeders_in_the_list() { + let mut peer_list = PeerList::default(); + + let seeder = PeerBuilder::seeder().build(); + let leecher = PeerBuilder::leecher().build(); + + peer_list.upsert(seeder.into()); + peer_list.upsert(leecher.into()); + + let (seeders, _leechers) = peer_list.seeders_and_leechers(); + + assert_eq!(seeders, 1); + } + + #[test] + fn return_the_number_of_leechers_in_the_list() { + let mut peer_list = PeerList::default(); + + let seeder = PeerBuilder::seeder().build(); + let leecher = PeerBuilder::leecher().build(); + + peer_list.upsert(seeder.into()); + peer_list.upsert(leecher.into()); + + let (_seeders, leechers) = peer_list.seeders_and_leechers(); + + assert_eq!(leechers, 1); + } + + #[test] + fn remove_inactive_peers() { + let mut peer_list = PeerList::default(); + let one_second = DurationSinceUnixEpoch::new(1, 0); + + // Insert the peer + let last_update_time = DurationSinceUnixEpoch::new(1_669_397_478_934, 0); + let peer = PeerBuilder::default().last_updated_on(last_update_time).build(); + peer_list.upsert(peer.into()); + + // Remove peers not updated since one second after inserting the peer + peer_list.remove_inactive_peers(last_update_time + one_second); + + assert_eq!(peer_list.len(), 0); + } + + #[test] + fn not_remove_active_peers() { + let mut peer_list = PeerList::default(); + let one_second = DurationSinceUnixEpoch::new(1, 0); + + // Insert the peer + let last_update_time = DurationSinceUnixEpoch::new(1_669_397_478_934, 0); + let peer = PeerBuilder::default().last_updated_on(last_update_time).build(); + peer_list.upsert(peer.into()); + + // Remove peers not updated since one second before inserting the peer. + peer_list.remove_inactive_peers(last_update_time - one_second); + + assert_eq!(peer_list.len(), 1); + } + + #[test] + fn allow_inserting_two_identical_peers_except_for_the_id() { + let mut peer_list = PeerList::default(); + + let peer1 = PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000001")) + .build(); + peer_list.upsert(peer1.into()); + + let peer2 = PeerBuilder::default() + .with_peer_id(&peer::Id(*b"-qB00000000000000002")) + .build(); + peer_list.upsert(peer2.into()); + + assert_eq!(peer_list.len(), 2); + } + } +} diff --git a/packages/torrent-repository/src/entry/single.rs b/packages/torrent-repository/src/entry/single.rs index 169ee2fb..a0112445 100644 --- a/packages/torrent-repository/src/entry/single.rs +++ b/packages/torrent-repository/src/entry/single.rs @@ -43,11 +43,11 @@ impl Entry for EntrySingle { } fn get_peers(&self, limit: Option) -> Vec> { - self.swarm.get_peers(limit) + self.swarm.get_all(limit) } fn get_peers_for_client(&self, client: &SocketAddr, limit: Option) -> Vec> { - self.swarm.get_peers_for_client(client, limit) + self.swarm.get_peers_excluding_addr(client, limit) } fn upsert_peer(&mut self, peer: &peer::Peer) -> bool { @@ -58,7 +58,7 @@ impl Entry for EntrySingle { drop(self.swarm.remove(&peer::ReadInfo::get_id(peer))); } AnnounceEvent::Completed => { - let previous = self.swarm.insert(peer::ReadInfo::get_id(peer), Arc::new(*peer)); + let previous = self.swarm.upsert(Arc::new(*peer)); // Don't count if peer was not previously known and not already completed. if previous.is_some_and(|p| p.event != AnnounceEvent::Completed) { self.downloaded += 1; @@ -66,7 +66,7 @@ impl Entry for EntrySingle { } } _ => { - drop(self.swarm.insert(peer::ReadInfo::get_id(peer), Arc::new(*peer))); + drop(self.swarm.upsert(Arc::new(*peer))); } } @@ -74,7 +74,6 @@ impl Entry for EntrySingle { } fn remove_inactive_peers(&mut self, current_cutoff: DurationSinceUnixEpoch) { - self.swarm - .retain(|_, peer| peer::ReadInfo::get_updated(peer) > current_cutoff); + self.swarm.remove_inactive_peers(current_cutoff); } }