forked from premiere/premiere-libtorrent
improve piece picker to better support torrents with very large pieces and web seeds
This commit is contained in:
parent
e6eb920021
commit
d8d069675c
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<piece_block>& 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<int> const& suggested_pieces
|
||||
, int num_peers
|
||||
, counters& pc
|
||||
|
@ -315,7 +319,7 @@ namespace libtorrent
|
|||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, std::vector<piece_block>& backup_blocks2
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, int num_blocks, int prefer_contiguous_blocks
|
||||
, void* peer, std::vector<int> const& ignore
|
||||
, piece_state_t speed, int options) const;
|
||||
|
||||
|
@ -325,7 +329,7 @@ namespace libtorrent
|
|||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, std::vector<piece_block>& 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;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<piece_block>& 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<int> 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<piece_block> backup_blocks2;
|
||||
const std::vector<int> 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<bool, bool> requested_from(piece_picker::downloading_piece const& p
|
||||
boost::tuple<bool, bool, int> 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<torrent_peer*>(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<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, std::vector<piece_block>& backup_blocks2
|
||||
, int num_blocks, int prefer_whole_pieces
|
||||
, int num_blocks, int prefer_contiguous_blocks
|
||||
, void* peer, std::vector<int> 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<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, std::vector<piece_block>& 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<int, int> piece_picker::expand_piece(int piece, int whole_pieces
|
||||
std::pair<int, int> 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;
|
||||
|
|
|
@ -106,13 +106,14 @@ namespace libtorrent
|
|||
std::vector<piece_block> 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<piece_block>::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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -246,14 +246,18 @@ void print_title(char const* name)
|
|||
std::cerr << "==== " << name << " ====\n";
|
||||
}
|
||||
|
||||
std::vector<piece_block> pick_pieces(boost::shared_ptr<piece_picker> const& p, char const* availability
|
||||
, int num_blocks, int prefer_whole_pieces, void* peer_struct, piece_picker::piece_state_t state
|
||||
std::vector<piece_block> pick_pieces(boost::shared_ptr<piece_picker> 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<int> const& suggested_pieces = empty_vector)
|
||||
{
|
||||
std::vector<piece_block> 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<int> picked_pieces;
|
||||
for (std::vector<piece_block>::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<int> 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);
|
||||
|
|
Loading…
Reference in New Issue