From 6d40519e66cf9bf227d975e7b99e81b6efa93f35 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 3 Sep 2007 21:16:24 +0000 Subject: [PATCH] added support for piece picker to pick multiple pieces (previously it could only pick one piece tops). Made the web_peer_connection always try to make 1 MB requests at a time. added tests to the piece_picker unit test --- include/libtorrent/peer_connection.hpp | 21 +++-- include/libtorrent/piece_picker.hpp | 11 ++- src/peer_connection.cpp | 30 ++++--- src/piece_picker.cpp | 101 ++++++++++++++++------ src/policy.cpp | 25 +++--- src/web_peer_connection.cpp | 25 ++++-- test/test_piece_picker.cpp | 113 ++++++++++++++++--------- 7 files changed, 214 insertions(+), 112 deletions(-) diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index ad02606e7..7f6bce29a 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -152,11 +152,15 @@ namespace libtorrent int upload_limit() const { return m_upload_limit; } int download_limit() const { return m_download_limit; } - bool prefer_whole_pieces() const - { return m_prefer_whole_pieces; } + int prefer_whole_pieces() const + { + if (m_prefer_whole_pieces == 0) + return peer_info_struct() && peer_info_struct()->on_parole ? 1 : 0; + return m_prefer_whole_pieces; + } - void prefer_whole_pieces(bool b) - { m_prefer_whole_pieces = b; } + void prefer_whole_pieces(int num) + { m_prefer_whole_pieces = num; } bool request_large_blocks() const { return m_request_large_blocks; } @@ -665,12 +669,13 @@ namespace libtorrent bool m_writing; bool m_reading; - // if set to true, this peer will always prefer - // to request entire pieces, rather than blocks. - // if it is false, the download rate limit setting + // if set to non-zero, this peer will always prefer + // to request entire n pieces, rather than blocks. + // where n is the value of this variable. + // if it is 0, the download rate limit setting // will be used to determine if whole pieces // are preferred. - bool m_prefer_whole_pieces; + int m_prefer_whole_pieces; // if this is true, the blocks picked by the piece // picker will be merged before passed to the diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 4305c2dde..1bbe63332 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -191,9 +191,9 @@ namespace libtorrent // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! // The last argument is the policy::peer pointer for the peer that // we'll download from. - void pick_pieces(const std::vector& pieces + void pick_pieces(std::vector const& pieces , std::vector& interesting_blocks - , int num_pieces, bool prefer_whole_pieces + , int num_pieces, int prefer_whole_pieces , void* peer, piece_state_t speed , bool rarest_first) const; @@ -202,11 +202,11 @@ namespace libtorrent // 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(const std::vector& piece_list + int add_interesting_blocks(std::vector const& piece_list , const std::vector& pieces , std::vector& interesting_blocks , std::vector& backup_blocks - , int num_blocks, bool prefer_whole_pieces + , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed , bool ignore_downloading_pieces) const; @@ -284,6 +284,9 @@ namespace libtorrent private: + std::pair expand_piece(int piece, int whole_pieces + , std::vector const& have) const; + struct piece_pos { piece_pos() {} diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 8255478bc..afdf6e168 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -521,6 +521,7 @@ namespace libtorrent assert(t); assert(t->valid_metadata()); + torrent_info const& ti = t->torrent_file(); return p.piece >= 0 && p.piece < t->torrent_file().num_pieces() @@ -528,11 +529,13 @@ namespace libtorrent && p.start >= 0 && (p.length == t->block_size() || (p.length < t->block_size() - && p.piece == t->torrent_file().num_pieces()-1 - && p.start + p.length == t->torrent_file().piece_size(p.piece)) + && p.piece == ti.num_pieces()-1 + && p.start + p.length == ti.piece_size(p.piece)) || (m_request_large_blocks - && p.length <= t->torrent_file().piece_size(p.piece))) - && p.start + p.length <= t->torrent_file().piece_size(p.piece) + && p.length <= ti.piece_length() * m_prefer_whole_pieces == 0 ? + 1 : m_prefer_whole_pieces)) + && p.piece * int64_t(ti.piece_length()) + p.start + p.length + <= ti.total_size() && (p.start % t->block_size() == 0); } @@ -1623,6 +1626,7 @@ namespace libtorrent assert(block.block_index >= 0); assert(block.block_index < t->torrent_file().piece_size(block.piece_index)); assert(!t->picker().is_requested(block) || (t->picker().num_peers(block) > 0)); + assert(!t->have_piece(block.piece_index)); piece_picker::piece_state_t state; peer_speed_t speed = peer_speed(); @@ -1815,21 +1819,27 @@ namespace libtorrent // blocks that are in the same piece into larger requests if (m_request_large_blocks) { - while (!m_request_queue.empty() - && m_request_queue.front().piece_index == r.piece - && m_request_queue.front().block_index == block.block_index + 1) + int blocks_per_piece = t->torrent_file().piece_length() / t->block_size(); + + while (!m_request_queue.empty()) { + // check to see if this block is connected to the previous one + // if it is, merge them, otherwise, break this merge loop + piece_block const& front = m_request_queue.front(); + if (front.piece_index * blocks_per_piece + front.block_index + != block.piece_index * blocks_per_piece + block.block_index + 1) + break; block = m_request_queue.front(); m_request_queue.pop_front(); m_download_queue.push_back(block); -/* + #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() - << " *** REQUEST-QUEUE** [ " + << " *** MERGING REQUEST ** [ " "piece: " << block.piece_index << " | " "block: " << block.block_index << " ]\n"; #endif -*/ + block_offset = block.block_index * t->block_size(); block_size = (std::min)((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 3447b63f5..a7debe712 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -1079,7 +1079,7 @@ namespace libtorrent // or slow once they're started. void piece_picker::pick_pieces(const std::vector& pieces , std::vector& interesting_blocks - , int num_blocks, bool prefer_whole_pieces + , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed, bool rarest_first) const { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -1102,7 +1102,7 @@ namespace libtorrent // 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 || !rarest_first) + if (prefer_whole_pieces > 0 || !rarest_first) { std::vector downloading_pieces; downloading_pieces.reserve(m_downloads.size()); @@ -1111,7 +1111,7 @@ namespace libtorrent { downloading_pieces.push_back(i->index); } - if (prefer_whole_pieces) + if (prefer_whole_pieces > 0) { add_interesting_blocks(downloading_pieces, pieces , backup_blocks, backup_blocks, num_blocks @@ -1159,8 +1159,9 @@ namespace libtorrent while (num_blocks > 0) { while (!pieces[piece] - || m_piece_map[piece].index == piece_pos::we_have_index - || m_piece_map[piece].downloading) + || m_piece_map[piece].have() + || m_piece_map[piece].downloading + || m_piece_map[piece].filtered()) { ++piece; if (piece == int(m_piece_map.size())) piece = 0; @@ -1170,14 +1171,20 @@ namespace libtorrent assert(m_piece_map[piece].downloading == false); - int num_blocks_in_piece = blocks_in_piece(piece); - - if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; - for (int j = 0; j < num_blocks_in_piece; ++j) - interesting_blocks.push_back(piece_block(piece, j)); - num_blocks -= (std::min)(num_blocks_in_piece, num_blocks); - ++piece; + int start, end; + boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces); + for (int k = start; k < end; ++k) + { + 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) + { + interesting_blocks.push_back(piece_block(k, j)); + --num_blocks; + } + } + piece = end; if (piece == int(m_piece_map.size())) piece = 0; // could not find any more pieces if (piece == start_piece) return; @@ -1233,7 +1240,7 @@ namespace libtorrent , std::vector const& pieces , std::vector& interesting_blocks , std::vector& backup_blocks - , int num_blocks, bool prefer_whole_pieces + , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed , bool ignore_downloading_pieces) const { @@ -1277,7 +1284,7 @@ namespace libtorrent // blocks to the backup list. If the prioritized // blocks aren't enough, blocks from this list // will be picked. - if (prefer_whole_pieces && !exclusive) + if (prefer_whole_pieces > 0 && !exclusive) { for (int j = 0; j < num_blocks_in_piece; ++j) { @@ -1332,7 +1339,7 @@ namespace libtorrent num_blocks--; // if we prefer whole pieces, continue picking from this // piece even though we have num_blocks - if (prefer_whole_pieces) continue; + if (prefer_whole_pieces > 0) continue; assert(num_blocks >= 0); if (num_blocks == 0) return num_blocks; } @@ -1341,23 +1348,68 @@ namespace libtorrent backup_blocks.push_back(piece_block(*i, j)); } } - assert(num_blocks >= 0 || prefer_whole_pieces); + assert(num_blocks >= 0 || prefer_whole_pieces > 0); if (num_blocks < 0) num_blocks = 0; } else { - if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; - for (int j = 0; j < num_blocks_in_piece; ++j) - interesting_blocks.push_back(piece_block(*i, j)); - num_blocks -= (std::min)(num_blocks_in_piece, num_blocks); + // pick a new piece + if (prefer_whole_pieces == 0) + { + if (num_blocks_in_piece > num_blocks) + num_blocks_in_piece = num_blocks; + 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; + } + } + } } - assert(num_blocks >= 0); - if (num_blocks == 0) return num_blocks; + if (num_blocks <= 0) return num_blocks < 0 ? 0 : num_blocks; } return num_blocks; } + std::pair piece_picker::expand_piece(int piece, int whole_pieces + , std::vector const& have) const + { + if (whole_pieces == 0) return std::make_pair(piece, piece + 1); + + int start = piece - 1; + int lower_limit = piece - whole_pieces; + if (lower_limit < -1) lower_limit = -1; + while (start > lower_limit + && have[start] + && !m_piece_map[start].downloading + && !m_piece_map[start].filtered() + && !m_piece_map[start].have()) + --start; + ++start; + assert(start >= 0); + int end = piece + 1; + int upper_limit = start + whole_pieces; + if (upper_limit > int(m_piece_map.size())) upper_limit = int(m_piece_map.size()); + while (end < upper_limit + && have[end] + && !m_piece_map[end].downloading + && !m_piece_map[end].filtered() + && !m_piece_map[end].have()) + ++end; + return std::make_pair(start, end); + } + bool piece_picker::is_piece_finished(int index) const { assert(index < (int)m_piece_map.size()); @@ -1443,6 +1495,7 @@ namespace libtorrent assert(block.block_index >= 0); assert(block.piece_index < (int)m_piece_map.size()); assert(block.block_index < blocks_in_piece(block.piece_index)); + assert(!m_piece_map[block.piece_index].have()); piece_pos& p = m_piece_map[block.piece_index]; if (p.downloading == 0) diff --git a/src/policy.cpp b/src/policy.cpp index 4302c2890..f728b3030 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -209,16 +209,15 @@ namespace libtorrent std::vector interesting_pieces; interesting_pieces.reserve(100); - bool prefer_whole_pieces = c.prefer_whole_pieces() - || (c.peer_info_struct() && c.peer_info_struct()->on_parole); + int prefer_whole_pieces = c.prefer_whole_pieces(); bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold; - if (!prefer_whole_pieces) + if (prefer_whole_pieces == 0) { prefer_whole_pieces = c.statistics().download_payload_rate() * t.settings().whole_pieces_threshold - > t.torrent_file().piece_length(); + > t.torrent_file().piece_length() ? 1 : 0; } // if we prefer whole pieces, the piece picker will pick at least @@ -265,12 +264,9 @@ namespace libtorrent std::vector 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); - interesting_pieces.insert(interesting_pieces.end() - , busy_pieces.begin(), busy_pieces.end()); - busy_pieces.clear(); + , interesting_pieces, busy_pieces, num_requests + , prefer_whole_pieces, c.peer_info_struct(), state + , false); } // picks the interesting pieces from this peer @@ -285,13 +281,14 @@ namespace libtorrent p.pick_pieces(c.get_bitfield(), interesting_pieces , num_requests, prefer_whole_pieces, c.peer_info_struct() , state, rarest_first); - - busy_pieces.reserve(10); } #ifdef TORRENT_VERBOSE_LOGGING - (*c.m_logger) << time_now_string() << " PIECE_PICKER [ picked: " << interesting_pieces.size() << " ]\n"; + (*c.m_logger) << time_now_string() << " PIECE_PICKER [ php: " << prefer_whole_pieces + << " picked: " << interesting_pieces.size() << " ]\n"; #endif + std::deque const& dq = c.download_queue(); + std::deque const& rq = c.request_queue(); for (std::vector::iterator i = interesting_pieces.begin(); i != interesting_pieces.end(); ++i) { @@ -299,8 +296,6 @@ namespace libtorrent { if (num_requests <= 0) break; // don't request pieces we already have in our request queue - const std::deque& dq = c.download_queue(); - const std::deque& rq = c.request_queue(); if (std::find(dq.begin(), dq.end(), *i) != dq.end() || std::find(rq.begin(), rq.end(), *i) != rq.end()) continue; diff --git a/src/web_peer_connection.cpp b/src/web_peer_connection.cpp index cddb35e42..df7a8a685 100755 --- a/src/web_peer_connection.cpp +++ b/src/web_peer_connection.cpp @@ -69,9 +69,6 @@ namespace libtorrent { INVARIANT_CHECK; - // we always prefer downloading entire - // pieces from web seeds - prefer_whole_pieces(true); // we want large blocks as well, so // we can request more bytes at once request_large_blocks(true); @@ -80,6 +77,10 @@ namespace libtorrent shared_ptr tor = t.lock(); assert(tor); int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size(); + + // we always prefer downloading 1 MB chunks + // from web seeds + prefer_whole_pieces((1024 * 1024) / tor->torrent_file().piece_length()); // multiply with the blocks per piece since that many requests are // merged into one http request @@ -178,13 +179,16 @@ namespace libtorrent int size = r.length; const int block_size = t->block_size(); + const int piece_size = t->torrent_file().piece_length(); + peer_request pr; while (size > 0) { - int request_size = (std::min)(block_size, size); - peer_request pr = {r.piece, r.start + r.length - size - , request_size}; + int request_offset = r.start + r.length - size; + pr.start = request_offset % piece_size; + pr.length = (std::min)(block_size, size); + pr.piece = r.piece + request_offset / piece_size; m_requests.push_back(pr); - size -= request_size; + size -= pr.length; } proxy_settings const& ps = m_ses.web_seed_proxy(); @@ -477,8 +481,11 @@ namespace libtorrent peer_request front_request = m_requests.front(); - if (in_range.piece != front_request.piece - || in_range.start > front_request.start + int(m_piece.size())) + size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start; + size_type re = rs + in_range.length; + size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start; + size_type fe = fs + front_request.length; + if (fs < rs || fe > re) { throw std::runtime_error("invalid range in HTTP response"); } diff --git a/test/test_piece_picker.cpp b/test/test_piece_picker.cpp index 3e994de98..b55fd8bbc 100644 --- a/test/test_piece_picker.cpp +++ b/test/test_piece_picker.cpp @@ -10,6 +10,8 @@ using namespace libtorrent; +const int blocks_per_piece = 4; + std::vector string2vec(char const* have_str) { const int num_pieces = strlen(have_str); @@ -30,7 +32,6 @@ boost::shared_ptr setup_picker( , char const* priority , char const* partial) { - const int blocks_per_piece = 4; const int num_pieces = strlen(availability); assert(int(strlen(have_str)) == num_pieces); @@ -183,10 +184,10 @@ 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, true, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("****** "), picked, 1, 1, 0, piece_picker::fast, true); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() >= 4); - for (int i = 0; i < 4 && i < int(picked.size()); ++i) + TEST_CHECK(int(picked.size()) >= blocks_per_piece); + for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i) TEST_CHECK(picked[i].piece_index == 1); // ======================================================== @@ -233,48 +234,48 @@ int test_main() p = setup_picker("7654321", " ", "", ""); picked.clear(); p->set_sequenced_download_threshold(3); - p->pick_pieces(string2vec("***** "), picked, 5 * 4, false, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("***** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 5 * 4); - for (int i = 0; i < 5 * 4 && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].piece_index == i / 4); + TEST_CHECK(picked.size() == 5 * blocks_per_piece); + for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i) + TEST_CHECK(picked[i].piece_index == i / blocks_per_piece); picked.clear(); p->set_sequenced_download_threshold(4); - p->pick_pieces(string2vec("**** "), picked, 5 * 4, false, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("**** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 4 * 4); - for (int i = 0; i < 4 * 4 && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].piece_index == i / 4); + TEST_CHECK(picked.size() == 4 * blocks_per_piece); + for (int i = 0; i < 4 * blocks_per_piece && i < int(picked.size()); ++i) + TEST_CHECK(picked[i].piece_index == i / blocks_per_piece); picked.clear(); p->set_sequenced_download_threshold(2); - p->pick_pieces(string2vec("****** "), picked, 6 * 4, false, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 6 * 4); - for (int i = 0; i < 6 * 4 && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].piece_index == i / 4); + TEST_CHECK(picked.size() == 6 * blocks_per_piece); + for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i) + TEST_CHECK(picked[i].piece_index == i / blocks_per_piece); picked.clear(); p->set_piece_priority(0, 0); - p->pick_pieces(string2vec("****** "), picked, 6 * 4, false, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 5 * 4); - for (int i = 0; i < 5 * 4 && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].piece_index == i / 4 + 1); + TEST_CHECK(picked.size() == 5 * blocks_per_piece); + for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i) + TEST_CHECK(picked[i].piece_index == i / blocks_per_piece + 1); picked.clear(); p->set_piece_priority(0, 1); - p->pick_pieces(string2vec("****** "), picked, 6 * 4, false, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 6 * 4); - for (int i = 0; i < 6 * 4 && i < int(picked.size()); ++i) - TEST_CHECK(picked[i].piece_index == i / 4); + TEST_CHECK(picked.size() == 6 * blocks_per_piece); + for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i) + TEST_CHECK(picked[i].piece_index == i / blocks_per_piece); // ======================================================== @@ -291,17 +292,17 @@ int test_main() TEST_CHECK(p->num_have_filtered() == 1); picked.clear(); - p->pick_pieces(string2vec("*******"), picked, 6 * 4, false, 0, piece_picker::fast, true); + p->pick_pieces(string2vec("*******"), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 6 * 4); - TEST_CHECK(picked[0].piece_index == 5); + TEST_CHECK(picked.size() == 6 * blocks_per_piece); + TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 5); // priority 5 and 6 is currently the same - TEST_CHECK(picked[4].piece_index == 6 || picked[4].piece_index == 4); - TEST_CHECK(picked[8].piece_index == 6 || picked[8].piece_index == 4); - TEST_CHECK(picked[12].piece_index == 3); - TEST_CHECK(picked[16].piece_index == 1); - TEST_CHECK(picked[20].piece_index == 2); + TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 6 || picked[1 * blocks_per_piece].piece_index == 4); + TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 6 || picked[2 * blocks_per_piece].piece_index == 4); + TEST_CHECK(picked[3 * blocks_per_piece].piece_index == 3); + TEST_CHECK(picked[4 * blocks_per_piece].piece_index == 1); + TEST_CHECK(picked[5 * blocks_per_piece].piece_index == 2); std::vector prios; p->piece_priorities(prios); @@ -365,12 +366,12 @@ int test_main() // test non-rarest-first mode p = setup_picker("1234567", "* * * ", "1111122", ""); picked.clear(); - p->pick_pieces(string2vec("****** "), picked, 5 * 4, false, 0, piece_picker::fast, false); + p->pick_pieces(string2vec("****** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, false); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() == 3 * 4); + TEST_CHECK(picked.size() == 3 * blocks_per_piece); - for (int i = 0; i < 4 * 4 && i < int(picked.size()); ++i) + for (int i = 0; i < 4 * blocks_per_piece && i < int(picked.size()); ++i) { TEST_CHECK(picked[i].piece_index != 0); TEST_CHECK(picked[i].piece_index != 2); @@ -393,8 +394,6 @@ int test_main() std::cout << "distributed copies: " << dc << std::endl; TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f); - - // ======================================================== // test have_all and have_none, with a sequenced download threshold @@ -419,11 +418,11 @@ int test_main() p->pick_pieces(string2vec(" * ****"), picked, 100, false, 0, piece_picker::fast, true); print_pick(picked); TEST_CHECK(verify_pick(p, picked)); - TEST_CHECK(picked.size() >= 4 * 4); - TEST_CHECK(picked[0].piece_index == 3); - TEST_CHECK(picked[4].piece_index == 4); - TEST_CHECK(picked[8].piece_index == 5); - TEST_CHECK(picked[12].piece_index == 6); + TEST_CHECK(picked.size() >= 4 * blocks_per_piece); + TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 3); + TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 4); + TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 5); + TEST_CHECK(picked[3 * blocks_per_piece].piece_index == 6); // ======================================================== @@ -464,6 +463,36 @@ int test_main() TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0); TEST_CHECK(p->unverified_blocks() == 2); +// ======================================================== + + // test prefer_whole_pieces + p = setup_picker("1111111", " ", "", ""); + picked.clear(); + p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, true); + print_pick(picked); + TEST_CHECK(verify_pick(p, picked)); + TEST_CHECK(picked.size() >= 3 * blocks_per_piece); + piece_block b = picked.front(); + for (int i = 1; i < int(picked.size()); ++i) + { + TEST_CHECK(picked[i].piece_index * blocks_per_piece + picked[i].block_index + == b.piece_index * blocks_per_piece + b.block_index + 1); + b = picked[i]; + } + + picked.clear(); + p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, false); + print_pick(picked); + TEST_CHECK(verify_pick(p, picked)); + TEST_CHECK(picked.size() >= 3 * blocks_per_piece); + b = picked.front(); + for (int i = 1; i < int(picked.size()); ++i) + { + TEST_CHECK(picked[i].piece_index * blocks_per_piece + picked[i].block_index + == b.piece_index * blocks_per_piece + b.block_index + 1); + b = picked[i]; + } + // MISSING TESTS: // 2. inc_ref() from 0 to 1 while sequenced download threshold is 1 // 4. filtered_pieces