summaryrefslogtreecommitdiff
path: root/src/ot_clean.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ot_clean.c')
-rw-r--r--src/ot_clean.c64
1 files changed, 35 insertions, 29 deletions
diff --git a/src/ot_clean.c b/src/ot_clean.c
index 9e2186f..130bd2a 100644
--- a/src/ot_clean.c
+++ b/src/ot_clean.c
@@ -51,51 +51,48 @@ static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t pee
51 return (peers - insert_point) / peer_size; 51 return (peers - insert_point) / peer_size;
52} 52}
53 53
54/* Age one family's peers by timedout minutes. Frees the list and clears the 54/* Age one family's peers by timedout minutes. Releases and zeroes the vector
55 slot once its last peer is gone, so an absent family costs nothing. */ 55 once its last peer is gone, so an empty family costs nothing. */
56static void clean_peer_list_family(ot_peerlist **slot, size_t peer_size, ot_time timedout) { 56static void clean_family_vector(ot_vector *peer_vector, size_t peer_size, ot_time timedout, size_t *removed_seeders) {
57 ot_peerlist *peer_list = *slot; 57 ot_vector *bucket = peer_vector;
58 ot_vector *peer_vector; 58 size_t num_buckets = 1, peer_count;
59 size_t num_buckets = 1, removed_seeders = 0;
60 59
61 if (!peer_list) 60 if (OT_VECTOR_HASBUCKETS(peer_vector)) {
62 return;
63
64 peer_vector = &peer_list->peers;
65 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
66 num_buckets = peer_vector->size; 61 num_buckets = peer_vector->size;
67 peer_vector = (ot_vector *)peer_vector->data; 62 bucket = (ot_vector *)peer_vector->data;
68 } 63 }
69 64
70 while (num_buckets--) { 65 while (num_buckets--) {
71 size_t removed_peers = clean_single_bucket(peer_vector->data, peer_vector->size, peer_size, timedout, &removed_seeders); 66 size_t removed_peers = clean_single_bucket(bucket->data, bucket->size, peer_size, timedout, removed_seeders);
72 peer_list->peer_count -= removed_peers; 67 bucket->size -= removed_peers;
73 peer_vector->size -= removed_peers;
74 if (removed_peers) 68 if (removed_peers)
75 vector_fixup_peers(peer_vector, peer_size); 69 vector_fixup_peers(bucket, peer_size);
76 70
77 /* Skip to next bucket, a vector containing peers */ 71 /* Skip to next bucket, a vector containing peers */
78 ++peer_vector; 72 ++bucket;
79 } 73 }
80 74
81 peer_list->seed_count -= removed_seeders; 75 peer_count = vector_peer_count(peer_vector);
82 76
83 if (!peer_list->peer_count) { 77 /* Run dry: release the family (a collapsed bucket list or a plain vector) */
84 free_peerlist(peer_list); 78 if (!peer_count) {
85 *slot = NULL; 79 free_peer_vector(peer_vector);
80 memset(peer_vector, 0, sizeof(*peer_vector));
86 return; 81 return;
87 } 82 }
88 83
89 /* See if we need to convert the list from simple vector to bucket list */ 84 /* See if we need to convert the vector from simple to bucket list or back */
90 if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list)) 85 if ((peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_VECTOR_HASBUCKETS(peer_vector))
91 vector_redistribute_buckets(peer_list, peer_size); 86 vector_redistribute_buckets(peer_vector, peer_size, peer_count);
92} 87}
93 88
94/* Clean a single torrent 89/* Clean a single torrent
95 return 1 if torrent timed out 90 return 1 if torrent timed out
96*/ 91*/
97int clean_single_torrent(ot_torrent *torrent) { 92int clean_single_torrent(ot_torrent *torrent) {
98 ot_time timedout = time_since_minutes(torrent->base); 93 ot_time timedout = time_since_minutes(torrent->base);
94 ot_peerlist *peer_list = torrent->peer_list;
95 size_t removed_seeders = 0;
99 96
100 /* Touched since the last sweep: nothing to do */ 97 /* Touched since the last sweep: nothing to do */
101 if (!timedout) 98 if (!timedout)
@@ -107,7 +104,7 @@ int clean_single_torrent(ot_torrent *torrent) {
107 104
108 /* Already empty and nothing arrived before the peer timeout: keep it only 105 /* Already empty and nothing arrived before the peer timeout: keep it only
109 while a down count is worth remembering */ 106 while a down count is worth remembering */
110 if (timedout > OT_PEER_TIMEOUT && !torrent->peer_list6 && !torrent->peer_list4) 107 if (timedout > OT_PEER_TIMEOUT && !peer_list)
111 return (torrent->down_count && timedout <= g_empty_torrent_timeout) ? 0 : 1; 108 return (torrent->down_count && timedout <= g_empty_torrent_timeout) ? 0 : 1;
112 109
113 /* Peers past the peer timeout are gone regardless, which caps how far the 110 /* Peers past the peer timeout are gone regardless, which caps how far the
@@ -115,10 +112,19 @@ int clean_single_torrent(ot_torrent *torrent) {
115 if (timedout > OT_PEER_TIMEOUT) 112 if (timedout > OT_PEER_TIMEOUT)
116 timedout = OT_PEER_TIMEOUT; 113 timedout = OT_PEER_TIMEOUT;
117 114
118 clean_peer_list_family(&torrent->peer_list6, OT_PEER_SIZE6, timedout); 115 if (peer_list) {
119 clean_peer_list_family(&torrent->peer_list4, OT_PEER_SIZE4, timedout); 116 clean_family_vector(&peer_list->peers6, OT_PEER_SIZE6, timedout, &removed_seeders);
117 clean_family_vector(&peer_list->peers4, OT_PEER_SIZE4, timedout, &removed_seeders);
118 peer_list->seed_count -= removed_seeders;
119
120 /* Both families gone: drop the peerlist, the torrent keeps only its count */
121 if (!vector_peer_count(&peer_list->peers6) && !vector_peer_count(&peer_list->peers4)) {
122 free_peerlist(peer_list);
123 torrent->peer_list = peer_list = NULL;
124 }
125 }
120 126
121 if (torrent->peer_list6 || torrent->peer_list4) 127 if (peer_list)
122 torrent->base = time_now_minutes(); /* still carrying peers */ 128 torrent->base = time_now_minutes(); /* still carrying peers */
123 else { 129 else {
124 /* Fell empty: hold base a peer timeout back so a later idle sweep makes 130 /* Fell empty: hold base a peer timeout back so a later idle sweep makes