Improve swarm peer saturation
This commit is contained in:
parent
6ae72907b0
commit
6be239943a
2 changed files with 265 additions and 34 deletions
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue