file.deselect() drops shared pieces from the active download pool, causing torrents to hang at 99%
Bug Report: file.deselect() drops shared pieces from the active download pool, causing torrents to hang at 99%
Description
When a piece is shared across the boundary of two files, calling file.deselect() on one of the files causes webtorrent to completely remove that shared piece from this._selections (via this._torrent.deselect()).
If the adjacent file sharing that piece is still selected, it will never finish downloading because its final piece has been stripped from the active selection pool. This causes the torrent to hang indefinitely at 99.9% and never emit the 'done' event.
Steps to Reproduce
- Start downloading a torrent that contains at least two adjacent files (e.g., a large
.mp4followed immediately by a small.srtfile). By default,webtorrentselects both files. - Call
file.deselect()on the small.srtfile. webtorrentcallstorrent.deselect(startPiece, endPiece). Because the.srtfile shares itsstartPiecewith the.mp4file'sendPiece, that piece is dropped fromthis._selections.- Observe the download progress. The
.mp4file will download all of its pieces except the final one, getting permanently stuck at 99.9% completion.
Expected Behavior
file.deselect() should be aware of cross-file piece boundaries. It should ideally check if a piece is still required by another currently-selected file before unconditionally stripping it from the selection pool.
Alternatively, file.deselect() could simply lower the priority of the piece rather than removing it entirely if it's shared.
Workaround
For anyone experiencing this, you can manually patch the piece array by immediately re-calling file.select() on the files you do want after calling deselect() on the ones you don't:
// Deselect the unwanted files
for (const f of unwantedFiles) {
f.deselect();
}
// Immediately re-select the wanted files.
// This forces webtorrent to restore any shared pieces that were just dropped!
for (const f of wantedFiles) {
f.select();
}Environment
- WebTorrent version: v2.x / v3.x
- Node.js version: (Any)
Source: webtorrent/webtorrent