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/trackerlogic.h | |
| 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/trackerlogic.h')
| -rw-r--r-- | src/trackerlogic.h | 39 |
1 files changed, 27 insertions, 12 deletions
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; | |||
| 170 | typedef struct ot_peerlist ot_peerlist; | 170 | typedef struct ot_peerlist ot_peerlist; |
| 171 | typedef struct { | 171 | typedef struct { |
| 172 | ot_hash hash; | 172 | ot_hash hash; |
| 173 | ot_peerlist *peer_list6; /* NULL until the torrent has a v6 peer */ | 173 | ot_peerlist *peer_list; /* NULL until the torrent has a peer in either family */ |
| 174 | ot_peerlist *peer_list4; /* NULL until the torrent has a v4 peer */ | 174 | uint32_t base; /* epoch minutes, when the torrent was last cleaned */ |
| 175 | uint32_t base; /* minutes, when the torrent was last cleaned */ | 175 | uint32_t down_count; /* completed events */ |
| 176 | uint32_t down_count; /* completed events, summed over both families */ | ||
| 177 | } ot_torrent; | 176 | } ot_torrent; |
| 178 | 177 | ||
| 179 | #include "ot_vector.h" | 178 | #include "ot_vector.h" |
| 180 | 179 | ||
| 181 | struct ot_peerlist { | 180 | struct ot_peerlist { |
| 182 | uint32_t seed_count; | 181 | uint32_t seed_count; |
| 183 | uint32_t peer_count; | 182 | /* each family's peers: a normal vector, or a pointer to ot_vector[] buckets |
| 184 | /* normal peers vector or | 183 | when data != NULL and space == 0 (size then holds the bucket count) */ |
| 185 | pointer to ot_vector[32] buckets if data != NULL and space == 0 | 184 | ot_vector peers6; |
| 186 | */ | 185 | ot_vector peers4; |
| 187 | ot_vector peers; | ||
| 188 | }; | 186 | }; |
| 189 | #define OT_PEERLIST_HASBUCKETS(peer_list) ((peer_list)->peers.size > (peer_list)->peers.space) | ||
| 190 | 187 | ||
| 191 | static inline uint32_t peerlist_peer_count(const ot_peerlist *peer_list) { return peer_list ? peer_list->peer_count : 0; } | 188 | /* A peer vector becomes a bucket list of peer vectors, marker is size > space (usually 0) */ |
| 192 | static inline uint32_t peerlist_seed_count(const ot_peerlist *peer_list) { return peer_list ? peer_list->seed_count : 0; } | 189 | #define OT_VECTOR_HASBUCKETS(v) ((v)->size > (v)->space) |
| 190 | |||
| 191 | /* Peers in one family: a plain vector's size is the count, a bucket list's is | ||
| 192 | the sum of its buckets. O(1) for the small torrents that dominate a table. */ | ||
| 193 | static inline size_t vector_peer_count(const ot_vector *v) { | ||
| 194 | const ot_vector *b; | ||
| 195 | size_t n, total = 0; | ||
| 196 | if (!OT_VECTOR_HASBUCKETS(v)) | ||
| 197 | return v->size; | ||
| 198 | b = (const ot_vector *)v->data; | ||
| 199 | for (n = 0; n < v->size; ++n) | ||
| 200 | total += b[n].size; | ||
| 201 | return total; | ||
| 202 | } | ||
| 203 | static inline size_t torrent_peer_count(const ot_torrent *t) { | ||
| 204 | return t->peer_list ? vector_peer_count(&t->peer_list->peers6) + vector_peer_count(&t->peer_list->peers4) : 0; | ||
| 205 | } | ||
| 206 | static inline uint32_t torrent_seed_count(const ot_torrent *t) { return t->peer_list ? t->peer_list->seed_count : 0; } | ||
| 193 | 207 | ||
| 194 | /* The http replies the tracker counts when it has to refuse a request. */ | 208 | /* The http replies the tracker counts when it has to refuse a request. */ |
| 195 | enum { | 209 | enum { |
| @@ -314,5 +328,6 @@ void iterate_all_torrents(int (*for_each)(ot_torrent *torrent, uintptr_t data), | |||
| 314 | 328 | ||
| 315 | /* Helper, before it moves to its own object */ | 329 | /* Helper, before it moves to its own object */ |
| 316 | void free_peerlist(ot_peerlist *peer_list); | 330 | void free_peerlist(ot_peerlist *peer_list); |
| 331 | void free_peer_vector(ot_vector *peer_vector); | ||
| 317 | 332 | ||
| 318 | #endif | 333 | #endif |
