1 /* This software was written by Dirk Engling <erdgeist@erdgeist.org>
2 It is considered beerware. Prost. Skol. Cheers or whatever.
15 #include "ot_accesslist.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
)
31 OT_PEERTIME(peers
, peer_size
) = timediff
;
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
)
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 */
59 /* Torrent has idled out */
60 if (timedout
> OT_TORRENT_TIMEOUT
)
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
;
80 vector_fixup_peers(peer_vector
, peer_size
);
82 /* Skip to next bucket, a vector containing peers */
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
;
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
;
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
111 static void *clean_worker(void *args
) {
114 int bucket
= OT_BUCKET_COUNT
;
116 ot_vector
*torrents_list
= mutex_bucket_lock(bucket
);
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
;
128 mutex_bucket_unlock(bucket
, delta_torrentcount
);
129 if (!g_opentracker_running
)
131 usleep(OT_CLEAN_SLEEP
);
134 #ifdef WANT_ACCESSLIST
135 accesslist_cleanup();
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
); }