Skip to content

feat(stats): expose per-piece chunk progress - #650

Open
zond wants to merge 1 commit into
ikatson:mainfrom
zond:piece-chunk-progress
Open

zond wants to merge 1 commit into
ikatson:mainfrom
zond:piece-chunk-progress

Conversation

@zond

@zond zond commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Progress is only observable at whole-piece granularity today: the have bitfield behind api_dump_haves, TorrentStats and file_progress all count verified pieces. That is fine for a download bar over a whole torrent, but not for a consumer waiting on one specific piece: with a 16 MiB piece length, a reader blocked on a 4 MiB window inside a single piece can only ever observe 0% or 100%, and appears frozen for the whole time the piece is in flight.

The information already exists. ChunkTracker keeps chunk_status, one bit per 16 KiB chunk, set by mark_chunk_downloaded as blocks arrive and cleared by mark_piece_broken_if_not_have when a piece fails its hash. It just was not reachable: the chunk_tracker module is private and with_chunk_tracker is pub(crate).

Add ChunkTracker::piece_chunk_progress(piece_index) -> Option<PieceChunkProgress>, and ManagedTorrent::piece_chunk_progress(piece_index) -> Result<PieceChunkProgress> reaching it through the existing with_chunk_tracker, in the style of Api::api_dump_haves. PieceChunkProgress carries downloaded_chunks, total_chunks and verified, and is re-exported from the crate root.

Read-only and cheap enough to poll once a second: it counts bits in a bitfield that is already there, allocates nothing, and holds the state lock only for that count.

The counts are downloaded-not-verified, and the docs on both methods say so in as many words: a chunk counts once it has been written to storage, the hash is only checked when the piece is complete, and a piece that fails goes back to zero. verified distinguishes a piece that is merely fully downloaded from one that is known good, so a caller can hold a progress bar short of 100% rather than let it silently run backwards.

Purely additive: no behaviour change, no new dependencies, and no existing type or serde shape is touched.

This one is also created by my friendly Opus 5 agent.

Progress is only observable at whole-piece granularity today: the have
bitfield behind `api_dump_haves`, `TorrentStats` and `file_progress` all
count verified pieces. That is fine for a download bar over a whole
torrent, but not for a consumer waiting on one specific piece: with a
16 MiB piece length, a reader blocked on a 4 MiB window inside a single
piece can only ever observe 0% or 100%, and appears frozen for the whole
time the piece is in flight.

The information already exists. ChunkTracker keeps `chunk_status`, one
bit per 16 KiB chunk, set by `mark_chunk_downloaded` as blocks arrive and
cleared by `mark_piece_broken_if_not_have` when a piece fails its hash.
It just was not reachable: the `chunk_tracker` module is private and
`with_chunk_tracker` is `pub(crate)`.

Add `ChunkTracker::piece_chunk_progress(piece_index) -> Option<PieceChunkProgress>`,
and `ManagedTorrent::piece_chunk_progress(piece_index) -> Result<PieceChunkProgress>`
reaching it through the existing `with_chunk_tracker`, in the style of
`Api::api_dump_haves`. `PieceChunkProgress` carries `downloaded_chunks`,
`total_chunks` and `verified`, and is re-exported from the crate root.

Read-only and cheap enough to poll once a second: it counts bits in a
bitfield that is already there, allocates nothing, and holds the state
lock only for that count.

The counts are downloaded-not-verified, and the docs on both methods say
so in as many words: a chunk counts once it has been written to storage,
the hash is only checked when the piece is complete, and a piece that
fails goes back to zero. `verified` distinguishes a piece that is merely
fully downloaded from one that is known good, so a caller can hold a
progress bar short of 100% rather than let it silently run backwards.

Purely additive: no behaviour change, no new dependencies, and no
existing type or serde shape is touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant