mirror of git://erdgeist.org/opentracker
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.3 KiB
144 lines
4.3 KiB
/* This software was written by Dirk Engling <erdgeist@erdgeist.org> |
|
It is considered beerware. Prost. Skol. Cheers or whatever. |
|
|
|
$id$ */ |
|
|
|
/* System */ |
|
#include <pthread.h> |
|
#include <string.h> |
|
#include <unistd.h> |
|
|
|
/* Libowfat */ |
|
#include "io.h" |
|
|
|
/* Opentracker */ |
|
#include "ot_accesslist.h" |
|
#include "ot_clean.h" |
|
#include "ot_mutex.h" |
|
#include "ot_stats.h" |
|
#include "ot_vector.h" |
|
#include "trackerlogic.h" |
|
|
|
/* Returns amount of removed peers */ |
|
static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders) { |
|
ot_peer *last_peer = peers + peer_count * peer_size, *insert_point; |
|
|
|
/* Two scan modes: unless there is one peer removed, just increase ot_peertime */ |
|
while (peers < last_peer) { |
|
time_t timediff = timedout + OT_PEERTIME(peers, peer_size); |
|
if (timediff >= OT_PEER_TIMEOUT) |
|
break; |
|
OT_PEERTIME(peers, peer_size) = timediff; |
|
peers += peer_size; |
|
} |
|
|
|
/* If we at least remove one peer, we have to copy */ |
|
for (insert_point = peers; peers < last_peer; peers += peer_size) { |
|
time_t timediff = timedout + OT_PEERTIME(peers, peer_size); |
|
|
|
if (timediff < OT_PEER_TIMEOUT) { |
|
OT_PEERTIME(peers, peer_size) = timediff; |
|
memcpy(insert_point, peers, peer_size); |
|
insert_point += peer_size; |
|
} else if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING) |
|
(*removed_seeders)++; |
|
} |
|
|
|
return (peers - insert_point) / peer_size; |
|
} |
|
|
|
int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { |
|
ot_vector *peer_vector = &peer_list->peers; |
|
time_t timedout = (time_t)(g_now_minutes - peer_list->base); |
|
int num_buckets = 1, removed_seeders = 0; |
|
|
|
/* No need to clean empty torrent */ |
|
if (!timedout) |
|
return 0; |
|
|
|
/* Torrent has idled out */ |
|
if (timedout > OT_TORRENT_TIMEOUT) |
|
return 1; |
|
|
|
/* Nothing to be cleaned here? Test if torrent is worth keeping */ |
|
if (timedout > OT_PEER_TIMEOUT) { |
|
if (!peer_list->peer_count) |
|
return peer_list->down_count ? 0 : 1; |
|
timedout = OT_PEER_TIMEOUT; |
|
} |
|
|
|
if (OT_PEERLIST_HASBUCKETS(peer_list)) { |
|
num_buckets = peer_vector->size; |
|
peer_vector = (ot_vector *)peer_vector->data; |
|
} |
|
|
|
while (num_buckets--) { |
|
size_t removed_peers = clean_single_bucket(peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders); |
|
peer_list->peer_count -= removed_peers; |
|
peer_vector->size -= removed_peers; |
|
if (removed_peers) |
|
vector_fixup_peers(peer_vector, peer_size); |
|
|
|
/* Skip to next bucket, a vector containing peers */ |
|
++peer_vector; |
|
} |
|
|
|
peer_list->seed_count -= removed_seeders; |
|
|
|
/* See if we need to convert a torrent from simple vector to bucket list */ |
|
if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list)) |
|
vector_redistribute_buckets(peer_list, peer_size); |
|
|
|
if (peer_list->peer_count) |
|
peer_list->base = g_now_minutes; |
|
else { |
|
/* When we got here, the last time that torrent |
|
has been touched is OT_PEER_TIMEOUT Minutes before */ |
|
peer_list->base = g_now_minutes - OT_PEER_TIMEOUT; |
|
} |
|
return 0; |
|
} |
|
|
|
/* Clean a single torrent |
|
return 1 if torrent timed out |
|
*/ |
|
int clean_single_torrent(ot_torrent *torrent) { |
|
return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4); |
|
} |
|
|
|
/* Clean up all peers in current bucket, remove timedout pools and |
|
torrents */ |
|
static void *clean_worker(void *args) { |
|
(void)args; |
|
while (1) { |
|
int bucket = OT_BUCKET_COUNT; |
|
while (bucket--) { |
|
ot_vector *torrents_list = mutex_bucket_lock(bucket); |
|
size_t toffs; |
|
int delta_torrentcount = 0; |
|
|
|
for (toffs = 0; toffs < torrents_list->size; ++toffs) { |
|
ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + toffs; |
|
if (clean_single_torrent(torrent)) { |
|
vector_remove_torrent(torrents_list, torrent); |
|
--delta_torrentcount; |
|
--toffs; |
|
} |
|
} |
|
mutex_bucket_unlock(bucket, delta_torrentcount); |
|
if (!g_opentracker_running) |
|
return NULL; |
|
usleep(OT_CLEAN_SLEEP); |
|
} |
|
stats_cleanup(); |
|
#ifdef WANT_ACCESSLIST |
|
accesslist_cleanup(); |
|
#endif |
|
} |
|
return NULL; |
|
} |
|
|
|
static pthread_t thread_id; |
|
void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); } |
|
|
|
void clean_deinit(void) { pthread_cancel(thread_id); }
|
|
|