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
This commit is contained in:
parent
5fc49a6cf4
commit
6d40519e66
|
@ -152,11 +152,15 @@ namespace libtorrent
|
||||||
int upload_limit() const { return m_upload_limit; }
|
int upload_limit() const { return m_upload_limit; }
|
||||||
int download_limit() const { return m_download_limit; }
|
int download_limit() const { return m_download_limit; }
|
||||||
|
|
||||||
bool prefer_whole_pieces() const
|
int prefer_whole_pieces() const
|
||||||
{ return m_prefer_whole_pieces; }
|
{
|
||||||
|
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)
|
void prefer_whole_pieces(int num)
|
||||||
{ m_prefer_whole_pieces = b; }
|
{ m_prefer_whole_pieces = num; }
|
||||||
|
|
||||||
bool request_large_blocks() const
|
bool request_large_blocks() const
|
||||||
{ return m_request_large_blocks; }
|
{ return m_request_large_blocks; }
|
||||||
|
@ -665,12 +669,13 @@ namespace libtorrent
|
||||||
bool m_writing;
|
bool m_writing;
|
||||||
bool m_reading;
|
bool m_reading;
|
||||||
|
|
||||||
// if set to true, this peer will always prefer
|
// if set to non-zero, this peer will always prefer
|
||||||
// to request entire pieces, rather than blocks.
|
// to request entire n pieces, rather than blocks.
|
||||||
// if it is false, the download rate limit setting
|
// 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
|
// will be used to determine if whole pieces
|
||||||
// are preferred.
|
// are preferred.
|
||||||
bool m_prefer_whole_pieces;
|
int m_prefer_whole_pieces;
|
||||||
|
|
||||||
// if this is true, the blocks picked by the piece
|
// if this is true, the blocks picked by the piece
|
||||||
// picker will be merged before passed to the
|
// picker will be merged before passed to the
|
||||||
|
|
|
@ -191,9 +191,9 @@ namespace libtorrent
|
||||||
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
// THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
|
||||||
// The last argument is the policy::peer pointer for the peer that
|
// The last argument is the policy::peer pointer for the peer that
|
||||||
// we'll download from.
|
// we'll download from.
|
||||||
void pick_pieces(const std::vector<bool>& pieces
|
void pick_pieces(std::vector<bool> const& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, int num_pieces, bool prefer_whole_pieces
|
, int num_pieces, int prefer_whole_pieces
|
||||||
, void* peer, piece_state_t speed
|
, void* peer, piece_state_t speed
|
||||||
, bool rarest_first) const;
|
, bool rarest_first) const;
|
||||||
|
|
||||||
|
@ -202,11 +202,11 @@ namespace libtorrent
|
||||||
// are added to interesting_blocks, and busy blocks are
|
// are added to interesting_blocks, and busy blocks are
|
||||||
// added to backup_blocks. num blocks is the number of
|
// added to backup_blocks. num blocks is the number of
|
||||||
// blocks to be picked.
|
// blocks to be picked.
|
||||||
int add_interesting_blocks(const std::vector<int>& piece_list
|
int add_interesting_blocks(std::vector<int> const& piece_list
|
||||||
, const std::vector<bool>& pieces
|
, const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, std::vector<piece_block>& backup_blocks
|
, std::vector<piece_block>& backup_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, int prefer_whole_pieces
|
||||||
, void* peer, piece_state_t speed
|
, void* peer, piece_state_t speed
|
||||||
, bool ignore_downloading_pieces) const;
|
, bool ignore_downloading_pieces) const;
|
||||||
|
|
||||||
|
@ -284,6 +284,9 @@ namespace libtorrent
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::pair<int, int> expand_piece(int piece, int whole_pieces
|
||||||
|
, std::vector<bool> const& have) const;
|
||||||
|
|
||||||
struct piece_pos
|
struct piece_pos
|
||||||
{
|
{
|
||||||
piece_pos() {}
|
piece_pos() {}
|
||||||
|
|
|
@ -521,6 +521,7 @@ namespace libtorrent
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
assert(t->valid_metadata());
|
assert(t->valid_metadata());
|
||||||
|
torrent_info const& ti = t->torrent_file();
|
||||||
|
|
||||||
return p.piece >= 0
|
return p.piece >= 0
|
||||||
&& p.piece < t->torrent_file().num_pieces()
|
&& p.piece < t->torrent_file().num_pieces()
|
||||||
|
@ -528,11 +529,13 @@ namespace libtorrent
|
||||||
&& p.start >= 0
|
&& p.start >= 0
|
||||||
&& (p.length == t->block_size()
|
&& (p.length == t->block_size()
|
||||||
|| (p.length < t->block_size()
|
|| (p.length < t->block_size()
|
||||||
&& p.piece == t->torrent_file().num_pieces()-1
|
&& p.piece == ti.num_pieces()-1
|
||||||
&& p.start + p.length == t->torrent_file().piece_size(p.piece))
|
&& p.start + p.length == ti.piece_size(p.piece))
|
||||||
|| (m_request_large_blocks
|
|| (m_request_large_blocks
|
||||||
&& p.length <= t->torrent_file().piece_size(p.piece)))
|
&& p.length <= ti.piece_length() * m_prefer_whole_pieces == 0 ?
|
||||||
&& p.start + p.length <= t->torrent_file().piece_size(p.piece)
|
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);
|
&& (p.start % t->block_size() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1623,6 +1626,7 @@ namespace libtorrent
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
|
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->picker().is_requested(block) || (t->picker().num_peers(block) > 0));
|
||||||
|
assert(!t->have_piece(block.piece_index));
|
||||||
|
|
||||||
piece_picker::piece_state_t state;
|
piece_picker::piece_state_t state;
|
||||||
peer_speed_t speed = peer_speed();
|
peer_speed_t speed = peer_speed();
|
||||||
|
@ -1815,21 +1819,27 @@ namespace libtorrent
|
||||||
// blocks that are in the same piece into larger requests
|
// blocks that are in the same piece into larger requests
|
||||||
if (m_request_large_blocks)
|
if (m_request_large_blocks)
|
||||||
{
|
{
|
||||||
while (!m_request_queue.empty()
|
int blocks_per_piece = t->torrent_file().piece_length() / t->block_size();
|
||||||
&& m_request_queue.front().piece_index == r.piece
|
|
||||||
&& m_request_queue.front().block_index == block.block_index + 1)
|
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();
|
block = m_request_queue.front();
|
||||||
m_request_queue.pop_front();
|
m_request_queue.pop_front();
|
||||||
m_download_queue.push_back(block);
|
m_download_queue.push_back(block);
|
||||||
/*
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
(*m_logger) << time_now_string()
|
(*m_logger) << time_now_string()
|
||||||
<< " *** REQUEST-QUEUE** [ "
|
<< " *** MERGING REQUEST ** [ "
|
||||||
"piece: " << block.piece_index << " | "
|
"piece: " << block.piece_index << " | "
|
||||||
"block: " << block.block_index << " ]\n";
|
"block: " << block.block_index << " ]\n";
|
||||||
#endif
|
#endif
|
||||||
*/
|
|
||||||
block_offset = block.block_index * t->block_size();
|
block_offset = block.block_index * t->block_size();
|
||||||
block_size = (std::min)((int)t->torrent_file().piece_size(
|
block_size = (std::min)((int)t->torrent_file().piece_size(
|
||||||
block.piece_index) - block_offset, t->block_size());
|
block.piece_index) - block_offset, t->block_size());
|
||||||
|
|
|
@ -1079,7 +1079,7 @@ namespace libtorrent
|
||||||
// or slow once they're started.
|
// or slow once they're started.
|
||||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& 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
|
, void* peer, piece_state_t speed, bool rarest_first) const
|
||||||
{
|
{
|
||||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||||
|
@ -1102,7 +1102,7 @@ namespace libtorrent
|
||||||
// ignored as long as possible. All blocks found in downloading
|
// ignored as long as possible. All blocks found in downloading
|
||||||
// pieces are regarded as backup blocks
|
// pieces are regarded as backup blocks
|
||||||
bool ignore_downloading_pieces = false;
|
bool ignore_downloading_pieces = false;
|
||||||
if (prefer_whole_pieces || !rarest_first)
|
if (prefer_whole_pieces > 0 || !rarest_first)
|
||||||
{
|
{
|
||||||
std::vector<int> downloading_pieces;
|
std::vector<int> downloading_pieces;
|
||||||
downloading_pieces.reserve(m_downloads.size());
|
downloading_pieces.reserve(m_downloads.size());
|
||||||
|
@ -1111,7 +1111,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
downloading_pieces.push_back(i->index);
|
downloading_pieces.push_back(i->index);
|
||||||
}
|
}
|
||||||
if (prefer_whole_pieces)
|
if (prefer_whole_pieces > 0)
|
||||||
{
|
{
|
||||||
add_interesting_blocks(downloading_pieces, pieces
|
add_interesting_blocks(downloading_pieces, pieces
|
||||||
, backup_blocks, backup_blocks, num_blocks
|
, backup_blocks, backup_blocks, num_blocks
|
||||||
|
@ -1159,8 +1159,9 @@ namespace libtorrent
|
||||||
while (num_blocks > 0)
|
while (num_blocks > 0)
|
||||||
{
|
{
|
||||||
while (!pieces[piece]
|
while (!pieces[piece]
|
||||||
|| m_piece_map[piece].index == piece_pos::we_have_index
|
|| m_piece_map[piece].have()
|
||||||
|| m_piece_map[piece].downloading)
|
|| m_piece_map[piece].downloading
|
||||||
|
|| m_piece_map[piece].filtered())
|
||||||
{
|
{
|
||||||
++piece;
|
++piece;
|
||||||
if (piece == int(m_piece_map.size())) piece = 0;
|
if (piece == int(m_piece_map.size())) piece = 0;
|
||||||
|
@ -1170,14 +1171,20 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(m_piece_map[piece].downloading == false);
|
assert(m_piece_map[piece].downloading == false);
|
||||||
|
|
||||||
int num_blocks_in_piece = blocks_in_piece(piece);
|
int start, end;
|
||||||
|
boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces);
|
||||||
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
|
for (int k = start; k < end; ++k)
|
||||||
num_blocks_in_piece = num_blocks;
|
{
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
int num_blocks_in_piece = blocks_in_piece(k);
|
||||||
interesting_blocks.push_back(piece_block(piece, j));
|
if (prefer_whole_pieces == 0 && num_blocks_in_piece > num_blocks)
|
||||||
num_blocks -= (std::min)(num_blocks_in_piece, num_blocks);
|
num_blocks_in_piece = num_blocks;
|
||||||
++piece;
|
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;
|
if (piece == int(m_piece_map.size())) piece = 0;
|
||||||
// could not find any more pieces
|
// could not find any more pieces
|
||||||
if (piece == start_piece) return;
|
if (piece == start_piece) return;
|
||||||
|
@ -1233,7 +1240,7 @@ namespace libtorrent
|
||||||
, std::vector<bool> const& pieces
|
, std::vector<bool> const& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks
|
||||||
, std::vector<piece_block>& backup_blocks
|
, std::vector<piece_block>& backup_blocks
|
||||||
, int num_blocks, bool prefer_whole_pieces
|
, int num_blocks, int prefer_whole_pieces
|
||||||
, void* peer, piece_state_t speed
|
, void* peer, piece_state_t speed
|
||||||
, bool ignore_downloading_pieces) const
|
, bool ignore_downloading_pieces) const
|
||||||
{
|
{
|
||||||
|
@ -1277,7 +1284,7 @@ namespace libtorrent
|
||||||
// blocks to the backup list. If the prioritized
|
// blocks to the backup list. If the prioritized
|
||||||
// blocks aren't enough, blocks from this list
|
// blocks aren't enough, blocks from this list
|
||||||
// will be picked.
|
// will be picked.
|
||||||
if (prefer_whole_pieces && !exclusive)
|
if (prefer_whole_pieces > 0 && !exclusive)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||||
{
|
{
|
||||||
|
@ -1332,7 +1339,7 @@ namespace libtorrent
|
||||||
num_blocks--;
|
num_blocks--;
|
||||||
// if we prefer whole pieces, continue picking from this
|
// if we prefer whole pieces, continue picking from this
|
||||||
// piece even though we have num_blocks
|
// piece even though we have num_blocks
|
||||||
if (prefer_whole_pieces) continue;
|
if (prefer_whole_pieces > 0) continue;
|
||||||
assert(num_blocks >= 0);
|
assert(num_blocks >= 0);
|
||||||
if (num_blocks == 0) return num_blocks;
|
if (num_blocks == 0) return num_blocks;
|
||||||
}
|
}
|
||||||
|
@ -1341,23 +1348,68 @@ namespace libtorrent
|
||||||
backup_blocks.push_back(piece_block(*i, j));
|
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;
|
if (num_blocks < 0) num_blocks = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks)
|
// pick a new piece
|
||||||
num_blocks_in_piece = num_blocks;
|
if (prefer_whole_pieces == 0)
|
||||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
{
|
||||||
interesting_blocks.push_back(piece_block(*i, j));
|
if (num_blocks_in_piece > num_blocks)
|
||||||
num_blocks -= (std::min)(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 < 0 ? 0 : num_blocks;
|
||||||
if (num_blocks == 0) return num_blocks;
|
|
||||||
}
|
}
|
||||||
return num_blocks;
|
return num_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int, int> piece_picker::expand_piece(int piece, int whole_pieces
|
||||||
|
, std::vector<bool> 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
|
bool piece_picker::is_piece_finished(int index) const
|
||||||
{
|
{
|
||||||
assert(index < (int)m_piece_map.size());
|
assert(index < (int)m_piece_map.size());
|
||||||
|
@ -1443,6 +1495,7 @@ namespace libtorrent
|
||||||
assert(block.block_index >= 0);
|
assert(block.block_index >= 0);
|
||||||
assert(block.piece_index < (int)m_piece_map.size());
|
assert(block.piece_index < (int)m_piece_map.size());
|
||||||
assert(block.block_index < blocks_in_piece(block.piece_index));
|
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];
|
piece_pos& p = m_piece_map[block.piece_index];
|
||||||
if (p.downloading == 0)
|
if (p.downloading == 0)
|
||||||
|
|
|
@ -209,16 +209,15 @@ namespace libtorrent
|
||||||
std::vector<piece_block> interesting_pieces;
|
std::vector<piece_block> interesting_pieces;
|
||||||
interesting_pieces.reserve(100);
|
interesting_pieces.reserve(100);
|
||||||
|
|
||||||
bool prefer_whole_pieces = c.prefer_whole_pieces()
|
int prefer_whole_pieces = c.prefer_whole_pieces();
|
||||||
|| (c.peer_info_struct() && c.peer_info_struct()->on_parole);
|
|
||||||
|
|
||||||
bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold;
|
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()
|
prefer_whole_pieces = c.statistics().download_payload_rate()
|
||||||
* t.settings().whole_pieces_threshold
|
* 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
|
// if we prefer whole pieces, the piece picker will pick at least
|
||||||
|
@ -265,12 +264,9 @@ namespace libtorrent
|
||||||
std::vector<int> const& suggested = c.suggested_pieces();
|
std::vector<int> const& suggested = c.suggested_pieces();
|
||||||
|
|
||||||
p.add_interesting_blocks(suggested, c.get_bitfield()
|
p.add_interesting_blocks(suggested, c.get_bitfield()
|
||||||
, interesting_pieces, busy_pieces, num_requests
|
, interesting_pieces, busy_pieces, num_requests
|
||||||
, prefer_whole_pieces, c.peer_info_struct(), state
|
, prefer_whole_pieces, c.peer_info_struct(), state
|
||||||
, false);
|
, false);
|
||||||
interesting_pieces.insert(interesting_pieces.end()
|
|
||||||
, busy_pieces.begin(), busy_pieces.end());
|
|
||||||
busy_pieces.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// picks the interesting pieces from this peer
|
// picks the interesting pieces from this peer
|
||||||
|
@ -285,13 +281,14 @@ namespace libtorrent
|
||||||
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
p.pick_pieces(c.get_bitfield(), interesting_pieces
|
||||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||||
, state, rarest_first);
|
, state, rarest_first);
|
||||||
|
|
||||||
busy_pieces.reserve(10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#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
|
#endif
|
||||||
|
std::deque<piece_block> const& dq = c.download_queue();
|
||||||
|
std::deque<piece_block> const& rq = c.request_queue();
|
||||||
for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
|
for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
|
||||||
i != interesting_pieces.end(); ++i)
|
i != interesting_pieces.end(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -299,8 +296,6 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (num_requests <= 0) break;
|
if (num_requests <= 0) break;
|
||||||
// don't request pieces we already have in our request queue
|
// don't request pieces we already have in our request queue
|
||||||
const std::deque<piece_block>& dq = c.download_queue();
|
|
||||||
const std::deque<piece_block>& rq = c.request_queue();
|
|
||||||
if (std::find(dq.begin(), dq.end(), *i) != dq.end()
|
if (std::find(dq.begin(), dq.end(), *i) != dq.end()
|
||||||
|| std::find(rq.begin(), rq.end(), *i) != rq.end())
|
|| std::find(rq.begin(), rq.end(), *i) != rq.end())
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -69,9 +69,6 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
// we always prefer downloading entire
|
|
||||||
// pieces from web seeds
|
|
||||||
prefer_whole_pieces(true);
|
|
||||||
// we want large blocks as well, so
|
// we want large blocks as well, so
|
||||||
// we can request more bytes at once
|
// we can request more bytes at once
|
||||||
request_large_blocks(true);
|
request_large_blocks(true);
|
||||||
|
@ -80,6 +77,10 @@ namespace libtorrent
|
||||||
shared_ptr<torrent> tor = t.lock();
|
shared_ptr<torrent> tor = t.lock();
|
||||||
assert(tor);
|
assert(tor);
|
||||||
int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size();
|
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
|
// multiply with the blocks per piece since that many requests are
|
||||||
// merged into one http request
|
// merged into one http request
|
||||||
|
@ -178,13 +179,16 @@ namespace libtorrent
|
||||||
|
|
||||||
int size = r.length;
|
int size = r.length;
|
||||||
const int block_size = t->block_size();
|
const int block_size = t->block_size();
|
||||||
|
const int piece_size = t->torrent_file().piece_length();
|
||||||
|
peer_request pr;
|
||||||
while (size > 0)
|
while (size > 0)
|
||||||
{
|
{
|
||||||
int request_size = (std::min)(block_size, size);
|
int request_offset = r.start + r.length - size;
|
||||||
peer_request pr = {r.piece, r.start + r.length - size
|
pr.start = request_offset % piece_size;
|
||||||
, request_size};
|
pr.length = (std::min)(block_size, size);
|
||||||
|
pr.piece = r.piece + request_offset / piece_size;
|
||||||
m_requests.push_back(pr);
|
m_requests.push_back(pr);
|
||||||
size -= request_size;
|
size -= pr.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy_settings const& ps = m_ses.web_seed_proxy();
|
proxy_settings const& ps = m_ses.web_seed_proxy();
|
||||||
|
@ -477,8 +481,11 @@ namespace libtorrent
|
||||||
|
|
||||||
peer_request front_request = m_requests.front();
|
peer_request front_request = m_requests.front();
|
||||||
|
|
||||||
if (in_range.piece != front_request.piece
|
size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start;
|
||||||
|| in_range.start > front_request.start + int(m_piece.size()))
|
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");
|
throw std::runtime_error("invalid range in HTTP response");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
|
|
||||||
|
const int blocks_per_piece = 4;
|
||||||
|
|
||||||
std::vector<bool> string2vec(char const* have_str)
|
std::vector<bool> string2vec(char const* have_str)
|
||||||
{
|
{
|
||||||
const int num_pieces = strlen(have_str);
|
const int num_pieces = strlen(have_str);
|
||||||
|
@ -30,7 +32,6 @@ boost::shared_ptr<piece_picker> setup_picker(
|
||||||
, char const* priority
|
, char const* priority
|
||||||
, char const* partial)
|
, char const* partial)
|
||||||
{
|
{
|
||||||
const int blocks_per_piece = 4;
|
|
||||||
const int num_pieces = strlen(availability);
|
const int num_pieces = strlen(availability);
|
||||||
assert(int(strlen(have_str)) == num_pieces);
|
assert(int(strlen(have_str)) == num_pieces);
|
||||||
|
|
||||||
|
@ -183,10 +184,10 @@ int test_main()
|
||||||
// whole pieces are preferred. The only whole piece is 1.
|
// whole pieces are preferred. The only whole piece is 1.
|
||||||
p = setup_picker("1111111", " ", "1111111", "1023460");
|
p = setup_picker("1111111", " ", "1111111", "1023460");
|
||||||
picked.clear();
|
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(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() >= 4);
|
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
||||||
for (int i = 0; i < 4 && i < int(picked.size()); ++i)
|
for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[i].piece_index == 1);
|
TEST_CHECK(picked[i].piece_index == 1);
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
@ -233,48 +234,48 @@ int test_main()
|
||||||
p = setup_picker("7654321", " ", "", "");
|
p = setup_picker("7654321", " ", "", "");
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p->set_sequenced_download_threshold(3);
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() == 5 * 4);
|
TEST_CHECK(picked.size() == 5 * blocks_per_piece);
|
||||||
for (int i = 0; i < 5 * 4 && i < int(picked.size()); ++i)
|
for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[i].piece_index == i / 4);
|
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p->set_sequenced_download_threshold(4);
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() == 4 * 4);
|
TEST_CHECK(picked.size() == 4 * 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 == i / 4);
|
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p->set_sequenced_download_threshold(2);
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() == 6 * 4);
|
TEST_CHECK(picked.size() == 6 * blocks_per_piece);
|
||||||
for (int i = 0; i < 6 * 4 && i < int(picked.size()); ++i)
|
for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[i].piece_index == i / 4);
|
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p->set_piece_priority(0, 0);
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() == 5 * 4);
|
TEST_CHECK(picked.size() == 5 * blocks_per_piece);
|
||||||
for (int i = 0; i < 5 * 4 && i < int(picked.size()); ++i)
|
for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[i].piece_index == i / 4 + 1);
|
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece + 1);
|
||||||
|
|
||||||
picked.clear();
|
picked.clear();
|
||||||
p->set_piece_priority(0, 1);
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() == 6 * 4);
|
TEST_CHECK(picked.size() == 6 * blocks_per_piece);
|
||||||
for (int i = 0; i < 6 * 4 && i < int(picked.size()); ++i)
|
for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[i].piece_index == i / 4);
|
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
|
@ -291,17 +292,17 @@ int test_main()
|
||||||
TEST_CHECK(p->num_have_filtered() == 1);
|
TEST_CHECK(p->num_have_filtered() == 1);
|
||||||
|
|
||||||
picked.clear();
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() == 6 * 4);
|
TEST_CHECK(picked.size() == 6 * blocks_per_piece);
|
||||||
TEST_CHECK(picked[0].piece_index == 5);
|
TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 5);
|
||||||
// priority 5 and 6 is currently the same
|
// priority 5 and 6 is currently the same
|
||||||
TEST_CHECK(picked[4].piece_index == 6 || picked[4].piece_index == 4);
|
TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 6 || picked[1 * blocks_per_piece].piece_index == 4);
|
||||||
TEST_CHECK(picked[8].piece_index == 6 || picked[8].piece_index == 4);
|
TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 6 || picked[2 * blocks_per_piece].piece_index == 4);
|
||||||
TEST_CHECK(picked[12].piece_index == 3);
|
TEST_CHECK(picked[3 * blocks_per_piece].piece_index == 3);
|
||||||
TEST_CHECK(picked[16].piece_index == 1);
|
TEST_CHECK(picked[4 * blocks_per_piece].piece_index == 1);
|
||||||
TEST_CHECK(picked[20].piece_index == 2);
|
TEST_CHECK(picked[5 * blocks_per_piece].piece_index == 2);
|
||||||
|
|
||||||
std::vector<int> prios;
|
std::vector<int> prios;
|
||||||
p->piece_priorities(prios);
|
p->piece_priorities(prios);
|
||||||
|
@ -365,12 +366,12 @@ int test_main()
|
||||||
// test non-rarest-first mode
|
// test non-rarest-first mode
|
||||||
p = setup_picker("1234567", "* * * ", "1111122", "");
|
p = setup_picker("1234567", "* * * ", "1111122", "");
|
||||||
picked.clear();
|
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);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, 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 != 0);
|
||||||
TEST_CHECK(picked[i].piece_index != 2);
|
TEST_CHECK(picked[i].piece_index != 2);
|
||||||
|
@ -393,8 +394,6 @@ int test_main()
|
||||||
std::cout << "distributed copies: " << dc << std::endl;
|
std::cout << "distributed copies: " << dc << std::endl;
|
||||||
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
|
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// test have_all and have_none, with a sequenced download threshold
|
// 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);
|
p->pick_pieces(string2vec(" * ****"), picked, 100, false, 0, piece_picker::fast, true);
|
||||||
print_pick(picked);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(picked.size() >= 4 * 4);
|
TEST_CHECK(picked.size() >= 4 * blocks_per_piece);
|
||||||
TEST_CHECK(picked[0].piece_index == 3);
|
TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 3);
|
||||||
TEST_CHECK(picked[4].piece_index == 4);
|
TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 4);
|
||||||
TEST_CHECK(picked[8].piece_index == 5);
|
TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 5);
|
||||||
TEST_CHECK(picked[12].piece_index == 6);
|
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->get_downloader(piece_block(4, 3)) == 0);
|
||||||
TEST_CHECK(p->unverified_blocks() == 2);
|
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:
|
// MISSING TESTS:
|
||||||
// 2. inc_ref() from 0 to 1 while sequenced download threshold is 1
|
// 2. inc_ref() from 0 to 1 while sequenced download threshold is 1
|
||||||
// 4. filtered_pieces
|
// 4. filtered_pieces
|
||||||
|
|
Loading…
Reference in New Issue