diff options
| author | Dirk Engling <erdgeist@erdgeist.org> | 2026-11-07 03:55:27 +0100 |
|---|---|---|
| committer | Dirk Engling <erdgeist@erdgeist.org> | 2026-11-07 03:55:27 +0100 |
| commit | bbfd674e08c6b1fa4081f9c678fd220bead749d7 (patch) | |
| tree | 41c279103efda2765217a26c8164817d3db96606 /src/ot_clean.c | |
| parent | f18339a50eed09ed47b2b22212d2a50e543e9b09 (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.c | 77 |
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 | ||
| 52 | int 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); | 54 | static 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 | */ |
| 107 | int clean_single_torrent(ot_torrent *torrent) { | 95 | int 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 |
