From 589cb500fa5a6df13fa9634d0071922ec11fce17 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Sat, 7 Nov 2026 19:39:01 +0100 Subject: 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. --- src/trackerlogic.h | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'src/trackerlogic.h') diff --git a/src/trackerlogic.h b/src/trackerlogic.h index c4b7774..dd8a48c 100644 --- a/src/trackerlogic.h +++ b/src/trackerlogic.h @@ -170,26 +170,40 @@ struct ot_peerlist; typedef struct ot_peerlist ot_peerlist; typedef struct { ot_hash hash; - ot_peerlist *peer_list6; /* NULL until the torrent has a v6 peer */ - ot_peerlist *peer_list4; /* NULL until the torrent has a v4 peer */ - uint32_t base; /* minutes, when the torrent was last cleaned */ - uint32_t down_count; /* completed events, summed over both families */ + ot_peerlist *peer_list; /* NULL until the torrent has a peer in either family */ + uint32_t base; /* epoch minutes, when the torrent was last cleaned */ + uint32_t down_count; /* completed events */ } ot_torrent; #include "ot_vector.h" struct ot_peerlist { uint32_t seed_count; - uint32_t peer_count; - /* normal peers vector or - pointer to ot_vector[32] buckets if data != NULL and space == 0 - */ - ot_vector peers; + /* each family's peers: a normal vector, or a pointer to ot_vector[] buckets + when data != NULL and space == 0 (size then holds the bucket count) */ + ot_vector peers6; + ot_vector peers4; }; -#define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space) -static inline uint32_t peerlist_peer_count(const ot_peerlist *peer_list) { return peer_list ? peer_list->peer_count : 0; } -static inline uint32_t peerlist_seed_count(const ot_peerlist *peer_list) { return peer_list ? peer_list->seed_count : 0; } +/* A peer vector becomes a bucket list of peer vectors, marker is size > space (usually 0) */ +#define OT_VECTOR_HASBUCKETS(v) ((v)->size > (v)->space) + +/* Peers in one family: a plain vector's size is the count, a bucket list's is + the sum of its buckets. O(1) for the small torrents that dominate a table. */ +static inline size_t vector_peer_count(const ot_vector *v) { + const ot_vector *b; + size_t n, total = 0; + if (!OT_VECTOR_HASBUCKETS(v)) + return v->size; + b = (const ot_vector *)v->data; + for (n = 0; n < v->size; ++n) + total += b[n].size; + return total; +} +static inline size_t torrent_peer_count(const ot_torrent *t) { + return t->peer_list ? vector_peer_count(&t->peer_list->peers6) + vector_peer_count(&t->peer_list->peers4) : 0; +} +static inline uint32_t torrent_seed_count(const ot_torrent *t) { return t->peer_list ? t->peer_list->seed_count : 0; } /* The http replies the tracker counts when it has to refuse a request. */ enum { @@ -314,5 +328,6 @@ void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), /* Helper, before it moves to its own object */ void free_peerlist(ot_peerlist *peer_list); +void free_peer_vector(ot_vector *peer_vector); #endif -- cgit v1.3