summaryrefslogtreecommitdiff
path: root/src/ot_vector.c
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-11-07 19:39:01 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-11-07 19:39:01 +0100
commit589cb500fa5a6df13fa9634d0071922ec11fce17 (patch)
treefa5fc07d6d13d7b241d884441d3d22c1d0189d87 /src/ot_vector.c
parent1e7248b330bde4c70528ccf91535391e19294dc3 (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.c47
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
183void vector_redistribute_buckets(ot_peerlist *peer_list, size_t peer_size) { 182void 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}