Fix a couple bugs.

1. Bug one - last_piece_id when only_files is present.
2. Bug two - do not ensure_file_length for files we don't need.
This commit is contained in:
Igor Katson 2021-10-18 16:07:30 +01:00
parent f739c99dc0
commit 3a64254971
4 changed files with 34 additions and 13 deletions

2
Cargo.lock generated
View file

@ -1380,7 +1380,7 @@ dependencies = [
[[package]] [[package]]
name = "rqbit" name = "rqbit"
version = "1.1.0" version = "1.1.1"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap", "clap",

View file

@ -20,6 +20,8 @@ pub struct ChunkTracker {
have: BF, have: BF,
lengths: Lengths, lengths: Lengths,
priority_piece_ids: Vec<usize>,
} }
// TODO: this should be redone from "have" pieces, not from "needed" pieces. // TODO: this should be redone from "have" pieces, not from "needed" pieces.
@ -55,11 +57,20 @@ pub enum ChunkMarkingResult {
impl ChunkTracker { impl ChunkTracker {
pub fn new(needed_pieces: BF, have_pieces: BF, lengths: Lengths) -> Self { pub fn new(needed_pieces: BF, have_pieces: BF, lengths: Lengths) -> Self {
// TODO: ideally this needs to be a list based on needed files, e.g.
// last needed piece for each file. But let's keep simple for now.
let last_needed_piece_id = needed_pieces.iter_ones().rev().next();
// The last pieces first. Often important information is stored in the last piece.
// E.g. if it's a video file, than the last piece often contains some index, or just
// players look into it, and it's better be there.
let priority_piece_ids = last_needed_piece_id.into_iter().collect();
Self { Self {
chunk_status: compute_chunk_status(&lengths, &needed_pieces), chunk_status: compute_chunk_status(&lengths, &needed_pieces),
needed_pieces, needed_pieces,
lengths, lengths,
have: have_pieces, have: have_pieces,
priority_piece_ids,
} }
} }
pub fn get_needed_pieces(&self) -> &BF { pub fn get_needed_pieces(&self) -> &BF {
@ -73,15 +84,15 @@ impl ChunkTracker {
} }
pub fn iter_needed_pieces(&self) -> impl Iterator<Item = usize> + '_ { pub fn iter_needed_pieces(&self) -> impl Iterator<Item = usize> + '_ {
// Try the last piece first. Often important information is stored in the last piece. self.priority_piece_ids
// Then sequentially one by one. This is not super sophisticated but sometimes helps. .iter()
let last_piece_id = self.lengths.last_piece_id().get() as usize; .copied()
self.needed_pieces .filter(move |piece_id| self.needed_pieces[*piece_id])
.get(last_piece_id..) .chain(
.unwrap() self.needed_pieces
.iter_ones() .iter_ones()
.map(move |n| n + last_piece_id) .filter(move |id| !self.priority_piece_ids.contains(id)),
.chain(self.needed_pieces.get(..last_piece_id).unwrap().iter_ones()) )
} }
// None if wrong chunk // None if wrong chunk

View file

@ -214,9 +214,19 @@ impl TorrentManager {
); );
spawner.spawn_block_in_place(|| { spawner.spawn_block_in_place(|| {
for (file, (name, length)) in for (idx, (file, (name, length))) in files
files.iter().zip(info.iter_filenames_and_lengths().unwrap()) .iter()
.zip(info.iter_filenames_and_lengths().unwrap())
.enumerate()
{ {
if options
.only_files
.as_ref()
.map(|v| !v.contains(&idx))
.unwrap_or(false)
{
continue;
}
let now = Instant::now(); let now = Instant::now();
if let Err(err) = ensure_file_length(&mut file.lock(), length) { if let Err(err) = ensure_file_length(&mut file.lock(), length) {
warn!( warn!(

View file

@ -1,7 +1,7 @@
[package] [package]
name = "rqbit" name = "rqbit"
description = "A bittorent client" description = "A bittorent client"
version = "1.1.0" version = "1.1.1"
authors = ["Igor Katson <igor.katson@gmail.com>"] authors = ["Igor Katson <igor.katson@gmail.com>"]
edition = "2018" edition = "2018"