Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "torrust-tracker"
version = "2.2.0"
version = "2.2.1"
license = "AGPL-3.0"
authors = ["Mick van Dijke <mick@dutchbits.nl>"]
description = "A feature rich BitTorrent tracker."
Expand Down
1 change: 1 addition & 0 deletions src/torrust_http_tracker/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ impl ScrapeResponse {

#[derive(Serialize)]
pub struct ErrorResponse {
#[serde(rename = "failure reason")]
pub failure_reason: String
}

Expand Down
76 changes: 41 additions & 35 deletions src/tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{Configuration, database, key_manager, MAX_SCRAPE_TORRENTS};
use std::collections::btree_map::Entry;
use std::sync::Arc;
use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes};
use log::{debug};
use log::info;
use crate::key_manager::AuthKey;
use crate::database::{Database, DatabaseDrivers};
use crate::key_manager::Error::KeyInvalid;
Expand Down Expand Up @@ -456,47 +456,53 @@ impl TorrentTracker {
self.stats.read().await
}

// remove torrents without peers
// remove torrents without peers if enabled, and defragment memory
pub async fn cleanup_torrents(&self) {
debug!("Cleaning torrents..");
let mut lock = self.torrents.write().await;
let db: &mut BTreeMap<InfoHash, TorrentEntry> = &mut *lock;
let mut torrents_to_remove = Vec::new();

for (k, torrent_entry) in db.iter_mut() {
// timed-out peers..
{
let mut peers_to_remove = Vec::new();
let torrent_peers = &mut torrent_entry.peers;

for (peer_id, peer) in torrent_peers.iter() {
if peer.is_seeder() {
if peer.updated.elapsed() > std::time::Duration::from_secs(self.config.peer_timeout as u64) {
// remove seeders after 5 minutes since last update...
peers_to_remove.push(peer_id.clone());
torrent_entry.seeders -= 1;
}
} else if peer.updated.elapsed() > std::time::Duration::from_secs(self.config.peer_timeout as u64) {
// remove peers after 2 hours since last update...
peers_to_remove.push(peer_id.clone());
}
}
info!("Cleaning torrents...");
let lock = self.torrents.write().await;

// First we create a mapping of all the torrent hashes in a vector, and we use this to iterate through the btreemap.
// Every hash we have handled, we remove from the btreemap completely, and push it to the top.
let mut torrent_hashes: Vec<InfoHash> = Vec::new();
for (k, _torrent_entry) in lock.iter() {
torrent_hashes.push(k.clone());
}

drop(lock);

// Let's iterate through all torrents, and parse.
for hash in torrent_hashes.iter() {
let mut torrent = TorrentEntry{
peers: BTreeMap::new(),
completed: 0,
seeders: 0
};

for peer_id in peers_to_remove.iter() {
torrent_peers.remove(peer_id);
let lock = self.torrents.write().await;
let torrent_data = lock.get(hash).unwrap().clone();
drop(lock);

torrent.completed = torrent_data.completed.clone();
for (peer_id, peer) in torrent_data.peers.iter() {
if peer.updated.elapsed() > std::time::Duration::from_secs(self.config.peer_timeout as u64) {
continue;
}
torrent.peers.insert(peer_id.clone(), peer.clone());
if peer.is_seeder() {
torrent.seeders += 1;
}
}

let mut lock = self.torrents.write().await;
lock.remove(hash);
if self.config.mode.clone() == TrackerMode::PublicMode && self.config.cleanup_peerless && !self.config.persistence {
// peer-less torrents..
if torrent_entry.peers.len() == 0 {
torrents_to_remove.push(k.clone());
if torrent.peers.len() != 0 {
lock.insert(hash.clone(), torrent);
}
} else {
lock.insert(hash.clone(), torrent);
}
drop(lock);
}

for info_hash in torrents_to_remove {
db.remove(&info_hash);
}
info!("Torrents cleaned up.");
}
}