diff --git a/Cargo.lock b/Cargo.lock index f13ed1482..139a4ca47 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3946,6 +3946,7 @@ dependencies = [ "rand", "reqwest", "ringbuf", + "rustc-hash", "serde", "serde_bencode", "serde_bytes", @@ -4038,6 +4039,7 @@ dependencies = [ "dashmap", "futures", "rstest", + "rustc-hash", "tokio", "torrust-tracker-clock", "torrust-tracker-configuration", diff --git a/Cargo.toml b/Cargo.toml index ef0c39d4b..d8b433d97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ r2d2_sqlite = { version = "0", features = ["bundled"] } rand = "0" reqwest = { version = "0", features = ["json"] } ringbuf = "0" +rustc-hash = "1.1.0" serde = { version = "1", features = ["derive"] } serde_bencode = "0" serde_bytes = "0" diff --git a/cSpell.json b/cSpell.json index 24ef6b0a0..7ea479ebe 100644 --- a/cSpell.json +++ b/cSpell.json @@ -106,6 +106,7 @@ "Pando", "peekable", "peerlist", + "prefixfree", "proot", "proto", "Quickstart", @@ -125,6 +126,7 @@ "routable", "rstest", "rusqlite", + "rustc", "RUSTDOCFLAGS", "RUSTFLAGS", "rustfmt", diff --git a/packages/torrent-repository/Cargo.toml b/packages/torrent-repository/Cargo.toml index 6bc8bfcdd..94aa3df2a 100644 --- a/packages/torrent-repository/Cargo.toml +++ b/packages/torrent-repository/Cargo.toml @@ -19,6 +19,7 @@ version.workspace = true crossbeam-skiplist = "0.1" dashmap = "5.5.3" futures = "0.3.29" +rustc-hash = "1.1.0" tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "signal", "sync"] } torrust-tracker-clock = { version = "3.0.0-alpha.12-develop", path = "../clock" } torrust-tracker-configuration = { version = "3.0.0-alpha.12-develop", path = "../configuration" } diff --git a/packages/torrent-repository/src/entry/mod.rs b/packages/torrent-repository/src/entry/mod.rs index d72ff254b..c04a23530 100644 --- a/packages/torrent-repository/src/entry/mod.rs +++ b/packages/torrent-repository/src/entry/mod.rs @@ -2,7 +2,7 @@ use std::fmt::Debug; use std::net::SocketAddr; use std::sync::Arc; -//use serde::{Deserialize, Serialize}; +use rustc_hash::FxHashMap; use torrust_tracker_configuration::TrackerPolicy; use torrust_tracker_primitives::swarm_metadata::SwarmMetadata; use torrust_tracker_primitives::{peer, DurationSinceUnixEpoch}; @@ -79,11 +79,23 @@ pub trait EntryAsync { /// This is the tracker entry for a given torrent and contains the swarm data, /// that's the list of all the peers trying to download the same torrent. /// The tracker keeps one entry like this for every torrent. -#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Debug, Default, PartialEq, Eq)] 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: FxHashMap>, /// The number of peers that have ever completed downloading the torrent associated to this entry pub(crate) downloaded: u32, } + +impl std::hash::Hash for Torrent { + fn hash(&self, state: &mut H) { + state.write_length_prefix(self.peers.len()); + + for peer in &self.peers { + peer.hash(state); + } + + self.downloaded.hash(state); + } +} diff --git a/packages/torrent-repository/src/lib.rs b/packages/torrent-repository/src/lib.rs index 7a6d209b9..29813c384 100644 --- a/packages/torrent-repository/src/lib.rs +++ b/packages/torrent-repository/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(hasher_prefixfree_extras)] + use std::sync::Arc; use repository::dash_map_mutex_std::XacrimonDashMap; 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 b398b09dc..b981bc711 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,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::sync::Arc; use dashmap::DashMap; @@ -82,7 +82,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 af48428e4..a5a21c4fe 100644 --- a/packages/torrent-repository/src/repository/rw_lock_std.rs +++ b/packages/torrent-repository/src/repository/rw_lock_std.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use torrust_tracker_configuration::TrackerPolicy; use torrust_tracker_primitives::info_hash::InfoHash; @@ -13,7 +13,7 @@ use crate::{EntrySingle, TorrentsRwLockStd}; #[derive(Default, Debug)] pub struct RwLockStd { - pub(crate) torrents: std::sync::RwLock>, + pub(crate) torrents: std::sync::RwLock>, } impl RwLockStd { @@ -22,22 +22,22 @@ impl RwLockStd { /// Panics if unable to get a lock. pub fn write( &self, - ) -> std::sync::RwLockWriteGuard<'_, std::collections::BTreeMap> { + ) -> std::sync::RwLockWriteGuard<'_, std::collections::HashMap> { self.torrents.write().expect("it should get lock") } } impl TorrentsRwLockStd { - fn get_torrents<'a>(&'a self) -> std::sync::RwLockReadGuard<'a, std::collections::BTreeMap> + fn get_torrents<'a>(&'a self) -> std::sync::RwLockReadGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.read().expect("it should get the read lock") } - fn get_torrents_mut<'a>(&'a self) -> std::sync::RwLockWriteGuard<'a, std::collections::BTreeMap> + fn get_torrents_mut<'a>(&'a self) -> std::sync::RwLockWriteGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.write().expect("it should get the write lock") } @@ -102,7 +102,7 @@ where } let entry = EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 74cdc4475..f0ff2f3ca 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,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::sync::Arc; use torrust_tracker_configuration::TrackerPolicy; @@ -13,16 +13,16 @@ use crate::entry::{Entry, EntrySync}; use crate::{EntryMutexStd, EntrySingle, TorrentsRwLockStdMutexStd}; impl TorrentsRwLockStdMutexStd { - fn get_torrents<'a>(&'a self) -> std::sync::RwLockReadGuard<'a, std::collections::BTreeMap> + fn get_torrents<'a>(&'a self) -> std::sync::RwLockReadGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.read().expect("unable to get torrent list") } - fn get_torrents_mut<'a>(&'a self) -> std::sync::RwLockWriteGuard<'a, std::collections::BTreeMap> + fn get_torrents_mut<'a>(&'a self) -> std::sync::RwLockWriteGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.write().expect("unable to get writable torrent list") } @@ -97,7 +97,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 83ac02c91..07ca8bde8 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,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::iter::zip; use std::pin::Pin; use std::sync::Arc; @@ -17,16 +17,16 @@ use crate::entry::{Entry, EntryAsync}; use crate::{EntryMutexTokio, EntrySingle, TorrentsRwLockStdMutexTokio}; impl TorrentsRwLockStdMutexTokio { - fn get_torrents<'a>(&'a self) -> std::sync::RwLockReadGuard<'a, std::collections::BTreeMap> + fn get_torrents<'a>(&'a self) -> std::sync::RwLockReadGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.read().expect("unable to get torrent list") } - fn get_torrents_mut<'a>(&'a self) -> std::sync::RwLockWriteGuard<'a, std::collections::BTreeMap> + fn get_torrents_mut<'a>(&'a self) -> std::sync::RwLockWriteGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.write().expect("unable to get writable torrent list") } @@ -106,7 +106,7 @@ where let entry = EntryMutexTokio::new( EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 b95f1e31e..fcdd5c76d 100644 --- a/packages/torrent-repository/src/repository/rw_lock_tokio.rs +++ b/packages/torrent-repository/src/repository/rw_lock_tokio.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use torrust_tracker_configuration::TrackerPolicy; use torrust_tracker_primitives::info_hash::InfoHash; @@ -13,7 +13,7 @@ use crate::{EntrySingle, TorrentsRwLockTokio}; #[derive(Default, Debug)] pub struct RwLockTokio { - pub(crate) torrents: tokio::sync::RwLock>, + pub(crate) torrents: tokio::sync::RwLock>, } impl RwLockTokio { @@ -22,7 +22,7 @@ impl RwLockTokio { ) -> impl std::future::Future< Output = tokio::sync::RwLockWriteGuard< '_, - std::collections::BTreeMap, + std::collections::HashMap, >, > { self.torrents.write() @@ -30,18 +30,18 @@ impl RwLockTokio { } impl TorrentsRwLockTokio { - async fn get_torrents<'a>(&'a self) -> tokio::sync::RwLockReadGuard<'a, std::collections::BTreeMap> + async fn get_torrents<'a>(&'a self) -> tokio::sync::RwLockReadGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.read().await } async fn get_torrents_mut<'a>( &'a self, - ) -> tokio::sync::RwLockWriteGuard<'a, std::collections::BTreeMap> + ) -> tokio::sync::RwLockWriteGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.write().await } @@ -106,7 +106,7 @@ where } let entry = EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 bde959940..5ced37391 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,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::sync::Arc; use torrust_tracker_configuration::TrackerPolicy; @@ -13,18 +13,18 @@ use crate::entry::{Entry, EntrySync}; use crate::{EntryMutexStd, EntrySingle, TorrentsRwLockTokioMutexStd}; impl TorrentsRwLockTokioMutexStd { - async fn get_torrents<'a>(&'a self) -> tokio::sync::RwLockReadGuard<'a, std::collections::BTreeMap> + async fn get_torrents<'a>(&'a self) -> tokio::sync::RwLockReadGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.read().await } async fn get_torrents_mut<'a>( &'a self, - ) -> tokio::sync::RwLockWriteGuard<'a, std::collections::BTreeMap> + ) -> tokio::sync::RwLockWriteGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.write().await } @@ -97,7 +97,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 1d002e317..e6c11b4ba 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,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::sync::Arc; use torrust_tracker_configuration::TrackerPolicy; @@ -13,18 +13,18 @@ use crate::entry::{Entry, EntryAsync}; use crate::{EntryMutexTokio, EntrySingle, TorrentsRwLockTokioMutexTokio}; impl TorrentsRwLockTokioMutexTokio { - async fn get_torrents<'a>(&'a self) -> tokio::sync::RwLockReadGuard<'a, std::collections::BTreeMap> + async fn get_torrents<'a>(&'a self) -> tokio::sync::RwLockReadGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.read().await } async fn get_torrents_mut<'a>( &'a self, - ) -> tokio::sync::RwLockWriteGuard<'a, std::collections::BTreeMap> + ) -> tokio::sync::RwLockWriteGuard<'a, std::collections::HashMap> where - std::collections::BTreeMap: 'a, + std::collections::HashMap: 'a, { self.torrents.write().await } @@ -100,7 +100,7 @@ where let entry = EntryMutexTokio::new( EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::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 ef3e7e478..b92b6aed2 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,4 @@ -use std::collections::BTreeMap; +use std::collections::HashMap; use std::sync::Arc; use crossbeam_skiplist::SkipMap; @@ -76,7 +76,7 @@ where let entry = EntryMutexStd::new( EntrySingle { - peers: BTreeMap::default(), + peers: HashMap::default(), downloaded: *completed, } .into(), diff --git a/packages/torrent-repository/tests/repository/mod.rs b/packages/torrent-repository/tests/repository/mod.rs index fde34467e..6c5983163 100644 --- a/packages/torrent-repository/tests/repository/mod.rs +++ b/packages/torrent-repository/tests/repository/mod.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashSet}; +use std::collections::{HashMap, HashSet}; use std::hash::{DefaultHasher, Hash, Hasher}; use rstest::{fixture, rstest}; @@ -140,7 +140,7 @@ fn many_out_of_order() -> Entries { #[fixture] fn many_hashed_in_order() -> Entries { - let mut entries: BTreeMap = BTreeMap::default(); + let mut entries: HashMap = HashMap::default(); for i in 0..408 { let mut entry = EntrySingle::default();