summaryrefslogtreecommitdiff
path: root/src/ot_clean.c
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-11-07 03:55:27 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-11-07 03:55:27 +0100
commitbbfd674e08c6b1fa4081f9c678fd220bead749d7 (patch)
tree41c279103efda2765217a26c8164817d3db96606 /src/ot_clean.c
parentf18339a50eed09ed47b2b22212d2a50e543e9b09 (diff)
Start to opentracker's memory requirements
* peer lists for v4 and v6 are now lazily allocated and, more importantly, will be freed once there are no more peers * The downloaded count is now per torrent and not per peer list anymore, moving in what was alignment loss, anyway * The (now) per torrent downloaded and the per peer list peer and seed count shrunk from size_t to uint32_t * A helper guards accesses to the peer and seed count to prevent null pointer dereferences * The base time also shrank from time_t to uint32_t, minutes since the epoch currently fits in 25 bits
Diffstat (limited to 'src/ot_clean.c')
-rw-r--r--src/ot_clean.c77
1 files changed, 48 insertions, 29 deletions
diff --git a/src/ot_clean.c b/src/ot_clean.c
index eaf069a..77cb4ba 100644
--- a/src/ot_clean.c
+++ b/src/ot_clean.c
@@ -49,26 +49,17 @@ static ssize_t clean_single_bucket(ot_peer *peers, size_t peer_count, size_t pee
49 return (peers - insert_point) / peer_size; 49 return (peers - insert_point) / peer_size;
50} 50}
51 51
52int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) { 52/* Age one family's peers by timedout minutes. Frees the list and clears the
53 ot_vector *peer_vector = &peer_list->peers; 53 slot once its last peer is gone, so an absent family costs nothing. */
54 ot_time timedout = time_since_minutes(peer_list->base); 54static void clean_peer_list_family(ot_peerlist **slot, size_t peer_size, ot_time timedout) {
55 size_t num_buckets = 1, removed_seeders = 0; 55 ot_peerlist *peer_list = *slot;
56 ot_vector *peer_vector;
57 size_t num_buckets = 1, removed_seeders = 0;
56 58
57 /* No need to clean empty torrent */ 59 if (!peer_list)
58 if (!timedout) 60 return;
59 return 0;
60
61 /* Torrent has idled out */
62 if (timedout > OT_TORRENT_TIMEOUT)
63 return 1;
64
65 /* Nothing to be cleaned here? Test if torrent is worth keeping */
66 if (timedout > OT_PEER_TIMEOUT) {
67 if (!peer_list->peer_count)
68 return peer_list->down_count ? 0 : 1;
69 timedout = OT_PEER_TIMEOUT;
70 }
71 61
62 peer_vector = &peer_list->peers;
72 if (OT_PEERLIST_HASBUCKETS(peer_list)) { 63 if (OT_PEERLIST_HASBUCKETS(peer_list)) {
73 num_buckets = peer_vector->size; 64 num_buckets = peer_vector->size;
74 peer_vector = (ot_vector *)peer_vector->data; 65 peer_vector = (ot_vector *)peer_vector->data;
@@ -87,25 +78,53 @@ int clean_single_peer_list(ot_peerlist *peer_list, size_t peer_size) {
87 78
88 peer_list->seed_count -= removed_seeders; 79 peer_list->seed_count -= removed_seeders;
89 80
90 /* See if we need to convert a torrent from simple vector to bucket list */ 81 if (!peer_list->peer_count) {
82 free_peerlist(peer_list);
83 *slot = NULL;
84 return;
85 }
86
87 /* See if we need to convert the list from simple vector to bucket list */
91 if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list)) 88 if ((peer_list->peer_count > OT_PEER_BUCKET_MINCOUNT) || OT_PEERLIST_HASBUCKETS(peer_list))
92 vector_redistribute_buckets(peer_list, peer_size); 89 vector_redistribute_buckets(peer_list, peer_size);
93
94 if (peer_list->peer_count)
95 peer_list->base = time_now_minutes();
96 else {
97 /* When we got here, the last time that torrent
98 has been touched is OT_PEER_TIMEOUT Minutes before */
99 peer_list->base = time_now_minutes() - OT_PEER_TIMEOUT;
100 }
101 return 0;
102} 90}
103 91
104/* Clean a single torrent 92/* Clean a single torrent
105 return 1 if torrent timed out 93 return 1 if torrent timed out
106*/ 94*/
107int clean_single_torrent(ot_torrent *torrent) { 95int clean_single_torrent(ot_torrent *torrent) {
108 return clean_single_peer_list(torrent->peer_list6, OT_PEER_SIZE6) * clean_single_peer_list(torrent->peer_list4, OT_PEER_SIZE4); 96 ot_time timedout = time_since_minutes(torrent->base);
97
98 /* Touched since the last sweep: nothing to do */
99 if (!timedout)
100 return 0;
101
102 /* Torrent has idled out */
103 if (timedout > OT_TORRENT_TIMEOUT)
104 return 1;
105
106 /* Already empty and nothing arrived before the peer timeout: keep it only
107 while a down count is worth remembering */
108 if (timedout > OT_PEER_TIMEOUT && !torrent->peer_list6 && !torrent->peer_list4)
109 return torrent->down_count ? 0 : 1;
110
111 /* Peers past the peer timeout are gone regardless, which caps how far the
112 lists are aged in this pass */
113 if (timedout > OT_PEER_TIMEOUT)
114 timedout = OT_PEER_TIMEOUT;
115
116 clean_peer_list_family(&torrent->peer_list6, OT_PEER_SIZE6, timedout);
117 clean_peer_list_family(&torrent->peer_list4, OT_PEER_SIZE4, timedout);
118
119 if (torrent->peer_list6 || torrent->peer_list4)
120 torrent->base = time_now_minutes(); /* still carrying peers */
121 else {
122 /* Fell empty: hold base a peer timeout back so a later idle sweep makes
123 the keep-or-drop decision above */
124 ot_time now = time_now_minutes();
125 torrent->base = now > OT_PEER_TIMEOUT ? (uint32_t)(now - OT_PEER_TIMEOUT) : 0;
126 }
127 return 0;
109} 128}
110 129
111/* Written to once, by clean_deinit, and never read: the byte stays in and 130/* Written to once, by clean_deinit, and never read: the byte stays in and