summaryrefslogtreecommitdiff
path: root/tests/t_clean.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 /tests/t_clean.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 'tests/t_clean.c')
-rw-r--r--tests/t_clean.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/tests/t_clean.c b/tests/t_clean.c
index 0237cc6..ce17bc3 100644
--- a/tests/t_clean.c
+++ b/tests/t_clean.c
@@ -33,6 +33,20 @@ static void announce(struct ot_workstruct *ws, ot_hash *hash, uint8_t last_octet
33 add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, 0); 33 add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, 0);
34} 34}
35 35
36/* A distinct v4 peer addressed by two octets, to build swarms past 256 */
37static size_t announce_wide(struct ot_workstruct *ws, ot_hash *hash, unsigned int which, size_t amount) {
38 static const uint8_t v4mapped[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
39
40 ws->reply = ws->outbuf;
41 memset(&ws->peer, 0, sizeof(ws->peer));
42 memcpy(&ws->peer, v4mapped, sizeof(v4mapped));
43 ((uint8_t *)&ws->peer)[14] = (uint8_t)(which >> 8);
44 ((uint8_t *)&ws->peer)[15] = (uint8_t)which;
45 OT_SETPORT(&ws->peer, &(uint16_t){6881});
46 ws->hash = hash;
47 return add_peer_to_torrent_and_return_peers(FLAG_TCP, ws, amount);
48}
49
36static size_t peers_in(ot_hash *hash) { 50static size_t peers_in(ot_hash *hash) {
37 char reply[1024]; 51 char reply[1024];
38 size_t len = return_udp_scrape_for_torrent(*hash, reply); 52 size_t len = return_udp_scrape_for_torrent(*hash, reply);
@@ -157,6 +171,39 @@ static void case_empty_torrent_timeout_bounds_a_counter_only_torrent(void) {
157 workstruct_deinit(&ws); 171 workstruct_deinit(&ws);
158} 172}
159 173
174static void case_a_bucketed_swarm_survives_clean_and_serves(void) {
175 struct ot_workstruct ws;
176 ot_hash hash;
177 ot_torrent *torrent;
178 unsigned int i;
179 const unsigned int n = 600; /* past OT_PEER_BUCKET_MINCOUNT (512) */
180
181 test_case("a swarm large enough to be bucketed cleans, splits and serves without loss");
182 memset(hash, 0x34, sizeof(hash));
183 CHECK_INT(workstruct_init(&ws, G_INBUF_SIZE), 0);
184
185 for (i = 0; i < n; ++i)
186 announce_wide(&ws, &hash, i, 0);
187 CHECK_INT(peers_in(&hash), n);
188
189 torrent = torrent_of(&hash);
190 CHECK(torrent != NULL);
191 CHECK(torrent->peer_list != NULL);
192
193 /* A clean with a minute elapsed splits the flat vector into buckets */
194 step_clock_back(torrent, -1);
195 CHECK_INT(clean_single_torrent(torrent), 0);
196 CHECK(torrent->peer_list != NULL);
197 CHECK_INT(OT_VECTOR_HASBUCKETS(&torrent->peer_list->peers4), 1);
198 CHECK_INT(peers_in(&hash), n);
199
200 /* Serve a selection back, which walks the bucket list */
201 CHECK(announce_wide(&ws, &hash, 1, 200) > 0);
202 CHECK_INT(peers_in(&hash), n);
203
204 workstruct_deinit(&ws);
205}
206
160void test_clean(void) { 207void test_clean(void) {
161 sigset_t hup; 208 sigset_t hup;
162 209
@@ -170,5 +217,6 @@ void test_clean(void) {
170 case_a_clock_that_went_back_keeps_the_swarm(); 217 case_a_clock_that_went_back_keeps_the_swarm();
171 case_an_idle_swarm_still_ages_out(); 218 case_an_idle_swarm_still_ages_out();
172 case_empty_torrent_timeout_bounds_a_counter_only_torrent(); 219 case_empty_torrent_timeout_bounds_a_counter_only_torrent();
220 case_a_bucketed_swarm_survives_clean_and_serves();
173 trackerlogic_deinit(); 221 trackerlogic_deinit();
174} 222}