diff options
| author | Dirk Engling <erdgeist@erdgeist.org> | 2026-11-07 19:39:01 +0100 |
|---|---|---|
| committer | Dirk Engling <erdgeist@erdgeist.org> | 2026-11-07 19:39:01 +0100 |
| commit | 589cb500fa5a6df13fa9634d0071922ec11fce17 (patch) | |
| tree | fa5fc07d6d13d7b241d884441d3d22c1d0189d87 /src/ot_vector.c | |
| parent | 1e7248b330bde4c70528ccf91535391e19294dc3 (diff) | |
Unify the peerlists for v4 and v6
This commit finishes what started with unifying v4 and v6 trackers, from then on, torrents
carried a peer list per family, with obvious redundancies. With the race to save memory,
these became burdening enough that now these peerlist pointers have been moved into a
single struct, holding both v4 and v6 peers in their respective ot_vectors, so the per-
torrent cost shrunk by another pointer's size.
Each peerlist also lost its peer count cache, as in most cases, it's trivial to load it
directly from the ot_vector's entry count. The seed counts that were kept per family only
to be aggregated later for every consumer, are also merged now.
Total savings depend on the tracker's actual load. In some corner cases, where only one
address family dominates the torrents, we actually use a few bytes more in the ot_vector
for the absent family, but even that mostly becomes noise: before it actually adds to the
memory load, the peer payload will be the deciding factor.
Most wins are on what often is experienced on trackers: A long tail of abandoned torrents
now needs eight fewer bytes, slipping into a smaller allocation unit on glibc's allocator.
Diffstat (limited to 'src/ot_vector.c')
| -rw-r--r-- | src/ot_vector.c | 47 |
1 files changed, 23 insertions, 24 deletions
diff --git a/src/ot_vector.c b/src/ot_vector.c index 23dfb10..ef38919 100644 --- a/src/ot_vector.c +++ b/src/ot_vector.c | |||
| @@ -160,8 +160,7 @@ void vector_remove_torrent(ot_vector *vector, ot_torrent *match) { | |||
| 160 | 160 | ||
| 161 | end = ((ot_torrent *)vector->data) + vector->size; | 161 | end = ((ot_torrent *)vector->data) + vector->size; |
| 162 | 162 | ||
| 163 | free_peerlist(match->peer_list6); | 163 | free_peerlist(match->peer_list); |
| 164 | free_peerlist(match->peer_list4); | ||
| 165 | 164 | ||
| 166 | memmove(match, match + 1, sizeof(ot_torrent) * (end - match - 1)); | 165 | memmove(match, match + 1, sizeof(ot_torrent) * (end - match - 1)); |
| 167 | if ((--vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS)) { | 166 | if ((--vector->size * OT_VECTOR_SHRINK_THRESH < vector->space) && (vector->space >= OT_VECTOR_SHRINK_RATIO * OT_VECTOR_MIN_MEMBERS)) { |
| @@ -180,27 +179,27 @@ void vector_clean_list(ot_vector *vector, size_t num_buckets) { | |||
| 180 | return; | 179 | return; |
| 181 | } | 180 | } |
| 182 | 181 | ||
| 183 | void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) { | 182 | void vector_redistribute_buckets(ot_vector *peer_vector, size_t peer_size, size_t peer_count) { |
| 184 | size_t bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; | 183 | size_t bucket, bucket_size_new, num_buckets_new, num_buckets_old = 1; |
| 185 | ot_vector *bucket_list_new, *bucket_list_old = &peer_list->peers; | 184 | ot_vector *bucket_list_new, *bucket_list_old = peer_vector; |
| 186 | int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4; | 185 | int (*sort_func)(const void *, const void *) = peer_size == OT_PEER_SIZE6 ? &vector_compare_peer6 : &vector_compare_peer4; |
| 187 | 186 | ||
| 188 | if (OT_PEERLIST_HASBUCKETS(peer_list)) { | 187 | if (OT_VECTOR_HASBUCKETS(peer_vector)) { |
| 189 | num_buckets_old = peer_list->peers.size; | 188 | num_buckets_old = peer_vector->size; |
| 190 | bucket_list_old = peer_list->peers.data; | 189 | bucket_list_old = peer_vector->data; |
| 191 | } | 190 | } |
| 192 | 191 | ||
| 193 | if (peer_list->peer_count < 255) | 192 | if (peer_count < 255) |
| 194 | num_buckets_new = 1; | 193 | num_buckets_new = 1; |
| 195 | else if (peer_list->peer_count > 8192) | 194 | else if (peer_count > 8192) |
| 196 | num_buckets_new = 64; | 195 | num_buckets_new = 64; |
| 197 | else if (peer_list->peer_count >= 512 && peer_list->peer_count < 4096) | 196 | else if (peer_count >= 512 && peer_count < 4096) |
| 198 | num_buckets_new = 16; | 197 | num_buckets_new = 16; |
| 199 | else if (peer_list->peer_count < 512 && num_buckets_old <= 16) | 198 | else if (peer_count < 512 && num_buckets_old <= 16) |
| 200 | num_buckets_new = num_buckets_old; | 199 | num_buckets_new = num_buckets_old; |
| 201 | else if (peer_list->peer_count < 512) | 200 | else if (peer_count < 512) |
| 202 | num_buckets_new = 1; | 201 | num_buckets_new = 1; |
| 203 | else if (peer_list->peer_count < 8192 && num_buckets_old > 1) | 202 | else if (peer_count < 8192 && num_buckets_old > 1) |
| 204 | num_buckets_new = num_buckets_old; | 203 | num_buckets_new = num_buckets_old; |
| 205 | else | 204 | else |
| 206 | num_buckets_new = 16; | 205 | num_buckets_new = 16; |
| @@ -214,7 +213,7 @@ void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) { | |||
| 214 | return; | 213 | return; |
| 215 | 214 | ||
| 216 | bucket_size_new = OT_VECTOR_MIN_MEMBERS; | 215 | bucket_size_new = OT_VECTOR_MIN_MEMBERS; |
| 217 | while (bucket_size_new * num_buckets_new < peer_list->peer_count) | 216 | while (bucket_size_new * num_buckets_new < peer_count) |
| 218 | bucket_size_new *= OT_VECTOR_GROW_RATIO; | 217 | bucket_size_new *= OT_VECTOR_GROW_RATIO; |
| 219 | 218 | ||
| 220 | /* preallocate vectors to hold all peers */ | 219 | /* preallocate vectors to hold all peers */ |
| @@ -253,20 +252,20 @@ void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) { | |||
| 253 | for (bucket = 0; bucket < num_buckets_new; ++bucket) | 252 | for (bucket = 0; bucket < num_buckets_new; ++bucket) |
| 254 | qsort(bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func); | 253 | qsort(bucket_list_new[bucket].data, bucket_list_new[bucket].size, peer_size, sort_func); |
| 255 | 254 | ||
| 256 | /* Everything worked fine. Now link new bucket_list to peer_list */ | 255 | /* Everything worked fine. Now link new bucket_list to the vector */ |
| 257 | if (OT_PEERLIST_HASBUCKETS(peer_list)) | 256 | if (OT_VECTOR_HASBUCKETS(peer_vector)) |
| 258 | vector_clean_list((ot_vector *)peer_list->peers.data, peer_list->peers.size); | 257 | vector_clean_list((ot_vector *)peer_vector->data, peer_vector->size); |
| 259 | else | 258 | else |
| 260 | free(peer_list->peers.data); | 259 | free(peer_vector->data); |
| 261 | 260 | ||
| 262 | if (num_buckets_new > 1) { | 261 | if (num_buckets_new > 1) { |
| 263 | peer_list->peers.data = bucket_list_new; | 262 | peer_vector->data = bucket_list_new; |
| 264 | peer_list->peers.size = num_buckets_new; | 263 | peer_vector->size = num_buckets_new; |
| 265 | peer_list->peers.space = 0; /* Magic marker for "is list of buckets" */ | 264 | peer_vector->space = 0; /* Magic marker for "is list of buckets" */ |
| 266 | } else { | 265 | } else { |
| 267 | peer_list->peers.data = bucket_list_new->data; | 266 | peer_vector->data = bucket_list_new->data; |
| 268 | peer_list->peers.size = bucket_list_new->size; | 267 | peer_vector->size = bucket_list_new->size; |
| 269 | peer_list->peers.space = bucket_list_new->space; | 268 | peer_vector->space = bucket_list_new->space; |
| 270 | free(bucket_list_new); | 269 | free(bucket_list_new); |
| 271 | } | 270 | } |
| 272 | } | 271 | } |
