piece picker fixes and optimizations (requires more tests in unit tests)
This commit is contained in:
parent
d2706b3600
commit
24b57d62c8
|
@ -159,6 +159,9 @@ namespace libtorrent
|
|||
return m_prefer_whole_pieces;
|
||||
}
|
||||
|
||||
bool on_parole() const
|
||||
{ return peer_info_struct() && peer_info_struct()->on_parole; }
|
||||
|
||||
void prefer_whole_pieces(int num)
|
||||
{ m_prefer_whole_pieces = num; }
|
||||
|
||||
|
|
|
@ -195,20 +195,30 @@ namespace libtorrent
|
|||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_pieces, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed
|
||||
, bool rarest_first) const;
|
||||
, bool rarest_first, bool on_parole
|
||||
, std::vector<int> const& suggested_pieces) const;
|
||||
|
||||
// picks blocks from each of the pieces in the piece_list
|
||||
// vector that is also in the piece bitmask. The blocks
|
||||
// are added to interesting_blocks, and busy blocks are
|
||||
// added to backup_blocks. num blocks is the number of
|
||||
// blocks to be picked.
|
||||
int add_interesting_blocks(std::vector<int> const& piece_list
|
||||
// blocks to be picked. Blocks are not picked from pieces
|
||||
// that are being downloaded
|
||||
int add_blocks(std::vector<int> const& piece_list
|
||||
, const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, std::vector<int> const& ignore) const;
|
||||
|
||||
// picks blocks only from downloading pieces
|
||||
int piece_picker::add_blocks_downloading(
|
||||
std::vector<bool> const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed
|
||||
, bool ignore_downloading_pieces) const;
|
||||
, bool on_parole) const;
|
||||
|
||||
// clears the peer pointer in all downloading pieces with this
|
||||
// peer pointer
|
||||
|
@ -336,9 +346,9 @@ namespace libtorrent
|
|||
|
||||
int priority(int limit) const
|
||||
{
|
||||
if (filtered() || have()) return 0;
|
||||
if (downloading || filtered() || have()) return 0;
|
||||
// pieces we are currently downloading have high priority
|
||||
int prio = downloading ? (std::min)(1, int(peer_count)) : peer_count * 2;
|
||||
int prio = peer_count * 2;
|
||||
// if the peer_count is 0 or 1, the priority cannot be higher
|
||||
if (prio <= 1) return prio;
|
||||
if (prio >= limit * 2) prio = limit * 2;
|
||||
|
|
|
@ -1080,7 +1080,8 @@ namespace libtorrent
|
|||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed, bool rarest_first) const
|
||||
, void* peer, piece_state_t speed, bool rarest_first
|
||||
, bool on_parole, std::vector<int> const& suggested_pieces) const
|
||||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
assert(num_blocks > 0);
|
||||
|
@ -1096,36 +1097,21 @@ namespace libtorrent
|
|||
// blocks belonging to a piece that others have
|
||||
// downloaded to
|
||||
std::vector<piece_block> backup_blocks;
|
||||
// suggested pieces for each vector is put in this vector
|
||||
std::vector<int> suggested_bucket;
|
||||
const std::vector<int> empty_vector;
|
||||
|
||||
// When prefer_whole_pieces is set (usually set when downloading from
|
||||
// fast peers) the partial pieces will not be prioritized, but actually
|
||||
// ignored as long as possible. All blocks found in downloading
|
||||
// pieces are regarded as backup blocks
|
||||
bool ignore_downloading_pieces = false;
|
||||
if (prefer_whole_pieces > 0 || !rarest_first)
|
||||
{
|
||||
std::vector<int> downloading_pieces;
|
||||
downloading_pieces.reserve(m_downloads.size());
|
||||
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
|
||||
, end(m_downloads.end()); i != end; ++i)
|
||||
{
|
||||
downloading_pieces.push_back(i->index);
|
||||
}
|
||||
if (prefer_whole_pieces > 0)
|
||||
{
|
||||
add_interesting_blocks(downloading_pieces, pieces
|
||||
, backup_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_blocks = add_interesting_blocks(downloading_pieces, pieces
|
||||
, interesting_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
|
||||
}
|
||||
ignore_downloading_pieces = true;
|
||||
}
|
||||
|
||||
|
||||
num_blocks = add_blocks_downloading(pieces
|
||||
, interesting_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer, speed, on_parole);
|
||||
|
||||
if (num_blocks == 0) return;
|
||||
|
||||
if (rarest_first)
|
||||
{
|
||||
// this loop will loop from pieces with priority 1 and up
|
||||
|
@ -1143,9 +1129,27 @@ namespace libtorrent
|
|||
++bucket)
|
||||
{
|
||||
if (bucket->empty()) continue;
|
||||
num_blocks = add_interesting_blocks(*bucket, pieces
|
||||
if (!suggested_pieces.empty())
|
||||
{
|
||||
int bucket_index = bucket - m_piece_info.begin();
|
||||
suggested_bucket.clear();
|
||||
for (std::vector<int>::const_iterator i = suggested_pieces.begin()
|
||||
, end(suggested_pieces.end()); i != end; ++i)
|
||||
{
|
||||
if (m_piece_map[*i].priority(m_sequenced_download_threshold) == bucket_index)
|
||||
suggested_bucket.push_back(*i);
|
||||
}
|
||||
if (!suggested_bucket.empty())
|
||||
{
|
||||
num_blocks = add_blocks(suggested_bucket, pieces
|
||||
, interesting_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer, empty_vector);
|
||||
if (num_blocks == 0) break;
|
||||
}
|
||||
}
|
||||
num_blocks = add_blocks(*bucket, pieces
|
||||
, interesting_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
|
||||
, prefer_whole_pieces, peer, suggested_bucket);
|
||||
assert(num_blocks >= 0);
|
||||
}
|
||||
}
|
||||
|
@ -1155,6 +1159,19 @@ namespace libtorrent
|
|||
// bucket, since that's where the currently downloading
|
||||
// pieces are)
|
||||
int start_piece = rand() % m_piece_map.size();
|
||||
|
||||
// if we have suggested pieces, try to find one of those instead
|
||||
for (std::vector<int>::const_iterator i = suggested_pieces.begin()
|
||||
, end(suggested_pieces.end()); i != end; ++i)
|
||||
{
|
||||
if (!pieces[*i]
|
||||
|| m_piece_map[*i].have()
|
||||
|| m_piece_map[*i].downloading
|
||||
|| m_piece_map[*i].filtered())
|
||||
continue;
|
||||
start_piece = *i;
|
||||
break;
|
||||
}
|
||||
int piece = start_piece;
|
||||
while (num_blocks > 0)
|
||||
{
|
||||
|
@ -1236,17 +1253,13 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
int piece_picker::add_interesting_blocks(std::vector<int> const& piece_list
|
||||
int piece_picker::add_blocks(std::vector<int> const& piece_list
|
||||
, std::vector<bool> const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed
|
||||
, bool ignore_downloading_pieces) const
|
||||
, void* peer, std::vector<int> const& ignore) const
|
||||
{
|
||||
// if we have less than 1% of the pieces, ignore speed priorities and just try
|
||||
// to finish any downloading piece
|
||||
bool ignore_speed_categories = (m_num_have * 100 / m_piece_map.size()) < 1;
|
||||
for (std::vector<int>::const_iterator i = piece_list.begin();
|
||||
i != piece_list.end(); ++i)
|
||||
{
|
||||
|
@ -1257,123 +1270,36 @@ namespace libtorrent
|
|||
// skip it
|
||||
if (!pieces[*i]) continue;
|
||||
|
||||
// ignore pieces found in the ignore list
|
||||
if (std::find(ignore.begin(), ignore.end(), *i) != ignore.end()) continue;
|
||||
|
||||
// skip the piece is the priority is 0
|
||||
if (m_piece_map[*i].priority(m_sequenced_download_threshold) == 0) continue;
|
||||
assert(m_piece_map[*i].priority(m_sequenced_download_threshold) > 0);
|
||||
|
||||
int num_blocks_in_piece = blocks_in_piece(*i);
|
||||
|
||||
if (m_piece_map[*i].downloading == 1)
|
||||
assert(m_piece_map[*i].downloading == 0);
|
||||
|
||||
// pick a new piece
|
||||
if (prefer_whole_pieces == 0)
|
||||
{
|
||||
if (ignore_downloading_pieces) continue;
|
||||
std::vector<downloading_piece>::const_iterator p
|
||||
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
|
||||
assert(p != m_downloads.end());
|
||||
|
||||
// is true if all the other pieces that are currently
|
||||
// requested from this piece are from the same
|
||||
// peer as 'peer'.
|
||||
bool exclusive;
|
||||
bool exclusive_active;
|
||||
boost::tie(exclusive, exclusive_active)
|
||||
= requested_from(*p, num_blocks_in_piece, peer);
|
||||
|
||||
// this means that this partial piece has
|
||||
// been downloaded/requested partially from
|
||||
// another peer that isn't us. And since
|
||||
// we prefer whole pieces, add this piece's
|
||||
// blocks to the backup list. If the prioritized
|
||||
// blocks aren't enough, blocks from this list
|
||||
// will be picked.
|
||||
if (prefer_whole_pieces > 0 && !exclusive)
|
||||
{
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
block_info const& info = p->info[j];
|
||||
if (info.state == block_info::state_finished
|
||||
|| info.state == block_info::state_writing)
|
||||
continue;
|
||||
if (info.state == block_info::state_requested
|
||||
&& info.peer == peer) continue;
|
||||
backup_blocks.push_back(piece_block(*i, j));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num_blocks_in_piece > num_blocks)
|
||||
num_blocks_in_piece = num_blocks;
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
// ignore completed blocks
|
||||
block_info const& info = p->info[j];
|
||||
if (info.state == block_info::state_finished
|
||||
|| info.state == block_info::state_writing)
|
||||
continue;
|
||||
// ignore blocks requested from this peer already
|
||||
if (info.state == block_info::state_requested
|
||||
&& info.peer == peer)
|
||||
continue;
|
||||
// if the piece is fast and the peer is slow, or vice versa,
|
||||
// add the block as a backup.
|
||||
// override this behavior if all the other blocks
|
||||
// have been requested from the same peer or
|
||||
// if the state of the piece is none (the
|
||||
// piece will in that case change state).
|
||||
if (p->state != none && p->state != speed
|
||||
&& !exclusive_active
|
||||
&& !ignore_speed_categories)
|
||||
{
|
||||
backup_blocks.push_back(piece_block(*i, j));
|
||||
continue;
|
||||
}
|
||||
// this block is interesting (we don't have it
|
||||
// yet). But it may already have been requested
|
||||
// from another peer. We have to add it anyway
|
||||
// to allow the requester to determine if the
|
||||
// block should be requested from more than one
|
||||
// peer. If it is being downloaded, we continue
|
||||
// to look for blocks until we have num_blocks
|
||||
// blocks that have not been requested from any
|
||||
// other peer.
|
||||
if (p->info[j].state == block_info::state_none)
|
||||
{
|
||||
interesting_blocks.push_back(piece_block(*i, j));
|
||||
// we have found a block that's free to download
|
||||
num_blocks--;
|
||||
// if we prefer whole pieces, continue picking from this
|
||||
// piece even though we have num_blocks
|
||||
if (prefer_whole_pieces > 0) continue;
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
}
|
||||
else
|
||||
{
|
||||
backup_blocks.push_back(piece_block(*i, j));
|
||||
}
|
||||
}
|
||||
assert(num_blocks >= 0 || prefer_whole_pieces > 0);
|
||||
if (num_blocks < 0) num_blocks = 0;
|
||||
interesting_blocks.push_back(piece_block(*i, j));
|
||||
num_blocks -= num_blocks_in_piece;
|
||||
}
|
||||
else
|
||||
{
|
||||
// pick a new piece
|
||||
if (prefer_whole_pieces == 0)
|
||||
int start, end;
|
||||
boost::tie(start, end) = expand_piece(*i, prefer_whole_pieces, pieces);
|
||||
for (int k = start; k < end; ++k)
|
||||
{
|
||||
if (num_blocks_in_piece > num_blocks)
|
||||
num_blocks_in_piece = num_blocks;
|
||||
num_blocks_in_piece = blocks_in_piece(k);
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
interesting_blocks.push_back(piece_block(*i, j));
|
||||
num_blocks -= num_blocks_in_piece;
|
||||
}
|
||||
else
|
||||
{
|
||||
int start, end;
|
||||
boost::tie(start, end) = expand_piece(*i, prefer_whole_pieces, pieces);
|
||||
for (int k = start; k < end; ++k)
|
||||
{
|
||||
num_blocks_in_piece = blocks_in_piece(k);
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
interesting_blocks.push_back(piece_block(k, j));
|
||||
--num_blocks;
|
||||
}
|
||||
interesting_blocks.push_back(piece_block(k, j));
|
||||
--num_blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1382,6 +1308,92 @@ namespace libtorrent
|
|||
return num_blocks;
|
||||
}
|
||||
|
||||
int piece_picker::add_blocks_downloading(std::vector<bool> const& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, void* peer, piece_state_t speed, bool on_parole) const
|
||||
{
|
||||
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
|
||||
, end(m_downloads.end()); i != end; ++i)
|
||||
{
|
||||
int num_blocks_in_piece = blocks_in_piece(i->index);
|
||||
|
||||
// is true if all the other pieces that are currently
|
||||
// requested from this piece are from the same
|
||||
// peer as 'peer'.
|
||||
bool exclusive;
|
||||
bool exclusive_active;
|
||||
boost::tie(exclusive, exclusive_active)
|
||||
= requested_from(*i, num_blocks_in_piece, peer);
|
||||
|
||||
// peers on parole are only allowed to pick blocks from
|
||||
// pieces that only they have downloaded/requested from
|
||||
if (on_parole && !exclusive) continue;
|
||||
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
// ignore completed blocks and already requested blocks
|
||||
block_info const& info = i->info[j];
|
||||
if (info.state == block_info::state_finished
|
||||
|| info.state == block_info::state_writing
|
||||
|| info.state == block_info::state_requested)
|
||||
continue;
|
||||
|
||||
assert(i->info[j].state == block_info::state_none);
|
||||
|
||||
// if the piece is fast and the peer is slow, or vice versa,
|
||||
// add the block as a backup.
|
||||
// override this behavior if all the other blocks
|
||||
// have been requested from the same peer or
|
||||
// if the state of the piece is none (the
|
||||
// piece will in that case change state).
|
||||
if (i->state != none && i->state != speed
|
||||
&& !exclusive_active)
|
||||
{
|
||||
backup_blocks.push_back(piece_block(i->index, j));
|
||||
continue;
|
||||
}
|
||||
|
||||
// this block is interesting (we don't have it
|
||||
// yet).
|
||||
interesting_blocks.push_back(piece_block(i->index, j));
|
||||
// we have found a block that's free to download
|
||||
num_blocks--;
|
||||
// if we prefer whole pieces, continue picking from this
|
||||
// piece even though we have num_blocks
|
||||
if (prefer_whole_pieces > 0) continue;
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
assert(num_blocks >= 0 || prefer_whole_pieces > 0);
|
||||
if (num_blocks <= 0) return 0;
|
||||
|
||||
interesting_blocks.insert(interesting_blocks.end()
|
||||
, backup_blocks.begin(), backup_blocks.end());
|
||||
backup_blocks.clear();
|
||||
|
||||
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
|
||||
, end(m_downloads.end()); i != end; ++i)
|
||||
{
|
||||
int num_blocks_in_piece = blocks_in_piece(i->index);
|
||||
|
||||
// fill in with blocks requested from other peers
|
||||
// as backups
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
block_info const& info = i->info[j];
|
||||
if (info.state != block_info::state_requested
|
||||
|| info.peer == peer)
|
||||
continue;
|
||||
backup_blocks.push_back(piece_block(i->index, j));
|
||||
}
|
||||
}
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
std::pair<int, int> piece_picker::expand_piece(int piece, int whole_pieces
|
||||
, std::vector<bool> const& have) const
|
||||
{
|
||||
|
@ -1735,13 +1747,16 @@ namespace libtorrent
|
|||
{
|
||||
erase_download_piece(i);
|
||||
piece_pos& p = m_piece_map[block.piece_index];
|
||||
int prio = p.priority(m_sequenced_download_threshold);
|
||||
assert(prio < int(m_piece_info.size()));
|
||||
int prev_prio = p.priority(m_sequenced_download_threshold);
|
||||
assert(prev_prio < int(m_piece_info.size()));
|
||||
p.downloading = 0;
|
||||
if (prio > 0) move(prio, p.index);
|
||||
int prio = p.priority(m_sequenced_download_threshold);
|
||||
if (prev_prio == 0 && prio > 0) add(block.piece_index);
|
||||
else if (prio > 0) move(prio, p.index);
|
||||
|
||||
assert(std::find_if(m_downloads.begin(), m_downloads.end()
|
||||
, has_index(block.piece_index)) == m_downloads.end());
|
||||
check_invariant();
|
||||
}
|
||||
else if (i->requested == 0)
|
||||
{
|
||||
|
|
|
@ -240,6 +240,8 @@ namespace libtorrent
|
|||
std::vector<piece_block> busy_pieces;
|
||||
busy_pieces.reserve(num_requests);
|
||||
|
||||
std::vector<int> const& suggested = c.suggested_pieces();
|
||||
|
||||
if (c.has_peer_choked())
|
||||
{
|
||||
// if we are choked we can only pick pieces from the
|
||||
|
@ -247,28 +249,18 @@ namespace libtorrent
|
|||
// in ascending priority order
|
||||
std::vector<int> const& allowed_fast = c.allowed_fast();
|
||||
|
||||
p.add_interesting_blocks(allowed_fast, c.get_bitfield()
|
||||
, interesting_pieces, busy_pieces, num_requests
|
||||
, prefer_whole_pieces, c.peer_info_struct(), state
|
||||
, false);
|
||||
interesting_pieces.insert(interesting_pieces.end()
|
||||
, busy_pieces.begin(), busy_pieces.end());
|
||||
busy_pieces.clear();
|
||||
// build a bitmask with only the allowed pieces in it
|
||||
std::vector<bool> mask(c.get_bitfield().size(), false);
|
||||
for (std::vector<int>::const_iterator i = allowed_fast.begin()
|
||||
, end(allowed_fast.end()); i != end; ++i)
|
||||
mask[*i] = true;
|
||||
|
||||
p.pick_pieces(mask, interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||
, state, rarest_first, c.on_parole(), suggested);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!c.suggested_pieces().empty())
|
||||
{
|
||||
// if the peer has suggested us to download certain pieces
|
||||
// try to pick among those primarily
|
||||
std::vector<int> const& suggested = c.suggested_pieces();
|
||||
|
||||
p.add_interesting_blocks(suggested, c.get_bitfield()
|
||||
, interesting_pieces, busy_pieces, num_requests
|
||||
, prefer_whole_pieces, c.peer_info_struct(), state
|
||||
, false);
|
||||
}
|
||||
|
||||
// picks the interesting pieces from this peer
|
||||
// the integer is the number of pieces that
|
||||
// should be guaranteed to be available for download
|
||||
|
@ -277,10 +269,9 @@ namespace libtorrent
|
|||
// the last argument is if we should prefer whole pieces
|
||||
// for this peer. If we're downloading one piece in 20 seconds
|
||||
// then use this mode.
|
||||
if (int(interesting_pieces.size()) < num_requests)
|
||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||
, state, rarest_first);
|
||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||
, state, rarest_first, c.on_parole(), suggested);
|
||||
}
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
|
|
|
@ -157,12 +157,13 @@ int test_main()
|
|||
policy::peer peer_struct(endp, policy::peer::connectable, 0);
|
||||
std::vector<piece_block> picked;
|
||||
boost::shared_ptr<piece_picker> p;
|
||||
const std::vector<int> empty_vector;
|
||||
|
||||
// make sure the block that is picked is from piece 1, since it
|
||||
// it is the piece with the lowest availability
|
||||
p = setup_picker("2223333", "* * * ", "", "");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() > 0);
|
||||
TEST_CHECK(picked.front().piece_index == 1);
|
||||
|
@ -173,7 +174,7 @@ int test_main()
|
|||
// has the highest priority among the available pieces
|
||||
p = setup_picker("1111111", "* * * ", "1111122", "");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("****** "), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("****** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() > 0);
|
||||
TEST_CHECK(picked.front().piece_index == 5);
|
||||
|
@ -184,7 +185,7 @@ int test_main()
|
|||
// whole pieces are preferred. The only whole piece is 1.
|
||||
p = setup_picker("1111111", " ", "1111111", "1023460");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("****** "), picked, 1, 1, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("****** "), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
||||
for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
|
||||
|
@ -204,7 +205,7 @@ int test_main()
|
|||
// make sure filtered pieces are ignored
|
||||
p = setup_picker("1111111", " ", "0010000", "");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() > 0);
|
||||
TEST_CHECK(picked.front().piece_index == 2);
|
||||
|
@ -214,7 +215,7 @@ int test_main()
|
|||
// make sure requested blocks aren't picked
|
||||
p = setup_picker("1234567", " ", "", "");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() > 0);
|
||||
TEST_CHECK(picked.front().piece_index == 0);
|
||||
|
@ -222,7 +223,7 @@ int test_main()
|
|||
p->mark_as_downloading(picked.front(), &peer_struct, piece_picker::fast);
|
||||
TEST_CHECK(p->num_peers(picked.front()) == 1);
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() > 0);
|
||||
TEST_CHECK(picked.front() != first);
|
||||
|
@ -234,7 +235,7 @@ int test_main()
|
|||
p = setup_picker("7654321", " ", "", "");
|
||||
picked.clear();
|
||||
p->set_sequenced_download_threshold(3);
|
||||
p->pick_pieces(string2vec("***** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("***** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 5 * blocks_per_piece);
|
||||
|
@ -243,7 +244,7 @@ int test_main()
|
|||
|
||||
picked.clear();
|
||||
p->set_sequenced_download_threshold(4);
|
||||
p->pick_pieces(string2vec("**** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("**** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 4 * blocks_per_piece);
|
||||
|
@ -252,7 +253,7 @@ int test_main()
|
|||
|
||||
picked.clear();
|
||||
p->set_sequenced_download_threshold(2);
|
||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 6 * blocks_per_piece);
|
||||
|
@ -261,7 +262,7 @@ int test_main()
|
|||
|
||||
picked.clear();
|
||||
p->set_piece_priority(0, 0);
|
||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 5 * blocks_per_piece);
|
||||
|
@ -270,7 +271,7 @@ int test_main()
|
|||
|
||||
picked.clear();
|
||||
p->set_piece_priority(0, 1);
|
||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 6 * blocks_per_piece);
|
||||
|
@ -292,7 +293,7 @@ int test_main()
|
|||
TEST_CHECK(p->num_have_filtered() == 1);
|
||||
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 6 * blocks_per_piece);
|
||||
|
@ -320,7 +321,7 @@ int test_main()
|
|||
p->mark_as_finished(piece_block(0,3), 0);
|
||||
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 1);
|
||||
|
@ -328,7 +329,7 @@ int test_main()
|
|||
|
||||
p->restore_piece(0);
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 1);
|
||||
|
@ -336,10 +337,12 @@ int test_main()
|
|||
|
||||
p->mark_as_finished(piece_block(0,0), 0);
|
||||
p->mark_as_finished(piece_block(0,1), 0);
|
||||
p->mark_as_finished(piece_block(0,2), 0);
|
||||
p->mark_as_finished(piece_block(0,3), 0);
|
||||
p->set_piece_priority(0, 0);
|
||||
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 1);
|
||||
|
@ -347,7 +350,7 @@ int test_main()
|
|||
|
||||
p->restore_piece(0);
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 1);
|
||||
|
@ -355,7 +358,7 @@ int test_main()
|
|||
|
||||
p->set_piece_priority(0, 1);
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 1);
|
||||
|
@ -366,7 +369,7 @@ int test_main()
|
|||
// test non-rarest-first mode
|
||||
p = setup_picker("1234567", "* * * ", "1111122", "");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("****** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, false);
|
||||
p->pick_pieces(string2vec("****** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, false, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() == 3 * blocks_per_piece);
|
||||
|
@ -415,7 +418,7 @@ int test_main()
|
|||
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
|
||||
picked.clear();
|
||||
// make sure it won't pick the piece we just got
|
||||
p->pick_pieces(string2vec(" * ****"), picked, 100, false, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec(" * ****"), picked, 100, false, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 4 * blocks_per_piece);
|
||||
|
@ -468,7 +471,7 @@ int test_main()
|
|||
// test prefer_whole_pieces
|
||||
p = setup_picker("1111111", " ", "", "");
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, true);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, true, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 3 * blocks_per_piece);
|
||||
|
@ -481,7 +484,7 @@ int test_main()
|
|||
}
|
||||
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, false);
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, false, false, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= 3 * blocks_per_piece);
|
||||
|
@ -493,6 +496,35 @@ int test_main()
|
|||
b = picked[i];
|
||||
}
|
||||
|
||||
// ========================================================
|
||||
|
||||
// test parole mode
|
||||
p = setup_picker("3333133", " ", "", "");
|
||||
p->mark_as_finished(piece_block(0, 0), 0);
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, 1, 0, piece_picker::fast, true, true, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= blocks_per_piece - 1);
|
||||
for (int i = 1; i < int(picked.size()); ++i)
|
||||
{
|
||||
TEST_CHECK(picked[i].piece_index == 0);
|
||||
TEST_CHECK(picked[i].block_index == i + 1);
|
||||
}
|
||||
|
||||
// make sure that the partial piece is not picked by a
|
||||
// peer that is has not downloaded/requested the other blocks
|
||||
picked.clear();
|
||||
p->pick_pieces(string2vec("*******"), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
|
||||
print_pick(picked);
|
||||
TEST_CHECK(verify_pick(p, picked));
|
||||
TEST_CHECK(picked.size() >= blocks_per_piece);
|
||||
for (int i = 1; i < int(picked.size()); ++i)
|
||||
{
|
||||
TEST_CHECK(picked[i].piece_index == 4);
|
||||
TEST_CHECK(picked[i].block_index == i);
|
||||
}
|
||||
|
||||
// MISSING TESTS:
|
||||
// 2. inc_ref() from 0 to 1 while sequenced download threshold is 1
|
||||
// 4. filtered_pieces
|
||||
|
|
Loading…
Reference in New Issue