From d8d069675cc93b4fa150c75ec09821f2e8d24ac0 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Tue, 20 Jan 2015 02:34:55 +0000 Subject: [PATCH] improve piece picker to better support torrents with very large pieces and web seeds --- ChangeLog | 3 + include/libtorrent/peer_connection.hpp | 10 +-- include/libtorrent/piece_picker.hpp | 20 +++-- src/http_seed_connection.cpp | 2 +- src/peer_connection.cpp | 7 +- src/piece_picker.cpp | 114 +++++++++++++++---------- src/request_blocks.cpp | 17 ++-- src/web_peer_connection.cpp | 2 +- test/test_piece_picker.cpp | 81 +++++++++++------- 9 files changed, 154 insertions(+), 102 deletions(-) diff --git a/ChangeLog b/ChangeLog index e96157274..4c2fe72b2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ + * improve piece picker to better support torrents with very large pieces + and web seeds. (request large contiguous ranges, but not necessarily a + whole piece). * deprecated session_status and session::status() in favor of performance counters. * improve support for HTTP where one direction of the socket is shut down. diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index e3e39e747..b68503ae1 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -350,18 +350,18 @@ namespace libtorrent void picker_options(int o) { m_picker_options = o; } - int prefer_whole_pieces() const + int prefer_contiguous_blocks() const { if (on_parole()) return 1; - return m_prefer_whole_pieces; + return m_prefer_contiguous_blocks; } bool on_parole() const; int picker_options() const; - void prefer_whole_pieces(int num) - { m_prefer_whole_pieces = num; } + void prefer_contiguous_blocks(int num) + { m_prefer_contiguous_blocks = (std::min)(num, 255); } bool request_large_blocks() const { return m_request_large_blocks; } @@ -1149,7 +1149,7 @@ namespace libtorrent // if it is 0, the download rate limit setting // will be used to determine if whole pieces // are preferred. - boost::uint8_t m_prefer_whole_pieces; + boost::uint8_t m_prefer_contiguous_blocks; // this is the number of times this peer has had // a request rejected because of a disk I/O failure. diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 634ee3aa0..077ca189a 100644 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -156,16 +156,14 @@ namespace libtorrent sequential = 16, // have affinity to pieces with the same speed category speed_affinity = 32, - // ignore the prefer_whole_pieces parameter - ignore_whole_pieces = 64, // treat pieces with priority 6 and below as filtered // to trigger end-game mode until all prio 7 pieces are // completed - time_critical_mode = 128, - // only expands pieces (when prefer whole pieces is set) + time_critical_mode = 64, + // only expands pieces (when prefer contiguous blocks is set) // within properly aligned ranges, not the largest possible // range of pieces. - align_expanded_pieces = 256 + align_expanded_pieces = 128 }; struct downloading_piece @@ -297,9 +295,15 @@ namespace libtorrent // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! // The last argument is the torrent_peer pointer for the peer that // we'll download from. + // prefer_contiguous_blocks indicates how many blocks we would like + // to request contiguously. The blocks are not merged by the piece + // picker, but may be coalesced later by the peer_connection. + // this feature is used by web_peer_connection to request larger blocks + // at a time to mitigate limited pipelining and lack of keep-alive + // (i.e. higher overhead per request). void pick_pieces(bitfield const& pieces , std::vector& interesting_blocks, int num_blocks - , int prefer_whole_pieces, void* peer, piece_state_t speed + , int prefer_contiguous_blocks, void* peer, piece_state_t speed , int options, std::vector const& suggested_pieces , int num_peers , counters& pc @@ -315,7 +319,7 @@ namespace libtorrent , std::vector& interesting_blocks , std::vector& backup_blocks , std::vector& backup_blocks2 - , int num_blocks, int prefer_whole_pieces + , int num_blocks, int prefer_contiguous_blocks , void* peer, std::vector const& ignore , piece_state_t speed, int options) const; @@ -325,7 +329,7 @@ namespace libtorrent , std::vector& interesting_blocks , std::vector& backup_blocks , std::vector& backup_blocks2 - , int num_blocks, int prefer_whole_pieces + , int num_blocks, int prefer_contiguous_blocks , void* peer, piece_state_t speed , int options) const; diff --git a/src/http_seed_connection.cpp b/src/http_seed_connection.cpp index 995660ad7..9afa8fc50 100644 --- a/src/http_seed_connection.cpp +++ b/src/http_seed_connection.cpp @@ -75,7 +75,7 @@ namespace libtorrent max_out_request_queue(m_settings.get_int(settings_pack::urlseed_pipeline_size) * blocks_per_piece); - prefer_whole_pieces(1); + prefer_contiguous_blocks(blocks_per_piece); #ifdef TORRENT_LOGGING peer_log("*** http_seed_connection"); diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index d9a0387b8..444d62a6d 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -182,7 +182,7 @@ namespace libtorrent , m_send_barrier(INT_MAX) , m_desired_queue_size(2) , m_speed(slow) - , m_prefer_whole_pieces(0) + , m_prefer_contiguous_blocks(0) , m_disk_read_failures(0) , m_outstanding_piece_verification(0) , m_outgoing(!pack.tor.expired()) @@ -866,6 +866,11 @@ namespace libtorrent // the common pieces first, just to make // it more likely for all snubbed peers to // request blocks from the same piece + // TODO: 3 this may cause a priority inversion! making a snubbed peer + // open up a new piece may cause that piece to become the highest + // priority. Unless there is some way to mark pieces as low-priority + // this is probably not a good idea. We just want to make all snubbed + // peers pick the same common piece. ret |= piece_picker::reverse; } diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 9cb54ea0d..d0e5a89a0 100644 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -1829,7 +1829,7 @@ namespace libtorrent { if (src.empty()) return num_blocks; int to_copy; -// if (prefer_whole_pieces == 0) +// if (prefer_contiguous_blocks == 0) to_copy = (std::min)(int(src.size()), num_blocks); // else // to_copy = int(src.size()); @@ -1845,7 +1845,7 @@ namespace libtorrent // has. // interesting_blocks is an out parameter, and will be filled // with (up to) num_blocks of interesting blocks that the peer has. - // prefer_whole_pieces can be set if this peer should download + // prefer_contiguous_blocks can be set if this peer should download // whole pieces rather than trying to download blocks from the // same piece as other peers. // the void* is the pointer to the torrent_peer of the peer we're @@ -1874,15 +1874,12 @@ namespace libtorrent // * speed_affinity // have an affinity to pick pieces in the same speed // category. - // * ignore_whole_pieces - // ignores the prefer_whole_pieces parameter (as if - // it was 0) // only one of rarest_first, sequential can be set void piece_picker::pick_pieces(bitfield const& pieces , std::vector& interesting_blocks, int num_blocks - , int prefer_whole_pieces, void* peer, piece_state_t speed + , int prefer_contiguous_blocks, void* peer, piece_state_t speed , int options, std::vector const& suggested_pieces , int num_peers , counters& pc @@ -1900,11 +1897,9 @@ namespace libtorrent // them. In order for this to have an affect, also disable // prefer whole pieces (otherwise partial pieces would be de-prioritized) options |= prioritize_partials; - prefer_whole_pieces = 0; + prefer_contiguous_blocks = 0; } - if (options & ignore_whole_pieces) prefer_whole_pieces = 0; - // only one of rarest_first and sequential can be set. TORRENT_ASSERT(((options & rarest_first) ? 1 : 0) + ((options & sequential) ? 1 : 0) <= 1); @@ -1927,7 +1922,7 @@ namespace libtorrent std::vector backup_blocks2; const std::vector empty_vector; - // When prefer_whole_pieces is set (usually set when downloading from + // When prefer_contiguous_blocks 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 @@ -1950,7 +1945,7 @@ namespace libtorrent num_blocks = add_blocks_downloading(*i, pieces , interesting_blocks, backup_blocks, backup_blocks2 - , num_blocks, prefer_whole_pieces, peer, speed, options); + , num_blocks, prefer_contiguous_blocks, peer, speed, options); if (num_blocks <= 0) return; } @@ -1977,7 +1972,7 @@ namespace libtorrent num_blocks = add_blocks(*i, pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, empty_vector + , prefer_contiguous_blocks, peer, empty_vector , speed, options); if (num_blocks <= 0) return; } @@ -1995,7 +1990,7 @@ namespace libtorrent num_blocks = add_blocks(*i, pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, suggested_pieces + , prefer_contiguous_blocks, peer, suggested_pieces , speed, options); if (num_blocks <= 0) return; } @@ -2014,7 +2009,7 @@ namespace libtorrent num_blocks = add_blocks(i, pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, suggested_pieces + , prefer_contiguous_blocks, peer, suggested_pieces , speed, options); if (num_blocks <= 0) return; } @@ -2030,7 +2025,7 @@ namespace libtorrent num_blocks = add_blocks(i, pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, suggested_pieces + , prefer_contiguous_blocks, peer, suggested_pieces , speed, options); if (num_blocks <= 0) return; } @@ -2073,7 +2068,7 @@ namespace libtorrent num_blocks = add_blocks(m_pieces[p], pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, suggested_pieces + , prefer_contiguous_blocks, peer, suggested_pieces , speed, options); if (num_blocks <= 0) return; } @@ -2099,7 +2094,7 @@ namespace libtorrent num_blocks = add_blocks(*i, pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, suggested_pieces + , prefer_contiguous_blocks, peer, suggested_pieces , speed, options); if (num_blocks <= 0) return; } @@ -2116,7 +2111,7 @@ namespace libtorrent num_blocks = add_blocks(*i, pieces , interesting_blocks, backup_blocks , backup_blocks2, num_blocks - , prefer_whole_pieces, peer, suggested_pieces + , prefer_contiguous_blocks, peer, suggested_pieces , speed, options); if (num_blocks <= 0) return; } @@ -2152,20 +2147,22 @@ namespace libtorrent TORRENT_ASSERT(m_piece_map[piece].downloading() == false); int start, end; - boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces, options); + boost::tie(start, end) = expand_piece(piece + , prefer_contiguous_blocks, pieces, options); for (int k = start; k < end; ++k) { TORRENT_ASSERT(m_piece_map[k].downloading() == false); TORRENT_ASSERT(m_piece_map[k].priority(this) >= 0); int num_blocks_in_piece = blocks_in_piece(k); - if (prefer_whole_pieces == 0 && num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; for (int j = 0; j < num_blocks_in_piece; ++j) { pc.inc_stats_counter(counters::piece_picker_rand_loops); TORRENT_ASSERT(is_piece_free(k, pieces)); interesting_blocks.push_back(piece_block(k, j)); --num_blocks; + --prefer_contiguous_blocks; + if (prefer_contiguous_blocks == 0 + && num_blocks <= 0) break; } } piece = end; @@ -2436,29 +2433,37 @@ namespace libtorrent // blocks from this piece. // the second bool is true if this is the only active peer that is requesting // and downloading blocks from this piece. Active means having a connection. - boost::tuple requested_from(piece_picker::downloading_piece const& p + boost::tuple requested_from(piece_picker::downloading_piece const& p , int num_blocks_in_piece, void* peer) { bool exclusive = true; bool exclusive_active = true; + int contiguous_blocks = 0; + int max_contiguous = 0; for (int j = 0; j < num_blocks_in_piece; ++j) { piece_picker::block_info const& info = p.info[j]; TORRENT_ASSERT(info.peer == 0 || static_cast(info.peer)->in_use); TORRENT_ASSERT(info.piece_index == p.index); - if (info.state != piece_picker::block_info::state_none - && info.peer != peer) + if (info.state == piece_picker::block_info::state_none) + { + ++contiguous_blocks; + continue; + } + max_contiguous = (std::max)(contiguous_blocks, max_contiguous); + contiguous_blocks = 0; + if (info.peer != peer) { exclusive = false; if (info.state == piece_picker::block_info::state_requested && info.peer != 0) { exclusive_active = false; - return boost::make_tuple(exclusive, exclusive_active); } } } - return boost::make_tuple(exclusive, exclusive_active); + max_contiguous = (std::max)(contiguous_blocks, max_contiguous); + return boost::make_tuple(exclusive, exclusive_active, max_contiguous); } } @@ -2467,7 +2472,7 @@ namespace libtorrent , std::vector& interesting_blocks , std::vector& backup_blocks , std::vector& backup_blocks2 - , int num_blocks, int prefer_whole_pieces + , int num_blocks, int prefer_contiguous_blocks , void* peer, std::vector const& ignore , piece_state_t speed, int options) const { @@ -2496,13 +2501,13 @@ namespace libtorrent return add_blocks_downloading(*i, pieces , interesting_blocks, backup_blocks, backup_blocks2 - , num_blocks, prefer_whole_pieces, peer, speed, options); + , num_blocks, prefer_contiguous_blocks, peer, speed, options); } int num_blocks_in_piece = blocks_in_piece(piece); // pick a new piece - if (prefer_whole_pieces == 0) + if (prefer_contiguous_blocks == 0) { if (num_blocks_in_piece > num_blocks) num_blocks_in_piece = num_blocks; @@ -2514,15 +2519,21 @@ namespace libtorrent else { int start, end; - boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces, options); + boost::tie(start, end) = expand_piece(piece, prefer_contiguous_blocks + , pieces, options); for (int k = start; k < end; ++k) { TORRENT_ASSERT(m_piece_map[k].priority(this) > 0); num_blocks_in_piece = blocks_in_piece(k); TORRENT_ASSERT(is_piece_free(k, pieces)); for (int j = 0; j < num_blocks_in_piece; ++j) + { interesting_blocks.push_back(piece_block(k, j)); - num_blocks -= num_blocks_in_piece; + --num_blocks; + --prefer_contiguous_blocks; + if (prefer_contiguous_blocks == 0 + && num_blocks <= 0) break; + } } } #if TORRENT_USE_INVARIANT_CHECKS @@ -2536,7 +2547,7 @@ namespace libtorrent , std::vector& interesting_blocks , std::vector& backup_blocks , std::vector& backup_blocks2 - , int num_blocks, int prefer_whole_pieces + , int num_blocks, int prefer_contiguous_blocks , void* peer, piece_state_t speed, int options) const { if (!pieces[dp.index]) return num_blocks; @@ -2553,7 +2564,8 @@ namespace libtorrent // peer as 'peer'. bool exclusive; bool exclusive_active; - boost::tie(exclusive, exclusive_active) + int contiguous_blocks; + boost::tie(exclusive, exclusive_active, contiguous_blocks) = requested_from(dp, num_blocks_in_piece, peer); // peers on parole are only allowed to pick blocks from @@ -2561,8 +2573,13 @@ namespace libtorrent if ((options & on_parole) && !exclusive) return num_blocks; // we prefer whole blocks, but there are other peers - // downloading from this piece, add it as backups - if (prefer_whole_pieces > 0 && !exclusive_active) + // downloading from this piece and there aren't enough contiguous blocks + // to pick, add it as backups. + // if we're on parole, don't let the contiguous blocks stop us, we want + // to primarily request from a piece all by ourselves. + if (prefer_contiguous_blocks > contiguous_blocks + && !exclusive_active + && (options & on_parole) == 0) { if (int(backup_blocks2.size()) >= num_blocks) return num_blocks; @@ -2609,19 +2626,21 @@ namespace libtorrent continue; } - // this block is interesting (we don't have it - // yet). + // this block is interesting (we don't have it yet). interesting_blocks.push_back(piece_block(dp.index, j)); // we have found a block that's free to download - num_blocks--; - // if we prefer whole pieces, continue picking from this + --num_blocks; + // if we prefer contiguous blocks, continue picking from this // piece even though we have num_blocks - if (prefer_whole_pieces > 0) continue; - TORRENT_ASSERT(num_blocks >= 0); - if (num_blocks <= 0) return num_blocks; + if (prefer_contiguous_blocks > 0) + { + --prefer_contiguous_blocks; + continue; + } + if (num_blocks <= 0) return 0; } - TORRENT_ASSERT(num_blocks >= 0 || prefer_whole_pieces > 0); + TORRENT_ASSERT(num_blocks >= 0 || prefer_contiguous_blocks > 0); if (num_blocks <= 0) return 0; if (options & on_parole) return num_blocks; @@ -2634,10 +2653,15 @@ namespace libtorrent return num_blocks; } - std::pair piece_picker::expand_piece(int piece, int whole_pieces + std::pair piece_picker::expand_piece(int piece, int contiguous_blocks , bitfield const& have, int options) const { - if (whole_pieces == 0) return std::make_pair(piece, piece + 1); + if (contiguous_blocks == 0) return std::make_pair(piece, piece + 1); + + // round to even pieces and expand in order to get the number of + // contiguous pieces we want + int whole_pieces = (contiguous_blocks + m_blocks_per_piece - 1) + / m_blocks_per_piece; int start = piece; int lower_limit; diff --git a/src/request_blocks.cpp b/src/request_blocks.cpp index 2bb4a0446..9e0818133 100644 --- a/src/request_blocks.cpp +++ b/src/request_blocks.cpp @@ -106,13 +106,14 @@ namespace libtorrent std::vector interesting_pieces; interesting_pieces.reserve(100); - int prefer_whole_pieces = c.prefer_whole_pieces(); + int prefer_contiguous_blocks = c.prefer_contiguous_blocks(); - if (prefer_whole_pieces == 0 && !time_critical_mode) + if (prefer_contiguous_blocks == 0 && !time_critical_mode) { - prefer_whole_pieces = c.statistics().download_payload_rate() + int blocks_per_piece = t.torrent_file().piece_length() / t.block_size(); + prefer_contiguous_blocks = c.statistics().download_payload_rate() * t.settings().get_int(settings_pack::whole_pieces_threshold) - > t.torrent_file().piece_length() ? 1 : 0; + > t.torrent_file().piece_length() ? blocks_per_piece : 0; } // if we prefer whole pieces, the piece picker will pick at least @@ -163,13 +164,13 @@ namespace libtorrent // for this peer. If we're downloading one piece in 20 seconds // then use this mode. p.pick_pieces(*bits, interesting_pieces - , num_requests, prefer_whole_pieces, c.peer_info_struct() + , num_requests, prefer_contiguous_blocks, c.peer_info_struct() , state, c.picker_options(), suggested, t.num_peers() , ses.stats_counters()); #ifdef TORRENT_LOGGING - c.peer_log("*** PIECE_PICKER [ prefer_whole: %d picked: %d ]" - , prefer_whole_pieces, int(interesting_pieces.size())); + c.peer_log("*** PIECE_PICKER [ prefer_contiguous: %d picked: %d ]" + , prefer_contiguous_blocks, int(interesting_pieces.size())); #endif // if the number of pieces we have + the number of pieces @@ -192,7 +193,7 @@ namespace libtorrent for (std::vector::iterator i = interesting_pieces.begin(); i != interesting_pieces.end(); ++i) { - if (prefer_whole_pieces == 0 && num_requests <= 0) break; + if (prefer_contiguous_blocks == 0 && num_requests <= 0) break; if (time_critical_mode && p.piece_priority(i->piece_index) != 7) { diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index 841a7d8bc..58041a5f0 100644 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -89,7 +89,7 @@ web_peer_connection::web_peer_connection(peer_connection_args const& pack // request even larger blocks at a time if (!web.supports_keepalive) preferred_size *= 4; - prefer_whole_pieces((std::max)(preferred_size / tor->torrent_file().piece_length(), 1)); + prefer_contiguous_blocks((std::max)(preferred_size / tor->block_size(), 1)); // we want large blocks as well, so // we can request more bytes at once diff --git a/test/test_piece_picker.cpp b/test/test_piece_picker.cpp index 0cf58a023..daf5e0073 100644 --- a/test/test_piece_picker.cpp +++ b/test/test_piece_picker.cpp @@ -246,14 +246,18 @@ void print_title(char const* name) std::cerr << "==== " << name << " ====\n"; } -std::vector pick_pieces(boost::shared_ptr const& p, char const* availability - , int num_blocks, int prefer_whole_pieces, void* peer_struct, piece_picker::piece_state_t state +std::vector pick_pieces(boost::shared_ptr const& p + , char const* availability + , int num_blocks + , int prefer_contiguous_blocks + , void* peer_struct + , piece_picker::piece_state_t state = piece_picker::fast, int options = piece_picker::rarest_first , std::vector const& suggested_pieces = empty_vector) { std::vector picked; counters pc; - p->pick_pieces(string2vec(availability), picked, num_blocks, prefer_whole_pieces, peer_struct + p->pick_pieces(string2vec(availability), picked, num_blocks, prefer_contiguous_blocks, peer_struct , state, options, suggested_pieces, 20, pc); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); @@ -458,20 +462,23 @@ int test_main() // it is not a whole piece print_title("test pick whole pieces"); p = setup_picker("2212222", " ", "1111111", "1023460"); - picked = pick_pieces(p, "****** ", 1, 1, &peer_struct, piece_picker::fast, options, empty_vector); - TEST_CHECK(int(picked.size()) == 3); + picked = pick_pieces(p, "****** ", 1, 1 * blocks_per_piece + , &peer_struct, piece_picker::fast, options, empty_vector); + TEST_EQUAL(int(picked.size()), 3); for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].piece_index == 2); + TEST_EQUAL(picked[i].piece_index, 2); p = setup_picker("1111111", " ", "1111111", ""); - picked = pick_pieces(p, "****** ", 1, 1, &peer_struct, piece_picker::fast, options, empty_vector); - TEST_CHECK(int(picked.size()) == blocks_per_piece); + picked = pick_pieces(p, "****** ", 1, 1 * blocks_per_piece + , &peer_struct, piece_picker::fast, options, empty_vector); + TEST_EQUAL(int(picked.size()), blocks_per_piece); for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].block_index == i); + TEST_EQUAL(picked[i].block_index, i); p = setup_picker("2221222", " ", "", ""); - picked = pick_pieces(p, "*******", 1, 7, &peer_struct, piece_picker::fast, options, empty_vector); - TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece); + picked = pick_pieces(p, "*******", 1, 7 * blocks_per_piece + , &peer_struct, piece_picker::fast, options, empty_vector); + TEST_EQUAL(int(picked.size()), 7 * blocks_per_piece); for (int i = 0; i < int(picked.size()); ++i) TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece)); @@ -867,8 +874,9 @@ int test_main() // make sure we still pick from a partial piece even when prefering whole pieces picked.clear(); - p->pick_pieces(string2vec(" * "), picked, 1, 1, 0 - , piece_picker::fast, piece_picker::rarest_first | piece_picker::align_expanded_pieces, empty_vector, 20 + p->pick_pieces(string2vec(" * "), picked, 1, 1 * blocks_per_piece, 0 + , piece_picker::fast, piece_picker::rarest_first + | piece_picker::align_expanded_pieces, empty_vector, 20 , pc); TEST_CHECK(verify_pick(p, picked, true)); print_pick(picked); @@ -879,7 +887,7 @@ int test_main() // don't pick locked pieces picked.clear(); p->lock_piece(1); - p->pick_pieces(string2vec(" ** "), picked, 7 * blocks_per_piece, 0, 0 + p->pick_pieces(string2vec(" ** "), picked, 7, 0, 0 , piece_picker::fast, piece_picker::rarest_first, empty_vector, 20 , pc); TEST_CHECK(verify_pick(p, picked, true)); @@ -898,7 +906,7 @@ int test_main() p->mark_as_downloading(piece_block(1,3), &tmp1, piece_picker::slow); picked.clear(); - p->pick_pieces(string2vec(" ** "), picked, 2 * blocks_per_piece, 0, 0 + p->pick_pieces(string2vec(" ** "), picked, 2, 0, 0 , piece_picker::fast, piece_picker::rarest_first, empty_vector, 20 , pc); TEST_CHECK(verify_pick(p, picked, true)); @@ -1071,10 +1079,11 @@ int test_main() // ======================================================== - // test prefer_whole_pieces - print_title("test prefer whole pieces"); + // test prefer_contiguous_blocks + print_title("test prefer contiguous blocks"); p = setup_picker("1111111", " ", "", ""); - picked = pick_pieces(p, "*******", 1, 3, 0, piece_picker::fast, options, empty_vector); + picked = pick_pieces(p, "*******", 1, 3 * blocks_per_piece + , 0, piece_picker::fast, options, empty_vector); TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece); piece_block b = picked.front(); for (int i = 1; i < int(picked.size()); ++i) @@ -1084,7 +1093,8 @@ int test_main() b = picked[i]; } - picked = pick_pieces(p, "*******", 1, 3, 0, piece_picker::fast, options, empty_vector); + picked = pick_pieces(p, "*******", 1, 3 * blocks_per_piece + , 0, piece_picker::fast, options, empty_vector); TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece); b = picked.front(); for (int i = 1; i < int(picked.size()); ++i) @@ -1098,21 +1108,21 @@ int test_main() // are picked if there's no other choice p = setup_picker("1111111", " ", "", ""); p->mark_as_downloading(piece_block(2,2), &tmp1, piece_picker::fast); - picked = pick_pieces(p, "*******", 7 * blocks_per_piece - 1, 1, 0 - , piece_picker::fast, options, empty_vector); + picked = pick_pieces(p, "*******", 7 * blocks_per_piece - 1, 1 * blocks_per_piece + , 0, piece_picker::fast, options, empty_vector); TEST_CHECK(picked.size() == 7 * blocks_per_piece - 1); TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(2,2)) == picked.end()); // test aligned whole pieces print_title("test prefer aligned whole pieces"); p = setup_picker("2222221222222222", " ", "", ""); - picked = pick_pieces(p, "****************", 1, 4, 0 + picked = pick_pieces(p, "****************", 1, 4 * blocks_per_piece, 0 , piece_picker::fast, options | piece_picker::align_expanded_pieces, empty_vector); // the piece picker should pick piece 5, and then align it to even 4 pieces // i.e. it should have picked pieces: 4,5,6,7 print_pick(picked); - TEST_CHECK(picked.size() == 4 * blocks_per_piece); + TEST_EQUAL(picked.size() , 4 * blocks_per_piece); std::set picked_pieces; for (std::vector::iterator i = picked.begin() @@ -1131,17 +1141,19 @@ int test_main() print_title("test parole mode"); p = setup_picker("3333133", " ", "", ""); p->mark_as_finished(piece_block(0, 0), 0); - picked = pick_pieces(p, "*******", 1, 1, 0, piece_picker::fast + picked = pick_pieces(p, "*******", 1, 1 * blocks_per_piece, 0 + , piece_picker::fast , options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector); - TEST_CHECK(int(picked.size()) == blocks_per_piece - 1); + TEST_EQUAL(int(picked.size()), blocks_per_piece - 1); for (int i = 1; i < int(picked.size()); ++i) TEST_CHECK(picked[i] == piece_block(0, i + 1)); // make sure that the partial piece is not picked by a // peer that is has not downloaded/requested the other blocks - picked = pick_pieces(p, "*******", 1, 1, &peer_struct, piece_picker::fast + picked = pick_pieces(p, "*******", 1, 1 * blocks_per_piece + , &peer_struct, piece_picker::fast , options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector); - TEST_CHECK(int(picked.size()) == blocks_per_piece); + TEST_EQUAL(int(picked.size()), blocks_per_piece); for (int i = 1; i < int(picked.size()); ++i) TEST_CHECK(picked[i] == piece_block(4, i)); @@ -1153,7 +1165,8 @@ int test_main() int v[] = {1, 5}; std::vector suggested_pieces(v, v + 2); - picked = pick_pieces(p, "****************", 1, 1, 0, piece_picker::fast, options, suggested_pieces); + picked = pick_pieces(p, "****************", 1, 1 * blocks_per_piece + , 0, piece_picker::fast, options, suggested_pieces); TEST_CHECK(int(picked.size()) >= blocks_per_piece); for (int i = 1; i < int(picked.size()); ++i) TEST_CHECK(picked[i] == piece_block(1, i)); @@ -1162,13 +1175,15 @@ int test_main() p->set_piece_priority(2, 0); p->set_piece_priority(3, 0); - picked = pick_pieces(p, "****************", 1, 1, 0, piece_picker::fast, options, suggested_pieces); + picked = pick_pieces(p, "****************", 1, 1 * blocks_per_piece + , 0, piece_picker::fast, options, suggested_pieces); TEST_CHECK(int(picked.size()) >= blocks_per_piece); for (int i = 1; i < int(picked.size()); ++i) TEST_CHECK(picked[i] == piece_block(5, i)); p = setup_picker("1111222233334444", "**** ", "", ""); - picked = pick_pieces(p, "****************", 1, 1, 0, piece_picker::fast, options, suggested_pieces); + picked = pick_pieces(p, "****************", 1, 1 * blocks_per_piece + , 0, piece_picker::fast, options, suggested_pieces); TEST_CHECK(int(picked.size()) >= blocks_per_piece); for (int i = 1; i < int(picked.size()); ++i) TEST_CHECK(picked[i] == piece_block(5, i)); @@ -1180,13 +1195,13 @@ int test_main() // we have less than half of the pieces p = setup_picker("2122222211221222", " ", "", ""); // make sure it's not dirty - pick_pieces(p, "****************", 1, 1, 0); + pick_pieces(p, "****************", 1, 1 * blocks_per_piece, 0); print_availability(p); p->dec_refcount(string2vec("** ** ** * "), &tmp0); print_availability(p); TEST_CHECK(verify_availability(p, "1022112200220222")); // make sure it's not dirty - pick_pieces(p, "****************", 1, 1, 0); + pick_pieces(p, "****************", 1, 1 * blocks_per_piece, 0); p->inc_refcount(string2vec(" ** ** * * "), &tmp8); print_availability(p); TEST_CHECK(verify_availability(p, "1132123201220322")); @@ -1198,7 +1213,7 @@ int test_main() p = setup_picker("0000000000000000", " ", "", ""); // make sure it's not dirty - pick_pieces(p, "****************", 1, 1, 0); + pick_pieces(p, "****************", 1, 1 * blocks_per_piece, 0); p->inc_refcount_all(&tmp0); print_availability(p);