diff --git a/crates/librqbit/src/chunk_tracker.rs b/crates/librqbit/src/chunk_tracker.rs index 1385a4d..7dbdebe 100644 --- a/crates/librqbit/src/chunk_tracker.rs +++ b/crates/librqbit/src/chunk_tracker.rs @@ -72,6 +72,18 @@ impl ChunkTracker { self.needed_pieces.set(index.get() as usize, false) } + pub fn iter_needed_pieces(&self) -> impl Iterator + '_ { + // Try the last piece first. Often important information is stored in the last piece. + // Then sequentially one by one. This is not super sophisticated but sometimes helps. + let last_piece_id = self.lengths.last_piece_id().get() as usize; + self.needed_pieces + .get(last_piece_id..) + .unwrap() + .iter_ones() + .map(move |n| n + last_piece_id) + .chain(self.needed_pieces.get(..last_piece_id).unwrap().iter_ones()) + } + // None if wrong chunk // true if did something // false if didn't do anything diff --git a/crates/librqbit/src/torrent_state.rs b/crates/librqbit/src/torrent_state.rs index a240eff..d6340be 100644 --- a/crates/librqbit/src/torrent_state.rs +++ b/crates/librqbit/src/torrent_state.rs @@ -349,7 +349,7 @@ impl TorrentState { fn get_next_needed_piece(&self, peer_handle: PeerHandle) -> Option { let g = self.locked.read(); let bf = g.peers.get_live(peer_handle)?.bitfield.as_ref()?; - for n in g.chunks.get_needed_pieces().iter_ones() { + for n in g.chunks.iter_needed_pieces() { if bf.get(n).map(|v| *v) == Some(true) { // in theory it should be safe without validation, but whatever. return self.lengths.validate_piece_index(n as u32); @@ -375,7 +375,7 @@ impl TorrentState { let n = { let mut n_opt = None; let bf = g.peers.get_live(peer_handle)?.bitfield.as_ref()?; - for n in g.chunks.get_needed_pieces().iter_ones() { + for n in g.chunks.iter_needed_pieces() { if bf.get(n).map(|v| *v) == Some(true) { n_opt = Some(n); break; diff --git a/crates/librqbit_core/src/lengths.rs b/crates/librqbit_core/src/lengths.rs index 3d5ade4..e3d7206 100644 --- a/crates/librqbit_core/src/lengths.rs +++ b/crates/librqbit_core/src/lengths.rs @@ -118,6 +118,9 @@ impl Lengths { pub const fn total_chunks(&self) -> u32 { ceil_div_u64(self.total_length, self.chunk_length as u64) as u32 } + pub const fn last_piece_id(&self) -> ValidPieceIndex { + ValidPieceIndex(self.last_piece_id) + } pub const fn total_pieces(&self) -> u32 { self.last_piece_id + 1 }