Improve swarm peer saturation

This commit is contained in:
ookami125 2026-06-17 01:52:30 -04:00
parent 6ae72907b0
commit 6be239943a
2 changed files with 265 additions and 34 deletions

View file

@ -9,6 +9,7 @@
#define BLK NAUT_BLOCK /* 16 KiB */
#define ENDGAME_BLOCKS 8 /* switch to endgame when this few remain */
#define ENDGAME_COPIES 2 /* at most two peers race a missing block */
#define PIECE_INFLIGHT_SOFT_CAP 64
/* per-piece in-progress state, lazily allocated and freed on completion */
typedef struct {
@ -37,6 +38,7 @@ struct naut_download {
pstate **ps; /* [num_pieces] in-progress state or NULL */
uint32_t cur_piece; /* sequential cursor for next_request() */
uint32_t pick_cursor; /* rotating start point for rarest-first ties */
uint64_t total_blocks, recv_blocks;
uint32_t pieces_done;
@ -205,6 +207,12 @@ static uint32_t first_unreq(const pstate *s) {
return UINT32_MAX;
}
static uint32_t piece_inflight(const pstate *s) {
uint32_t n = 0;
for (uint32_t b = 0; b < s->nblocks; b++) n += s->req_count[b];
return n;
}
static bool hand_out(naut_download *d, uint32_t p, uint32_t b,
uint32_t *index, uint32_t *begin, uint32_t *length) {
d->ps[p]->req_count[b]++;
@ -218,15 +226,20 @@ bool naut_download_pick_for_peer(naut_download *d, const naut_bitfield *peer_hav
d->endgame = (d->total_blocks - d->recv_blocks) <= ENDGAME_BLOCKS;
/* pass 1: finish an in-progress piece the peer has (reduces fragmentation) */
for (uint32_t p = 0; p < d->num_pieces; p++) {
for (uint32_t n = 0; n < d->num_pieces; n++) {
uint32_t p = (d->pick_cursor + n) % d->num_pieces;
if (naut_bitfield_test(&d->have, p) || !d->ps[p]) continue;
if (p >= peer_have->nbits || !naut_bitfield_test(peer_have, p)) continue;
if (!d->endgame &&
piece_inflight(d->ps[p]) >= PIECE_INFLIGHT_SOFT_CAP)
continue;
uint32_t b = first_unreq(d->ps[p]);
if (b != UINT32_MAX) return hand_out(d, p, b, index, begin, length);
}
/* pass 2: start the rarest new piece the peer has */
uint32_t best = UINT32_MAX, best_av = UINT32_MAX;
for (uint32_t p = 0; p < d->num_pieces; p++) {
for (uint32_t n = 0; n < d->num_pieces; n++) {
uint32_t p = (d->pick_cursor + n) % d->num_pieces;
if (naut_bitfield_test(&d->have, p) || d->ps[p]) continue;
if (p >= peer_have->nbits || !naut_bitfield_test(peer_have, p) ||
d->avail[p] == 0) continue;
@ -234,12 +247,14 @@ bool naut_download_pick_for_peer(naut_download *d, const naut_bitfield *peer_hav
}
if (best != UINT32_MAX) {
if (!ensure_ps(d, best)) return false;
d->pick_cursor = (best + 1) % d->num_pieces;
return hand_out(d, best, 0, index, begin, length);
}
/* pass 3: endgame — race each missing block on at most two distinct peers */
if (d->endgame) {
for (uint8_t copies = 1; copies < ENDGAME_COPIES; copies++) {
for (uint32_t p = 0; p < d->num_pieces; p++) {
for (uint32_t n = 0; n < d->num_pieces; n++) {
uint32_t p = (d->pick_cursor + n) % d->num_pieces;
if (naut_bitfield_test(&d->have, p) ||
p >= peer_have->nbits ||
!naut_bitfield_test(peer_have, p)) continue;