PiecePicker
Rarest-first piece selection: a pure-Kotlin port of the core of libtorrent's piece_picker (src/piece_picker.cpp, include/libtorrent/piece_picker.hpp).
The picker decides which block to request from which peer. It tracks, per piece:
availability: how many connected peers have the piece (incRefcount/ decRefcount driven by HAVE / BITFIELD / disconnect events), plus a seed counter so seeds don't each bump every piece individually;
priority: a manually-set 0..7 level (setPiecePriority); 0 = filtered (never downloaded);
block state: for partially downloaded pieces, the BlockState.NONE/BlockState.REQUESTED/BlockState.WRITING/BlockState.FINISHED state of every block, and which peer each was requested from;
have: whether the piece has passed its hash check.
pickPieces returns blocks in rarest-first order: the controlling key is piece_pos::priority() (ported verbatim in effectivePriority), where a lower value is picked first. Availability dominates that value, so a piece only one peer has outranks a piece every peer has; the manual priority and a partial-vs-open adjustment break ties exactly as upstream does.
Peers are kept fully opaque: callers identify a peer by any token (peerId: Any?), mirroring libtorrent's torrent_peer* without dragging in a peer_connection.
Scope (faithful core)
Ported: availability + seed accounting, the exact priority formula and its rarest-first / sequential / random ordering, the download-queue bucketing (open / downloading / full / finished / zero-prio) via updatePieceState, the full block state machine (markAsDownloading/markAsWriting/markAsFinished/ markAsCanceled/abortDownload/writeFailed/restorePiece), cursors, and the want/have/num_have counters.
Deliberately omitted (and noted in the module summary): the reverse, on_parole, piece_extent_affinity, prefer_contiguous_blocks/expand_piece whole-piece heuristics, suggested-pieces, end-game busy-block stealing, pad files, hashing-job details, and the mutable m_pieces/m_priority_boundaries swap-list with random in-bucket shuffling. Instead of that swap-list, pickPieces computes the pick order by stably sorting the pickable pieces on the same priority() key the swap-list encodes. The ordering semantics are the same, with far less machinery. Equal-priority ties are broken by piece index (the swap list randomizes them); pass a Random to pickPieces to restore randomized tie-breaking.
Functions
Cancel a requested block for peerId. Mirrors abort_download. Decrements the block's peer count; if other peers still have it requested the block stays requested. When it drops to zero the block returns to free, and if the whole piece becomes empty it is removed from the download list.
Blocks in the final piece. Mirrors piece_picker::blocks_in_last_piece().
Blocks in piece index: blocksInLastPiece for the last piece, else blocksPerPiece.
Blocks per (non-last) piece.
Decrement availability for every piece in bitmask (a peer with this bitfield disconnected). Mirrors the bitfield dec_refcount, with the same break-one-seed fix-up per piece.
Decrement the availability of index (a peer that had it disconnected, or sent dont-have). Mirrors piece_picker::dec_refcount(piece_index_t, ...), including the "break one seed" fix-up: if the per-piece count is already 0 but seeds exist, one seed is converted into explicit per-piece counts first so the counter never goes negative.
Pieces in any download bucket (downloading/full/finished/zero-prio): get_download_queue_size. The strict end-game gate compares this to numWantLeft: only when every wanted piece is already in the download queue may a busy block be double-requested.
The effective priority / sort value of piece: a verbatim port of piece_pos::priority(piece_picker const*).
The peer token block was last requested/downloaded from, or null. get_downloader.
The peer token for every block of piece (null where unknown). Length is blocksInPiece. Mirrors get_downloaders.
Increment availability for every piece in bitmask for peerId (a BITFIELD message). If the bitmask covers every piece it is treated as a seed and routed through incRefcountAll. Mirrors the bitfield inc_refcount.
Register a connected seed: bumps the seeds counter for every piece at once. Mirrors inc_refcount_all. Used when a seed joins the swarm.
True if block is finished or writing (i.e. we've received it). is_downloaded.
True if piece is partially or fully in a download bucket. is_downloading.
True once every piece we want has passed its hash check. Mirrors is_finished(): numPieces - numFiltered <= numHave.
True if block has been written to disk. is_finished.
True if every block of piece is finished or writing (or we already have it). Mirrors is_piece_finished. Note this is about blocks received, not the hash check. A piece can be "finished" before it has "passed".
True if piece is fully written to disk (is_piece_flushed). In this core a piece is "flushed" exactly when havePiece flips it on via markAsFinished of the last block or an explicit pieceFlushed.
True if block is currently in the BlockState.REQUESTED state. is_requested.
Lock piece so no blocks are picked from it until restorePiece. lock_piece.
Undo a writing block back to free (a write was cancelled). Mirrors mark_as_canceled. Only acts on a writing block; a no-op otherwise. If the piece becomes empty it is removed from the download list.
Mark block as requested from peerId. Mirrors mark_as_downloading. Returns false (without changing state) if the block is already writing or finished. If the block was already requested from another peer, this just bumps its peer count (end-game style). Lazily creates the piece's DownloadingPiece the first time a block of an open piece is touched.
Number of pieces in the downloading bucket only (partially requested, free blocks remain): m_downloads[piece_downloading].size(), the count behind the partial-sprawl cap.
Blocks of piece still free to request (not requested/writing/finished), derived from the piece_info counters. snub_peer uses this to decide whether a stalled request actually blocks the piece's completion.
How many peers currently have block in a request queue. num_peers.
Pieces we want and don't yet have. num_want_left.
Pick up to numBlocksWanted interesting blocks for a peer whose available pieces are described by peerBitfield. This is a port of pick_pieces, including its option modes and the end-game busy-block tail.
Mark piece as completely downloaded and flushed to disk. The picker now counts it as had and stops tracking its blocks. Mirrors piece_flushed. Safe to call straight from open (e.g. loading resume data): the have count is accounted as if it had been downloaded and hash-checked first.
Mark that the hash of piece passed. The piece may still be flushing to disk. If all blocks are already finished, this also flushes it (we "have" it). Mirrors piece_passed.
The manual priority of every piece, into a fresh IntArray. piece_priorities.
The manual priority (0..7) currently set on piece. piece_priority.
A snapshot of piece's state. piece_stats.
One past the last piece we don't have. reverse_cursor.
Override the block count of the final piece (for a short last piece). Must be called before any blocks are picked. This core does not derive it from a total byte size; the higher-level torrent layer supplies it.
Set the manual priority of piece to newPriority (0..7). Returns true iff this flipped the piece between filtered (0) and not-filtered, updating the filtered/have-filtered counters and cursors accordingly. Mirrors set_piece_priority.
Mark that we no longer have piece (e.g. it failed a later check and must be redownloaded). Mirrors we_dont_have. Restores cursors and the have count, and clears any partial download state.
Mark a writing block as failed-to-write: it returns to free and the piece is locked (no more picks) until restorePiece is called. If the piece had already passed its hash check, that is undone and the have count restored. Mirrors write_failed.