Let our fullscrapes have a binary content-type
[opentracker.git] / ot_clean.c
blob291b847e66cf77f9537b10d1840d2f03d42eb460
1 /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
4 $id$ */
6 /* System */
7 #include <pthread.h>
8 #include <string.h>
9 #include <unistd.h>
11 /* Libowfat */
12 #include "io.h"
14 /* Opentracker */
15 #include "ot_accesslist.h"
16 #include "ot_clean.h"
17 #include "ot_mutex.h"
18 #include "ot_stats.h"
19 #include "ot_vector.h"
20 #include "trackerlogic.h"
22 /* Returns amount of removed peers */
23 static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t peer_size, time_t timedout, int *removed_seeders) {
24 ot_peer *last_peer = peers + peer_count * peer_size, *insert_point;
26 /* Two scan modes: unless there is one peer removed, just increase ot_peertime */
27 while (peers < last_peer) {
28 time_t timediff = timedout + OT_PEERTIME(peers, peer_size);
29 if (timediff >= OT_PEER_TIMEOUT)
30 break;
31 OT_PEERTIME(peers, peer_size) = timediff;
32 peers += peer_size;
35 /* If we at least remove one peer, we have to copy */
36 for (insert_point = peers; peers < last_peer; peers += peer_size) {
37 time_t timediff = timedout + OT_PEERTIME(peers, peer_size);
39 if (timediff < OT_PEER_TIMEOUT) {
40 OT_PEERTIME(peers, peer_size) = timediff;
41 memcpy(insert_point, peers, peer_size);
42 insert_point += peer_size;
43 } else if (OT_PEERFLAG_D(peers, peer_size) & PEER_FLAG_SEEDING)
44 (*removed_seeders)++;
47 return (peers - insert_point) / peer_size;
50 int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) {
51 ot_vector *peer_vector = &peer_list->peers;
52 time_t timedout = (time_t)(g_now_minutes - peer_list->base);
53 int num_buckets = 1, removed_seeders = 0;
55 /* No need to clean empty torrent */
56 if (!timedout)
57 return 0;
59 /* Torrent has idled out */
60 if (timedout > OT_TORRENT_TIMEOUT)
61 return 1;
63 /* Nothing to be cleaned here? Test if torrent is worth keeping */
64 if (timedout > OT_PEER_TIMEOUT) {
65 if (!peer_list->peer_count)
66 return peer_list->down_count ? 0 : 1;
67 timedout = OT_PEER_TIMEOUT;
70 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
71 num_buckets = peer_vector->size;
72 peer_vector = (ot_vector *)peer_vector->data;
75 while (num_buckets--) {
76 size_t removed_peers = clean_single_bucket(peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders);
77 peer_list->peer_count -= removed_peers;
78 peer_vector->size -= removed_peers;
79 if (removed_peers)
80 vector_fixup_peers(peer_vector, peer_size);
82 /* Skip to next bucket, a vector containing peers */
83 ++peer_vector;
86 peer_list->seed_count -= removed_seeders;
88 /* See if we need to convert a torrent from simple vector to bucket list */
89 if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list))
90 vector_redistribute_buckets(peer_list, peer_size);
92 if (peer_list->peer_count)
93 peer_list->base = g_now_minutes;
94 else {
95 /* When we got here, the last time that torrent
96 has been touched is OT_PEER_TIMEOUT Minutes before */
97 peer_list->base = g_now_minutes - OT_PEER_TIMEOUT;
99 return 0;
102 /* Clean a single torrent
103 return 1 if torrent timed out
105 int clean_single_torrent(ot_torrent *torrent) {
106 return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4);
109 /* Clean up all peers in current bucket, remove timedout pools and
110 torrents */
111 static void *clean_worker(void *args) {
112 (void)args;
113 while (1) {
114 int bucket = OT_BUCKET_COUNT;
115 while (bucket--) {
116 ot_vector *torrents_list = mutex_bucket_lock(bucket);
117 size_t toffs;
118 int delta_torrentcount = 0;
120 for (toffs = 0; toffs < torrents_list->size; ++toffs) {
121 ot_torrent *torrent = ((ot_torrent *)(torrents_list->data)) + toffs;
122 if (clean_single_torrent(torrent)) {
123 vector_remove_torrent(torrents_list, torrent);
124 --delta_torrentcount;
125 --toffs;
128 mutex_bucket_unlock(bucket, delta_torrentcount);
129 if (!g_opentracker_running)
130 return NULL;
131 usleep(OT_CLEAN_SLEEP);
133 stats_cleanup();
134 #ifdef WANT_ACCESSLIST
135 accesslist_cleanup();
136 #endif
138 return NULL;
141 static pthread_t thread_id;
142 void clean_init(void) { pthread_create(&thread_id, NULL, clean_worker, NULL); }
144 void clean_deinit(void) { pthread_cancel(thread_id); }