big change to improve piece picker. Better end-game mode. More options on which pieces to pick.
This commit is contained in:
parent
7f143791d5
commit
41808f8742
|
@ -151,7 +151,7 @@ namespace libtorrent
|
||||||
policy::peer* peer_info_struct() const
|
policy::peer* peer_info_struct() const
|
||||||
{ return m_peer_info; }
|
{ return m_peer_info; }
|
||||||
|
|
||||||
enum peer_speed_t { slow, medium, fast };
|
enum peer_speed_t { slow = 1, medium, fast };
|
||||||
peer_speed_t peer_speed();
|
peer_speed_t peer_speed();
|
||||||
|
|
||||||
void send_allowed_set();
|
void send_allowed_set();
|
||||||
|
@ -187,6 +187,8 @@ namespace libtorrent
|
||||||
bool on_parole() const
|
bool on_parole() const
|
||||||
{ return peer_info_struct() && peer_info_struct()->on_parole; }
|
{ return peer_info_struct() && peer_info_struct()->on_parole; }
|
||||||
|
|
||||||
|
int picker_options() const;
|
||||||
|
|
||||||
void prefer_whole_pieces(int num)
|
void prefer_whole_pieces(int num)
|
||||||
{ m_prefer_whole_pieces = num; }
|
{ m_prefer_whole_pieces = num; }
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,14 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// the number of priority levels
|
||||||
|
priority_levels = 8,
|
||||||
|
// priority factor
|
||||||
|
prio_factor = priority_levels - 4
|
||||||
|
};
|
||||||
|
|
||||||
struct block_info
|
struct block_info
|
||||||
{
|
{
|
||||||
block_info(): peer(0), num_peers(0), state(state_none) {}
|
block_info(): peer(0), num_peers(0), state(state_none) {}
|
||||||
|
@ -110,6 +118,20 @@ namespace libtorrent
|
||||||
enum piece_state_t
|
enum piece_state_t
|
||||||
{ none, slow, medium, fast };
|
{ none, slow, medium, fast };
|
||||||
|
|
||||||
|
enum options_t
|
||||||
|
{
|
||||||
|
// pick rarest first
|
||||||
|
rarest_first = 1,
|
||||||
|
// pick the most common first, or the last pieces if sequential
|
||||||
|
reverse = 2,
|
||||||
|
// only pick pieces exclusively requested from this peer
|
||||||
|
on_parole = 4,
|
||||||
|
// always pick partial pieces before any other piece
|
||||||
|
prioritize_partials = 8,
|
||||||
|
// pick pieces in sequential order
|
||||||
|
sequential = 16
|
||||||
|
};
|
||||||
|
|
||||||
struct downloading_piece
|
struct downloading_piece
|
||||||
{
|
{
|
||||||
downloading_piece(): finished(0), writing(0), requested(0) {}
|
downloading_piece(): finished(0), writing(0), requested(0) {}
|
||||||
|
@ -133,9 +155,6 @@ namespace libtorrent
|
||||||
|
|
||||||
void get_availability(std::vector<int>& avail) const;
|
void get_availability(std::vector<int>& avail) const;
|
||||||
|
|
||||||
void sequential_download(bool sd);
|
|
||||||
bool sequential_download() const { return m_sequential_download >= 0; }
|
|
||||||
|
|
||||||
// increases the peer count for the given piece
|
// increases the peer count for the given piece
|
||||||
// (is used when a HAVE message is received)
|
// (is used when a HAVE message is received)
|
||||||
void inc_refcount(int index);
|
void inc_refcount(int index);
|
||||||
|
@ -161,6 +180,9 @@ namespace libtorrent
|
||||||
void we_have(int index);
|
void we_have(int index);
|
||||||
void we_dont_have(int index);
|
void we_dont_have(int index);
|
||||||
|
|
||||||
|
int cursor() const { return m_cursor; }
|
||||||
|
int reverse_cursor() const { return m_reverse_cursor; }
|
||||||
|
|
||||||
// sets all pieces to dont-have
|
// sets all pieces to dont-have
|
||||||
void init(int blocks_per_piece, int total_num_blocks);
|
void init(int blocks_per_piece, int total_num_blocks);
|
||||||
int num_pieces() const { return int(m_piece_map.size()); }
|
int num_pieces() const { return int(m_piece_map.size()); }
|
||||||
|
@ -202,11 +224,9 @@ namespace libtorrent
|
||||||
// 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(bitfield const& pieces
|
void pick_pieces(bitfield const& pieces
|
||||||
, std::vector<piece_block>& interesting_blocks
|
, std::vector<piece_block>& interesting_blocks, int num_blocks
|
||||||
, int num_pieces, int prefer_whole_pieces
|
, int prefer_whole_pieces, void* peer, piece_state_t speed
|
||||||
, void* peer, piece_state_t speed
|
, int options, std::vector<int> const& suggested_pieces) const;
|
||||||
, bool rarest_first, bool on_parole
|
|
||||||
, std::vector<int> const& suggested_pieces) const;
|
|
||||||
|
|
||||||
// picks blocks from each of the pieces in the piece_list
|
// picks blocks from each of the pieces in the piece_list
|
||||||
// vector that is also in the piece bitmask. The blocks
|
// vector that is also in the piece bitmask. The blocks
|
||||||
|
@ -214,20 +234,23 @@ namespace libtorrent
|
||||||
// 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 are not picked from pieces
|
// blocks to be picked. Blocks are not picked from pieces
|
||||||
// that are being downloaded
|
// that are being downloaded
|
||||||
int add_blocks(std::vector<int> const& piece_list
|
int add_blocks(int piece, bitfield const& pieces
|
||||||
, bitfield const& pieces
|
|
||||||
, std::vector<piece_block>& interesting_blocks
|
|
||||||
, int num_blocks, int prefer_whole_pieces
|
|
||||||
, void* peer, std::vector<int> const& ignore) const;
|
|
||||||
|
|
||||||
// picks blocks only from downloading pieces
|
|
||||||
int add_blocks_downloading(
|
|
||||||
bitfield 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
|
||||||
|
, std::vector<piece_block>& backup_blocks2
|
||||||
|
, int num_blocks, int prefer_whole_pieces
|
||||||
|
, void* peer, std::vector<int> const& ignore
|
||||||
|
, piece_state_t speed, int options) const;
|
||||||
|
|
||||||
|
// picks blocks only from downloading pieces
|
||||||
|
int add_blocks_downloading(downloading_piece const& dp
|
||||||
|
, bitfield const& pieces
|
||||||
|
, 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_whole_pieces
|
||||||
, void* peer, piece_state_t speed
|
, void* peer, piece_state_t speed
|
||||||
, bool on_parole) const;
|
, int options) const;
|
||||||
|
|
||||||
// clears the peer pointer in all downloading pieces with this
|
// clears the peer pointer in all downloading pieces with this
|
||||||
// peer pointer
|
// peer pointer
|
||||||
|
@ -291,6 +314,8 @@ namespace libtorrent
|
||||||
void check_invariant(const torrent* t = 0) const;
|
void check_invariant(const torrent* t = 0) const;
|
||||||
void verify_pick(std::vector<piece_block> const& picked
|
void verify_pick(std::vector<piece_block> const& picked
|
||||||
, bitfield const& bits) const;
|
, bitfield const& bits) const;
|
||||||
|
#endif
|
||||||
|
#if defined TORRENT_PICKER_LOG || !defined NDEBUG
|
||||||
void print_pieces() const;
|
void print_pieces() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -313,6 +338,7 @@ namespace libtorrent
|
||||||
friend struct piece_pos;
|
friend struct piece_pos;
|
||||||
|
|
||||||
bool can_pick(int piece, bitfield const& bitmask) const;
|
bool can_pick(int piece, bitfield const& bitmask) const;
|
||||||
|
bool is_piece_free(int piece, bitfield const& bitmask) const;
|
||||||
std::pair<int, int> expand_piece(int piece, int whole_pieces
|
std::pair<int, int> expand_piece(int piece, int whole_pieces
|
||||||
, bitfield const& have) const;
|
, bitfield const& have) const;
|
||||||
|
|
||||||
|
@ -354,7 +380,7 @@ namespace libtorrent
|
||||||
// the priority value that means the piece is filtered
|
// the priority value that means the piece is filtered
|
||||||
filter_priority = 0,
|
filter_priority = 0,
|
||||||
// the max number the peer count can hold
|
// the max number the peer count can hold
|
||||||
max_peer_count = 0x3ff
|
max_peer_count = 0x3ff,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool have() const { return index == we_have_index; }
|
bool have() const { return index == we_have_index; }
|
||||||
|
@ -364,20 +390,41 @@ namespace libtorrent
|
||||||
bool filtered() const { return piece_priority == filter_priority; }
|
bool filtered() const { return piece_priority == filter_priority; }
|
||||||
void filtered(bool f) { piece_priority = f ? filter_priority : 0; }
|
void filtered(bool f) { piece_priority = f ? filter_priority : 0; }
|
||||||
|
|
||||||
|
// prio 7 is always top priority
|
||||||
|
// prio 0 is always -1 (don't pick)
|
||||||
|
// downloading pieces are always on an even prio_factor priority
|
||||||
|
//
|
||||||
|
// availability x, downloading
|
||||||
|
// | availability x, prio 3; availability 2x, prio 6
|
||||||
|
// | | availability x, prio 2; availability 2x, prio 5
|
||||||
|
// | | | availability x, prio 1; availability 2x, prio 4
|
||||||
|
// | | | |
|
||||||
|
// +---+---+---+---+
|
||||||
|
// | 0 | 1 | 2 | 3 |
|
||||||
|
// +---+---+---+---+
|
||||||
|
|
||||||
int priority(piece_picker const* picker) const
|
int priority(piece_picker const* picker) const
|
||||||
{
|
{
|
||||||
if (downloading || filtered()
|
// filtered pieces (prio = 0), pieces we have or pieces with
|
||||||
|| have() || peer_count + picker->m_seeds == 0)
|
// availability = 0 should not be present in the piece list
|
||||||
|
// returning -1 indicates that they shouldn't.
|
||||||
|
if (filtered() || have() || peer_count + picker->m_seeds == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
// priority 5, 6 and 7 disregards availability of the piece
|
// prio 7 disregards availability
|
||||||
if (piece_priority > 4) return 7 - piece_priority;
|
if (piece_priority == priority_levels - 1) return 1 - downloading;
|
||||||
|
|
||||||
// pieces we are currently downloading have high priority
|
// prio 4,5,6 halves the availability of a piece
|
||||||
int prio = peer_count * 4;
|
int availability = peer_count;
|
||||||
// if (prio >= picker->m_prio_limit * 6) prio = picker->m_prio_limit * 6;
|
int priority = piece_priority;
|
||||||
|
if (piece_priority >= priority_levels / 2)
|
||||||
|
{
|
||||||
|
availability /= 2;
|
||||||
|
priority -= (priority_levels - 2) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
return prio + (4 - piece_priority);
|
if (downloading) return availability * prio_factor;
|
||||||
|
return availability * prio_factor + (priority_levels / 2) - priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=(piece_pos p) const
|
bool operator!=(piece_pos p) const
|
||||||
|
@ -467,11 +514,14 @@ namespace libtorrent
|
||||||
// the number of pieces we have
|
// the number of pieces we have
|
||||||
int m_num_have;
|
int m_num_have;
|
||||||
|
|
||||||
// -1 means sequential download is not active.
|
// we have all pieces in the range [0, m_cursor)
|
||||||
// >= 0 means that pieces are requested in sequential order
|
// m_cursor is the first piece we don't have
|
||||||
// and this variable is the next piece to request.
|
int m_cursor;
|
||||||
// in that case m_pieces is cleared and not used.
|
|
||||||
int m_sequential_download;
|
// we have all pieces in the range [m_reverse_cursor, end)
|
||||||
|
// m_reverse_cursor is the first piece where we also have
|
||||||
|
// all the subsequent pieces
|
||||||
|
int m_reverse_cursor;
|
||||||
|
|
||||||
// if this is set to true, it means update_pieces()
|
// if this is set to true, it means update_pieces()
|
||||||
// has to be called before accessing m_pieces.
|
// has to be called before accessing m_pieces.
|
||||||
|
|
|
@ -141,6 +141,7 @@ namespace libtorrent
|
||||||
, auto_scrape_min_interval(300)
|
, auto_scrape_min_interval(300)
|
||||||
, max_peerlist_size(8000)
|
, max_peerlist_size(8000)
|
||||||
, min_announce_interval(5 * 60)
|
, min_announce_interval(5 * 60)
|
||||||
|
, prioritize_partial_pieces(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// this is the user agent that will be sent to the tracker
|
// this is the user agent that will be sent to the tracker
|
||||||
|
@ -436,6 +437,10 @@ namespace libtorrent
|
||||||
// that is lower than this, will be clamped to this
|
// that is lower than this, will be clamped to this
|
||||||
// value. It's specified in seconds
|
// value. It's specified in seconds
|
||||||
int min_announce_interval;
|
int min_announce_interval;
|
||||||
|
|
||||||
|
// if true, partial pieces are picked before pieces
|
||||||
|
// that are more rare
|
||||||
|
bool prioritize_partial_pieces;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
|
|
|
@ -572,6 +572,50 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int peer_connection::picker_options() const
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
boost::shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
TORRENT_ASSERT(t);
|
||||||
|
if (!t) return 0;
|
||||||
|
|
||||||
|
if (t->is_sequential_download())
|
||||||
|
{
|
||||||
|
ret |= piece_picker::sequential;
|
||||||
|
}
|
||||||
|
else if (t->num_have() < t->settings().initial_picker_threshold)
|
||||||
|
{
|
||||||
|
// if we have fewer pieces than a certain threshols
|
||||||
|
// don't pick rare pieces, just pick random ones,
|
||||||
|
// and prioritize finishing them
|
||||||
|
ret |= piece_picker::prioritize_partials;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret |= piece_picker::rarest_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_snubbed)
|
||||||
|
{
|
||||||
|
// snubbed peers should request
|
||||||
|
// the common pieces first, just to make
|
||||||
|
// it more likely for all snubbed peers to
|
||||||
|
// request blocks from the same piece
|
||||||
|
ret |= piece_picker::reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->settings().prioritize_partial_pieces)
|
||||||
|
ret |= piece_picker::prioritize_partials;
|
||||||
|
|
||||||
|
if (on_parole()) ret |= piece_picker::on_parole
|
||||||
|
| piece_picker::prioritize_partials;
|
||||||
|
|
||||||
|
// only one of rarest_first, common_first and sequential can be set.
|
||||||
|
TORRENT_ASSERT(bool(ret & piece_picker::rarest_first)
|
||||||
|
+ bool(ret & piece_picker::sequential) <= 1);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void peer_connection::fast_reconnect(bool r)
|
void peer_connection::fast_reconnect(bool r)
|
||||||
{
|
{
|
||||||
if (!peer_info_struct() || peer_info_struct()->fast_reconnects > 1)
|
if (!peer_info_struct() || peer_info_struct()->fast_reconnects > 1)
|
||||||
|
@ -1724,9 +1768,12 @@ namespace libtorrent
|
||||||
bool multi = picker.num_peers(block_finished) > 1;
|
bool multi = picker.num_peers(block_finished) > 1;
|
||||||
picker.mark_as_writing(block_finished, peer_info_struct());
|
picker.mark_as_writing(block_finished, peer_info_struct());
|
||||||
|
|
||||||
|
TORRENT_ASSERT(picker.num_peers(block_finished) == 0);
|
||||||
// if we requested this block from other peers, cancel it now
|
// if we requested this block from other peers, cancel it now
|
||||||
if (multi) t->cancel_block(block_finished);
|
if (multi) t->cancel_block(block_finished);
|
||||||
|
|
||||||
|
TORRENT_ASSERT(picker.num_peers(block_finished) == 0);
|
||||||
|
|
||||||
#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
|
#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
|
||||||
t->check_invariant();
|
t->check_invariant();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1777,6 +1824,7 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(p.piece == j.piece);
|
TORRENT_ASSERT(p.piece == j.piece);
|
||||||
TORRENT_ASSERT(p.start == j.offset);
|
TORRENT_ASSERT(p.start == j.offset);
|
||||||
|
TORRENT_ASSERT(picker.num_peers(block_finished) == 0);
|
||||||
picker.mark_as_finished(block_finished, peer_info_struct());
|
picker.mark_as_finished(block_finished, peer_info_struct());
|
||||||
if (t->alerts().should_post<block_finished_alert>())
|
if (t->alerts().should_post<block_finished_alert>())
|
||||||
{
|
{
|
||||||
|
@ -3899,7 +3947,7 @@ namespace libtorrent
|
||||||
m_speed = medium;
|
m_speed = medium;
|
||||||
else if (download_rate < torrent_download_rate / 15 && m_speed == fast)
|
else if (download_rate < torrent_download_rate / 15 && m_speed == fast)
|
||||||
m_speed = medium;
|
m_speed = medium;
|
||||||
else if (download_rate < torrent_download_rate / 63 && m_speed == medium)
|
else
|
||||||
m_speed = slow;
|
m_speed = slow;
|
||||||
|
|
||||||
return m_speed;
|
return m_speed;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -200,8 +200,6 @@ namespace libtorrent
|
||||||
|
|
||||||
int prefer_whole_pieces = c.prefer_whole_pieces();
|
int prefer_whole_pieces = c.prefer_whole_pieces();
|
||||||
|
|
||||||
bool rarest_first = t.num_have() >= t.settings().initial_picker_threshold;
|
|
||||||
|
|
||||||
if (prefer_whole_pieces == 0)
|
if (prefer_whole_pieces == 0)
|
||||||
{
|
{
|
||||||
prefer_whole_pieces = c.statistics().download_payload_rate()
|
prefer_whole_pieces = c.statistics().download_payload_rate()
|
||||||
|
@ -250,7 +248,7 @@ namespace libtorrent
|
||||||
|
|
||||||
p.pick_pieces(mask, interesting_pieces
|
p.pick_pieces(mask, interesting_pieces
|
||||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||||
, state, rarest_first, c.on_parole(), suggested);
|
, state, c.picker_options(), suggested);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -264,7 +262,7 @@ namespace libtorrent
|
||||||
// then use this mode.
|
// then use this mode.
|
||||||
p.pick_pieces(bits, interesting_pieces
|
p.pick_pieces(bits, interesting_pieces
|
||||||
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
, num_requests, prefer_whole_pieces, c.peer_info_struct()
|
||||||
, state, rarest_first, c.on_parole(), suggested);
|
, state, c.picker_options(), suggested);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
@ -303,10 +301,6 @@ namespace libtorrent
|
||||||
|
|
||||||
if (busy_pieces.empty() || num_requests <= 0)
|
if (busy_pieces.empty() || num_requests <= 0)
|
||||||
{
|
{
|
||||||
// in this case, we could not find any blocks
|
|
||||||
// that was free. If we couldn't find any busy
|
|
||||||
// blocks as well, we cannot download anything
|
|
||||||
// more from this peer.
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -754,10 +754,14 @@ namespace libtorrent
|
||||||
|
|
||||||
m_progress = j.piece / float(torrent_file().num_pieces());
|
m_progress = j.piece / float(torrent_file().num_pieces());
|
||||||
|
|
||||||
|
m_picker->check_invariant();
|
||||||
|
|
||||||
TORRENT_ASSERT(m_picker);
|
TORRENT_ASSERT(m_picker);
|
||||||
if (j.offset >= 0 && !m_picker->have_piece(j.offset))
|
if (j.offset >= 0 && !m_picker->have_piece(j.offset))
|
||||||
m_picker->we_have(j.offset);
|
m_picker->we_have(j.offset);
|
||||||
|
|
||||||
|
m_picker->check_invariant();
|
||||||
|
|
||||||
// we're not done checking yet
|
// we're not done checking yet
|
||||||
// this handler will be called repeatedly until
|
// this handler will be called repeatedly until
|
||||||
// we're done, or encounter a failure
|
// we're done, or encounter a failure
|
||||||
|
@ -3298,9 +3302,6 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!is_seed())
|
if (!is_seed())
|
||||||
{
|
{
|
||||||
if (m_sequential_download)
|
|
||||||
picker().sequential_download(m_sequential_download);
|
|
||||||
|
|
||||||
// if we just finished checking and we're not a seed, we are
|
// if we just finished checking and we're not a seed, we are
|
||||||
// likely to be unpaused
|
// likely to be unpaused
|
||||||
if (m_ses.m_auto_manage_time_scaler > 1)
|
if (m_ses.m_auto_manage_time_scaler > 1)
|
||||||
|
@ -3549,13 +3550,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void torrent::set_sequential_download(bool sd)
|
void torrent::set_sequential_download(bool sd)
|
||||||
{
|
{ m_sequential_download = sd; }
|
||||||
m_sequential_download = sd;
|
|
||||||
if (has_picker())
|
|
||||||
{
|
|
||||||
picker().sequential_download(sd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void torrent::set_queue_position(int p)
|
void torrent::set_queue_position(int p)
|
||||||
{
|
{
|
||||||
|
|
|
@ -71,6 +71,14 @@ boost::shared_ptr<piece_picker> setup_picker(
|
||||||
boost::shared_ptr<piece_picker> p(new piece_picker);
|
boost::shared_ptr<piece_picker> p(new piece_picker);
|
||||||
p->init(blocks_per_piece, num_pieces * blocks_per_piece);
|
p->init(blocks_per_piece, num_pieces * blocks_per_piece);
|
||||||
|
|
||||||
|
for (int i = 0; i < num_pieces; ++i)
|
||||||
|
{
|
||||||
|
const int avail = availability[i] - '0';
|
||||||
|
assert(avail >= 0);
|
||||||
|
|
||||||
|
for (int j = 0; j < avail; ++j) p->inc_refcount(i);
|
||||||
|
}
|
||||||
|
|
||||||
bitfield have = string2vec(have_str);
|
bitfield have = string2vec(have_str);
|
||||||
|
|
||||||
for (int i = 0; i < num_pieces; ++i)
|
for (int i = 0; i < num_pieces; ++i)
|
||||||
|
@ -86,25 +94,24 @@ boost::shared_ptr<piece_picker> setup_picker(
|
||||||
blocks = partial[i] - 'a' + 10;
|
blocks = partial[i] - 'a' + 10;
|
||||||
|
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
if (blocks & 1)
|
for (int j = 0; j < 4; ++j)
|
||||||
{
|
{
|
||||||
|
TEST_CHECK(!p->is_finished(piece_block(i, j)));
|
||||||
|
if ((blocks & (1 << j)) == 0) continue;
|
||||||
++counter;
|
++counter;
|
||||||
p->mark_as_finished(piece_block(i, 0), 0);
|
bool ret = p->mark_as_downloading(piece_block(i, j), 0, piece_picker::slow);
|
||||||
}
|
TEST_CHECK(ret == true);
|
||||||
if (blocks & 2)
|
TEST_CHECK(p->is_requested(piece_block(i, j)) == bool(blocks & (1 << j)));
|
||||||
{
|
p->mark_as_writing(piece_block(i, j), 0);
|
||||||
++counter;
|
TEST_CHECK(!p->is_finished(piece_block(i, j)));
|
||||||
p->mark_as_finished(piece_block(i, 1), 0);
|
// trying to mark a block as requested after it has been completed
|
||||||
}
|
// should fail (return false)
|
||||||
if (blocks & 4)
|
ret = p->mark_as_downloading(piece_block(i, j), 0, piece_picker::slow);
|
||||||
{
|
TEST_CHECK(ret == false);
|
||||||
++counter;
|
p->mark_as_finished(piece_block(i, j), 0);
|
||||||
p->mark_as_finished(piece_block(i, 2), 0);
|
|
||||||
}
|
TEST_CHECK(p->is_downloaded(piece_block(i, j)) == bool(blocks & (1 << j)));
|
||||||
if (blocks & 8)
|
TEST_CHECK(p->is_finished(piece_block(i, j)) == bool(blocks & (1 << j)));
|
||||||
{
|
|
||||||
++counter;
|
|
||||||
p->mark_as_finished(piece_block(i, 3), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
piece_picker::downloading_piece st;
|
piece_picker::downloading_piece st;
|
||||||
|
@ -114,6 +121,9 @@ boost::shared_ptr<piece_picker> setup_picker(
|
||||||
TEST_CHECK(st.index == i);
|
TEST_CHECK(st.index == i);
|
||||||
|
|
||||||
TEST_CHECK(st.finished == counter);
|
TEST_CHECK(st.finished == counter);
|
||||||
|
TEST_CHECK(st.finished + st.requested + st.writing == counter);
|
||||||
|
|
||||||
|
TEST_CHECK(p->is_piece_finished(i) == (counter == 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < num_pieces; ++i)
|
for (int i = 0; i < num_pieces; ++i)
|
||||||
|
@ -134,14 +144,6 @@ boost::shared_ptr<piece_picker> setup_picker(
|
||||||
TEST_CHECK(p->is_finished(piece_block(i, j)));
|
TEST_CHECK(p->is_finished(piece_block(i, j)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < num_pieces; ++i)
|
|
||||||
{
|
|
||||||
const int avail = availability[i] - '0';
|
|
||||||
assert(avail >= 0);
|
|
||||||
|
|
||||||
for (int j = 0; j < avail; ++j) p->inc_refcount(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> availability_vec;
|
std::vector<int> availability_vec;
|
||||||
p->get_availability(availability_vec);
|
p->get_availability(availability_vec);
|
||||||
for (int i = 0; i < num_pieces; ++i)
|
for (int i = 0; i < num_pieces; ++i)
|
||||||
|
@ -158,20 +160,25 @@ boost::shared_ptr<piece_picker> setup_picker(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool verify_pick(boost::shared_ptr<piece_picker> p
|
bool verify_pick(boost::shared_ptr<piece_picker> p
|
||||||
, std::vector<piece_block> const& picked)
|
, std::vector<piece_block> const& picked, bool allow_multi_blocks = false)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
p->check_invariant();
|
p->check_invariant();
|
||||||
#endif
|
#endif
|
||||||
for (std::vector<piece_block>::const_iterator i = picked.begin()
|
if (!allow_multi_blocks)
|
||||||
, end(picked.end()); i != end; ++i)
|
|
||||||
{
|
{
|
||||||
if (p->num_peers(*i) > 0) return false;
|
for (std::vector<piece_block>::const_iterator i = picked.begin()
|
||||||
|
, end(picked.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
if (p->num_peers(*i) > 0) return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure there are no duplicated
|
// make sure there are no duplicated
|
||||||
std::set<piece_block> blocks;
|
std::set<piece_block> blocks;
|
||||||
std::copy(picked.begin(), picked.end(), std::insert_iterator<std::set<piece_block> >(blocks, blocks.end()));
|
std::copy(picked.begin(), picked.end()
|
||||||
|
, std::insert_iterator<std::set<piece_block> >(blocks, blocks.end()));
|
||||||
|
std::cerr << " verify: " << picked.size() << " " << blocks.size() << std::endl;
|
||||||
return picked.size() == blocks.size();
|
return picked.size() == blocks.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,60 +196,182 @@ void print_title(char const* name)
|
||||||
std::cerr << "==== " << name << " ====\n";
|
std::cerr << "==== " << name << " ====\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_pick(boost::shared_ptr<piece_picker> const& p)
|
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
|
||||||
|
, int options, std::vector<int> const& suggested_pieces)
|
||||||
{
|
{
|
||||||
std::vector<piece_block> picked;
|
std::vector<piece_block> picked;
|
||||||
const std::vector<int> empty_vector;
|
p->pick_pieces(string2vec(availability), picked, num_blocks, prefer_whole_pieces, peer_struct
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
, state, options, suggested_pieces);
|
||||||
print_pick(picked);
|
print_pick(picked);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(verify_pick(p, picked));
|
||||||
TEST_CHECK(int(picked.size()) == 1);
|
return picked;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_pick(boost::shared_ptr<piece_picker> const& p, int options = piece_picker::rarest_first)
|
||||||
|
{
|
||||||
|
const std::vector<int> empty_vector;
|
||||||
|
std::vector<piece_block> picked = pick_pieces(p, "*******", 1, 0, 0
|
||||||
|
, piece_picker::fast, options, empty_vector);
|
||||||
|
if (picked.empty()) return -1;
|
||||||
return picked[0].piece_index;
|
return picked[0].piece_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_main()
|
int test_main()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
int tmp1;
|
||||||
|
int tmp2;
|
||||||
|
int tmp3;
|
||||||
tcp::endpoint endp;
|
tcp::endpoint endp;
|
||||||
|
piece_picker::downloading_piece st;
|
||||||
policy::peer peer_struct(endp, policy::peer::connectable, 0);
|
policy::peer peer_struct(endp, policy::peer::connectable, 0);
|
||||||
std::vector<piece_block> picked;
|
std::vector<piece_block> picked;
|
||||||
boost::shared_ptr<piece_picker> p;
|
boost::shared_ptr<piece_picker> p;
|
||||||
const std::vector<int> empty_vector;
|
const std::vector<int> empty_vector;
|
||||||
|
int options = piece_picker::rarest_first;
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// test abort_download
|
||||||
|
print_title("test abort_download");
|
||||||
|
p = setup_picker("1111111", " ", "7110000", "");
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());
|
||||||
|
|
||||||
|
p->abort_download(piece_block(piece_block(0,0)));
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());
|
||||||
|
|
||||||
|
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::fast);
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == true);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) == picked.end());
|
||||||
|
|
||||||
|
p->abort_download(piece_block(0,0));
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());
|
||||||
|
|
||||||
|
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::fast);
|
||||||
|
p->mark_as_downloading(piece_block(0,1), &tmp1, piece_picker::fast);
|
||||||
|
p->abort_download(piece_block(0,0));
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());
|
||||||
|
|
||||||
|
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::fast);
|
||||||
|
p->mark_as_writing(piece_block(0,0), &tmp1);
|
||||||
|
p->write_failed(piece_block(0,0));
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());
|
||||||
|
|
||||||
|
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::fast);
|
||||||
|
p->mark_as_writing(piece_block(0,0), &tmp1);
|
||||||
|
p->mark_as_finished(piece_block(0,0), &tmp1);
|
||||||
|
p->abort_download(piece_block(0,0));
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) == picked.end());
|
||||||
|
|
||||||
|
p = setup_picker("1111111", " ", "7110000", "");
|
||||||
|
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::fast);
|
||||||
|
p->mark_as_finished(piece_block(0,1), 0);
|
||||||
|
p->piece_info(0, st);
|
||||||
|
TEST_CHECK(st.requested == 1);
|
||||||
|
TEST_CHECK(st.finished == 1);
|
||||||
|
TEST_CHECK(st.state == piece_picker::fast);
|
||||||
|
p->abort_download(piece_block(0,0));
|
||||||
|
p->piece_info(0, st);
|
||||||
|
TEST_CHECK(st.requested == 0);
|
||||||
|
TEST_CHECK(st.finished == 1);
|
||||||
|
TEST_CHECK(st.state == piece_picker::none);
|
||||||
|
picked = pick_pieces(p, "*******", blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
|
, options, empty_vector);
|
||||||
|
TEST_CHECK(p->is_requested(piece_block(0, 0)) == false);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(0,0)) != picked.end());
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
// make sure the block that is picked is from piece 1, since it
|
// make sure the block that is picked is from piece 1, since it
|
||||||
// it is the piece with the lowest availability
|
// it is the piece with the lowest availability
|
||||||
print_title("test pick lowest availability");
|
print_title("test pick lowest availability");
|
||||||
p = setup_picker("2223333", "* * * ", "", "");
|
p = setup_picker("2223333", "* * * ", "", "");
|
||||||
picked.clear();
|
TEST_CHECK(test_pick(p) == 1);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) > 0);
|
|
||||||
TEST_CHECK(picked.front().piece_index == 1);
|
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// make sure pieces with equal priority and availability
|
||||||
|
// are picked at random
|
||||||
|
print_title("test random pick at same priority");
|
||||||
|
std::map<int, int> random_prio_pieces;
|
||||||
|
for (int i = 0; i < 100; ++i)
|
||||||
|
{
|
||||||
|
p = setup_picker("1111112", " ", "", "");
|
||||||
|
++random_prio_pieces[test_pick(p)];
|
||||||
|
}
|
||||||
|
TEST_CHECK(random_prio_pieces.size() == 6);
|
||||||
|
for (std::map<int, int>::iterator i = random_prio_pieces.begin()
|
||||||
|
, end(random_prio_pieces.end()); i != end; ++i)
|
||||||
|
std::cout << i->first << ": " << i->second << " ";
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// make sure the block that is picked is from piece 5, since it
|
// make sure the block that is picked is from piece 5, since it
|
||||||
// has the highest priority among the available pieces
|
// has the highest priority among the available pieces
|
||||||
print_title("test pick highest priority");
|
print_title("test pick highest priority");
|
||||||
p = setup_picker("1111111", "* * * ", "1111122", "");
|
p = setup_picker("1111111", "* * * ", "1111121", "");
|
||||||
picked.clear();
|
TEST_CHECK(test_pick(p) == 5);
|
||||||
p->pick_pieces(string2vec("****** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
// ========================================================
|
||||||
TEST_CHECK(int(picked.size()) > 0);
|
|
||||||
TEST_CHECK(picked.front().piece_index == 5);
|
print_title("test reverse rarest first");
|
||||||
|
p = setup_picker("4179253", " ", "", "");
|
||||||
|
picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, &peer_struct, piece_picker::fast
|
||||||
|
, piece_picker::rarest_first | piece_picker::reverse, empty_vector);
|
||||||
|
int expected_common_pieces[] = {3, 2, 5, 0, 6, 4, 1};
|
||||||
|
for (int i = 0; i < int(picked.size()); ++i)
|
||||||
|
TEST_CHECK(picked[i] == piece_block(expected_common_pieces[i / blocks_per_piece], i % blocks_per_piece));
|
||||||
|
|
||||||
|
// piece 3 should be prioritized since it's a partial
|
||||||
|
p = setup_picker("1122111", " ", "3333333", " 1 ");
|
||||||
|
TEST_CHECK(test_pick(p, piece_picker::rarest_first | piece_picker::reverse) == 3);
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// make sure the 4 blocks are picked from the same piece if
|
// make sure the 4 blocks are picked from the same piece if
|
||||||
// whole pieces are preferred. The only whole piece is 1.
|
// whole pieces are preferred. Priority and availability is more
|
||||||
|
// important. Piece 1 has the lowest availability even though
|
||||||
|
// it is not a whole piece
|
||||||
print_title("test pick whole pieces");
|
print_title("test pick whole pieces");
|
||||||
p = setup_picker("1111111", " ", "1111111", "1023460");
|
p = setup_picker("2212222", " ", "1111111", "1023460");
|
||||||
picked.clear();
|
picked = pick_pieces(p, "****** ", 1, 1, &peer_struct, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("****** "), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
|
TEST_CHECK(int(picked.size()) == 3);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
|
||||||
for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
|
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 == 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);
|
||||||
|
for (int i = 0; i < blocks_per_piece && i < int(picked.size()); ++i)
|
||||||
|
TEST_CHECK(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);
|
||||||
|
for (int i = 0; i < int(picked.size()); ++i)
|
||||||
|
TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece));
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
|
@ -259,22 +388,23 @@ int test_main()
|
||||||
// make sure filtered pieces are ignored
|
// make sure filtered pieces are ignored
|
||||||
print_title("test filtered pieces");
|
print_title("test filtered pieces");
|
||||||
p = setup_picker("1111111", " ", "0010000", "");
|
p = setup_picker("1111111", " ", "0010000", "");
|
||||||
picked.clear();
|
TEST_CHECK(test_pick(p, piece_picker::rarest_first) == 2);
|
||||||
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
TEST_CHECK(test_pick(p, piece_picker::rarest_first | piece_picker::reverse) == 2);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(test_pick(p, piece_picker::sequential) == 2);
|
||||||
TEST_CHECK(int(picked.size()) > 0);
|
TEST_CHECK(test_pick(p, piece_picker::sequential | piece_picker::reverse) == 2);
|
||||||
TEST_CHECK(picked.front().piece_index == 2);
|
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// make sure we_dont_have works
|
// make sure we_dont_have works
|
||||||
print_title("test we_dont_have");
|
print_title("test we_dont_have");
|
||||||
p = setup_picker("1111111", "*******", "0100000", "");
|
p = setup_picker("1111111", "*******", "0100000", "");
|
||||||
picked.clear();
|
TEST_CHECK(p->have_piece(1));
|
||||||
|
TEST_CHECK(p->have_piece(2));
|
||||||
p->we_dont_have(1);
|
p->we_dont_have(1);
|
||||||
p->we_dont_have(2);
|
p->we_dont_have(2);
|
||||||
p->pick_pieces(string2vec("*** ** "), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
TEST_CHECK(!p->have_piece(1));
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(!p->have_piece(2));
|
||||||
|
picked = pick_pieces(p, "*** ** ", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
TEST_CHECK(int(picked.size()) > 0);
|
TEST_CHECK(int(picked.size()) > 0);
|
||||||
TEST_CHECK(picked.front().piece_index == 1);
|
TEST_CHECK(picked.front().piece_index == 1);
|
||||||
|
|
||||||
|
@ -309,76 +439,122 @@ int test_main()
|
||||||
|
|
||||||
// make sure requested blocks aren't picked
|
// make sure requested blocks aren't picked
|
||||||
print_title("test don't pick requested blocks");
|
print_title("test don't pick requested blocks");
|
||||||
p = setup_picker("1234567", " ", "", "");
|
p = setup_picker("1111111", " ", "", "");
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) > 0);
|
TEST_CHECK(int(picked.size()) > 0);
|
||||||
TEST_CHECK(picked.front().piece_index == 0);
|
|
||||||
piece_block first = picked.front();
|
piece_block first = picked.front();
|
||||||
p->mark_as_downloading(picked.front(), &peer_struct, piece_picker::fast);
|
p->mark_as_downloading(picked.front(), &peer_struct, piece_picker::fast);
|
||||||
TEST_CHECK(p->num_peers(picked.front()) == 1);
|
TEST_CHECK(p->num_peers(picked.front()) == 1);
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) > 0);
|
TEST_CHECK(int(picked.size()) > 0);
|
||||||
TEST_CHECK(picked.front() != first);
|
TEST_CHECK(picked.front() != first);
|
||||||
TEST_CHECK(picked.front().piece_index == 0);
|
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
/*
|
|
||||||
// test sequenced download
|
// make sure downloading pieces have higher priority
|
||||||
|
print_title("test downloading piece priority");
|
||||||
|
p = setup_picker("1111111", " ", "", "");
|
||||||
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
|
TEST_CHECK(int(picked.size()) > 0);
|
||||||
|
first = picked.front();
|
||||||
|
p->mark_as_downloading(picked.front(), &peer_struct, piece_picker::fast);
|
||||||
|
TEST_CHECK(p->num_peers(picked.front()) == 1);
|
||||||
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
|
TEST_CHECK(int(picked.size()) > 0);
|
||||||
|
TEST_CHECK(picked.front() != first);
|
||||||
|
TEST_CHECK(picked.front().piece_index == first.piece_index);
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// make sure downloading pieces closer to completion have higher priority
|
||||||
|
// piece 3 has only 1 block from being completed, and should be picked
|
||||||
|
print_title("test downloading piece order");
|
||||||
|
p = setup_picker("1111111", " ", "", "013700f");
|
||||||
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast
|
||||||
|
, options | piece_picker::prioritize_partials, empty_vector);
|
||||||
|
TEST_CHECK(int(picked.size()) > 0);
|
||||||
|
TEST_CHECK(picked.front() == piece_block(3, 3));
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// test sequential download
|
||||||
|
print_title("test sequential download");
|
||||||
p = setup_picker("7654321", " ", "", "");
|
p = setup_picker("7654321", " ", "", "");
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
p->set_sequenced_download_threshold(3);
|
, piece_picker::sequential, empty_vector);
|
||||||
p->pick_pieces(string2vec("***** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece);
|
||||||
print_pick(picked);
|
for (int i = 0; i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece));
|
||||||
TEST_CHECK(int(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 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(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();
|
// test reverse sequential download
|
||||||
p->set_sequenced_download_threshold(2);
|
print_title("test reverse sequential download");
|
||||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
p = setup_picker("7654321", " ", "", "");
|
||||||
print_pick(picked);
|
picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0, piece_picker::fast
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
, piece_picker::sequential | piece_picker::reverse, empty_vector);
|
||||||
TEST_CHECK(int(picked.size()) == 6 * blocks_per_piece);
|
TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece);
|
||||||
for (int i = 0; i < 6 * blocks_per_piece && i < int(picked.size()); ++i)
|
for (int i = 0; i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece);
|
TEST_CHECK(picked[i] == piece_block(6 - (i / blocks_per_piece), i % blocks_per_piece));
|
||||||
|
|
||||||
picked.clear();
|
// ========================================================
|
||||||
|
|
||||||
|
// test cursors
|
||||||
|
print_title("test cursors");
|
||||||
|
p = setup_picker("7654321", " ", "", "");
|
||||||
|
TEST_CHECK(p->cursor() == 0);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
|
p->we_have(1);
|
||||||
|
TEST_CHECK(p->cursor() == 0);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
|
p->we_have(0);
|
||||||
|
TEST_CHECK(p->cursor() == 2);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
|
p->we_have(5);
|
||||||
|
TEST_CHECK(p->cursor() == 2);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
|
p->we_have(6);
|
||||||
|
TEST_CHECK(p->cursor() == 2);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 5);
|
||||||
|
p->we_have(4);
|
||||||
|
p->we_have(3);
|
||||||
|
p->we_have(2);
|
||||||
|
TEST_CHECK(p->cursor() == 7);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 0);
|
||||||
|
p->we_dont_have(3);
|
||||||
|
TEST_CHECK(p->cursor() == 3);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 4);
|
||||||
|
|
||||||
|
p = setup_picker("7654321", " ", "", "");
|
||||||
|
TEST_CHECK(p->cursor() == 0);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
|
p->set_piece_priority(1, 0);
|
||||||
|
TEST_CHECK(p->cursor() == 0);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
p->set_piece_priority(0, 0);
|
p->set_piece_priority(0, 0);
|
||||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
TEST_CHECK(p->cursor() == 2);
|
||||||
print_pick(picked);
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
p->set_piece_priority(5, 0);
|
||||||
TEST_CHECK(int(picked.size()) == 5 * blocks_per_piece);
|
TEST_CHECK(p->cursor() == 2);
|
||||||
for (int i = 0; i < 5 * blocks_per_piece && i < int(picked.size()); ++i)
|
TEST_CHECK(p->reverse_cursor() == 7);
|
||||||
TEST_CHECK(picked[i].piece_index == i / blocks_per_piece + 1);
|
p->set_piece_priority(6, 0);
|
||||||
|
TEST_CHECK(p->cursor() == 2);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 5);
|
||||||
|
p->set_piece_priority(4, 0);
|
||||||
|
p->set_piece_priority(3, 0);
|
||||||
|
p->set_piece_priority(2, 0);
|
||||||
|
TEST_CHECK(p->cursor() == 7);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 0);
|
||||||
|
p->set_piece_priority(3, 1);
|
||||||
|
TEST_CHECK(p->cursor() == 3);
|
||||||
|
TEST_CHECK(p->reverse_cursor() == 4);
|
||||||
|
|
||||||
|
|
||||||
picked.clear();
|
|
||||||
p->set_piece_priority(0, 1);
|
|
||||||
p->pick_pieces(string2vec("****** "), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(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);
|
|
||||||
*/
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// test piece priorities
|
// test piece priorities
|
||||||
print_title("test piece priorities");
|
print_title("test piece priorities");
|
||||||
p = setup_picker("5555555", " ", "3214576", "");
|
p = setup_picker("5555555", " ", "7654321", "");
|
||||||
TEST_CHECK(p->num_filtered() == 0);
|
TEST_CHECK(p->num_filtered() == 0);
|
||||||
TEST_CHECK(p->num_have_filtered() == 0);
|
TEST_CHECK(p->num_have_filtered() == 0);
|
||||||
p->set_piece_priority(0, 0);
|
p->set_piece_priority(0, 0);
|
||||||
|
@ -389,25 +565,34 @@ int test_main()
|
||||||
TEST_CHECK(p->num_filtered() == 0);
|
TEST_CHECK(p->num_filtered() == 0);
|
||||||
TEST_CHECK(p->num_have_filtered() == 1);
|
TEST_CHECK(p->num_have_filtered() == 1);
|
||||||
|
|
||||||
picked.clear();
|
p->we_dont_have(0);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 6 * blocks_per_piece, false, 0, piece_picker::fast, true, false, empty_vector);
|
p->set_piece_priority(0, 7);
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0
|
||||||
TEST_CHECK(int(picked.size()) == 6 * blocks_per_piece);
|
, piece_picker::fast, options, empty_vector);
|
||||||
TEST_CHECK(picked[0 * blocks_per_piece].piece_index == 5);
|
TEST_CHECK(int(picked.size()) == 7 * blocks_per_piece);
|
||||||
// priority 5 and 6 is currently the same
|
|
||||||
TEST_CHECK(picked[1 * blocks_per_piece].piece_index == 6 || picked[1 * blocks_per_piece].piece_index == 4);
|
for (int i = 0; i < int(picked.size()); ++i)
|
||||||
TEST_CHECK(picked[2 * blocks_per_piece].piece_index == 6 || picked[2 * blocks_per_piece].piece_index == 4);
|
TEST_CHECK(picked[i] == piece_block(i / blocks_per_piece, i % blocks_per_piece));
|
||||||
TEST_CHECK(picked[3 * blocks_per_piece].piece_index == 3);
|
|
||||||
TEST_CHECK(picked[4 * blocks_per_piece].piece_index == 1);
|
// test changing priority on a piece we have
|
||||||
TEST_CHECK(picked[5 * blocks_per_piece].piece_index == 2);
|
p->we_have(0);
|
||||||
|
p->set_piece_priority(0, 0);
|
||||||
|
p->set_piece_priority(0, 1);
|
||||||
|
p->set_piece_priority(0, 0);
|
||||||
|
|
||||||
std::vector<int> prios;
|
std::vector<int> prios;
|
||||||
p->piece_priorities(prios);
|
p->piece_priorities(prios);
|
||||||
TEST_CHECK(prios.size() == 7);
|
TEST_CHECK(prios.size() == 7);
|
||||||
int prio_comp[] = {0, 2, 1, 4, 5, 7, 6};
|
int prio_comp[] = {0, 6, 5, 4, 3, 2, 1};
|
||||||
TEST_CHECK(std::equal(prios.begin(), prios.end(), prio_comp));
|
TEST_CHECK(std::equal(prios.begin(), prios.end(), prio_comp));
|
||||||
|
|
||||||
|
std::vector<bool> filter;
|
||||||
|
p->filtered_pieces(filter);
|
||||||
|
TEST_CHECK(prios.size() == 7);
|
||||||
|
bool filter_comp[] = {true, false, false, false, false, false, false};
|
||||||
|
TEST_CHECK(std::equal(filter.begin(), filter.end(), filter_comp));
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// test restore_piece
|
// test restore_piece
|
||||||
|
@ -418,18 +603,12 @@ int test_main()
|
||||||
p->mark_as_finished(piece_block(0,2), 0);
|
p->mark_as_finished(piece_block(0,2), 0);
|
||||||
p->mark_as_finished(piece_block(0,3), 0);
|
p->mark_as_finished(piece_block(0,3), 0);
|
||||||
|
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 1);
|
TEST_CHECK(int(picked.size()) >= 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 1);
|
TEST_CHECK(picked.front().piece_index == 1);
|
||||||
|
|
||||||
p->restore_piece(0);
|
p->restore_piece(0);
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 1);
|
TEST_CHECK(int(picked.size()) >= 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 0);
|
TEST_CHECK(picked.front().piece_index == 0);
|
||||||
|
|
||||||
|
@ -439,46 +618,128 @@ int test_main()
|
||||||
p->mark_as_finished(piece_block(0,3), 0);
|
p->mark_as_finished(piece_block(0,3), 0);
|
||||||
p->set_piece_priority(0, 0);
|
p->set_piece_priority(0, 0);
|
||||||
|
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 1);
|
TEST_CHECK(int(picked.size()) >= 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 1);
|
TEST_CHECK(picked.front().piece_index == 1);
|
||||||
|
|
||||||
p->restore_piece(0);
|
p->restore_piece(0);
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 1);
|
TEST_CHECK(int(picked.size()) >= 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 1);
|
TEST_CHECK(picked.front().piece_index == 1);
|
||||||
|
|
||||||
p->set_piece_priority(0, 1);
|
p->set_piece_priority(0, 1);
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 1);
|
TEST_CHECK(int(picked.size()) >= 1);
|
||||||
TEST_CHECK(picked.front().piece_index == 0);
|
TEST_CHECK(picked.front().piece_index == 0);
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// test non-rarest-first mode
|
// test random mode
|
||||||
print_title("test not rarest first");
|
print_title("test random pick");
|
||||||
p = setup_picker("1234567", "* * * ", "1111122", "");
|
p = setup_picker("1234567", " ", "1111122", "");
|
||||||
picked.clear();
|
std::set<int> random_pieces;
|
||||||
p->pick_pieces(string2vec("****** "), picked, 5 * blocks_per_piece, false, 0, piece_picker::fast, false, false, empty_vector);
|
for (int i = 0; i < 100; ++i)
|
||||||
print_pick(picked);
|
random_pieces.insert(test_pick(p, 0));
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
TEST_CHECK(random_pieces.size() == 7);
|
||||||
TEST_CHECK(int(picked.size()) == 3 * blocks_per_piece);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4 * blocks_per_piece && i < int(picked.size()); ++i)
|
random_pieces.clear();
|
||||||
|
for (int i = 0; i < 7; ++i)
|
||||||
{
|
{
|
||||||
TEST_CHECK(picked[i].piece_index != 0);
|
int piece = test_pick(p, 0);
|
||||||
TEST_CHECK(picked[i].piece_index != 2);
|
p->we_have(piece);
|
||||||
TEST_CHECK(picked[i].piece_index != 4);
|
random_pieces.insert(piece);
|
||||||
}
|
}
|
||||||
|
TEST_CHECK(random_pieces.size() == 7);
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// make sure that blocks from a slow piece are picked
|
||||||
|
// by a fast peer if there are no other options
|
||||||
|
print_title("test downloading piece affinity");
|
||||||
|
p = setup_picker("1111111", " ", "", "");
|
||||||
|
p->mark_as_downloading(piece_block(2,2), &tmp1, piece_picker::slow);
|
||||||
|
picked = pick_pieces(p, "*******", 7 * blocks_per_piece - 1, 0, &tmp2
|
||||||
|
, 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());
|
||||||
|
// piece 2 sould be the last one (least matching piece to pick)
|
||||||
|
TEST_CHECK(picked[7 * blocks_per_piece - 2].piece_index == 2);
|
||||||
|
TEST_CHECK(picked[7 * blocks_per_piece - 3].piece_index == 2);
|
||||||
|
TEST_CHECK(picked[7 * blocks_per_piece - 4].piece_index == 2);
|
||||||
|
|
||||||
|
// test the affinity of pieces with the same speed state
|
||||||
|
p = setup_picker("1111111", " ", "", "");
|
||||||
|
p->mark_as_downloading(piece_block(3,2), &tmp1, piece_picker::slow);
|
||||||
|
p->mark_as_downloading(piece_block(2,2), &tmp1, piece_picker::medium);
|
||||||
|
p->mark_as_downloading(piece_block(4,2), &tmp1, piece_picker::fast);
|
||||||
|
picked = pick_pieces(p, "*******", 2 * blocks_per_piece, 0, 0
|
||||||
|
, piece_picker::fast, piece_picker::prioritize_partials, empty_vector);
|
||||||
|
TEST_CHECK(picked.size() == 2 * blocks_per_piece);
|
||||||
|
TEST_CHECK(picked[0].piece_index == 4);
|
||||||
|
TEST_CHECK(picked[blocks_per_piece - 1].piece_index == 2);
|
||||||
|
TEST_CHECK(picked[2 * blocks_per_piece - 2].piece_index == 3);
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// make sure the piece picker will pick pieces that
|
||||||
|
// are already requested from other peers if it has to
|
||||||
|
print_title("test picking downloading blocks");
|
||||||
|
p = setup_picker("1111111", " ", "", "");
|
||||||
|
p->mark_as_downloading(piece_block(2,2), &tmp1, piece_picker::fast);
|
||||||
|
p->mark_as_downloading(piece_block(1,2), &tmp1, piece_picker::slow);
|
||||||
|
|
||||||
|
picked.clear();
|
||||||
|
p->pick_pieces(string2vec("*******"), picked, 7 * blocks_per_piece, 0, 0
|
||||||
|
, piece_picker::fast, piece_picker::prioritize_partials, empty_vector);
|
||||||
|
TEST_CHECK(verify_pick(p, picked, true));
|
||||||
|
print_pick(picked);
|
||||||
|
TEST_CHECK(picked.size() == 7 * blocks_per_piece);
|
||||||
|
|
||||||
|
picked.clear();
|
||||||
|
p->pick_pieces(string2vec("*******"), picked, 7 * blocks_per_piece, 0, 0
|
||||||
|
, piece_picker::fast, piece_picker::prioritize_partials
|
||||||
|
| piece_picker::rarest_first, empty_vector);
|
||||||
|
TEST_CHECK(verify_pick(p, picked, true));
|
||||||
|
print_pick(picked);
|
||||||
|
TEST_CHECK(picked.size() == 7 * blocks_per_piece);
|
||||||
|
|
||||||
|
picked.clear();
|
||||||
|
p->pick_pieces(string2vec("*******"), picked, 7 * blocks_per_piece, 0, 0
|
||||||
|
, piece_picker::fast, piece_picker::rarest_first, empty_vector);
|
||||||
|
TEST_CHECK(verify_pick(p, picked, true));
|
||||||
|
print_pick(picked);
|
||||||
|
TEST_CHECK(picked.size() == 7 * blocks_per_piece);
|
||||||
|
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
// test clear_peer
|
||||||
|
print_title("test clear_peer");
|
||||||
|
p = setup_picker("1123333", " ", "", "");
|
||||||
|
p->mark_as_downloading(piece_block(0, 0), &tmp1, piece_picker::slow);
|
||||||
|
p->mark_as_downloading(piece_block(0, 1), &tmp2, piece_picker::slow);
|
||||||
|
p->mark_as_downloading(piece_block(0, 2), &tmp3, piece_picker::slow);
|
||||||
|
p->mark_as_downloading(piece_block(1, 1), &tmp1, piece_picker::slow);
|
||||||
|
p->mark_as_downloading(piece_block(2, 1), &tmp2, piece_picker::slow);
|
||||||
|
p->mark_as_downloading(piece_block(3, 1), &tmp3, piece_picker::slow);
|
||||||
|
|
||||||
|
std::vector<void*> dls;
|
||||||
|
void* expected_dls1[] = {&tmp1, &tmp2, &tmp3, 0};
|
||||||
|
void* expected_dls2[] = {0, &tmp1, 0, 0};
|
||||||
|
void* expected_dls3[] = {0, &tmp2, 0, 0};
|
||||||
|
void* expected_dls4[] = {0, &tmp3, 0, 0};
|
||||||
|
void* expected_dls5[] = {&tmp1, 0, &tmp3, 0};
|
||||||
|
p->get_downloaders(dls, 0);
|
||||||
|
TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls1));
|
||||||
|
p->get_downloaders(dls, 1);
|
||||||
|
TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls2));
|
||||||
|
p->get_downloaders(dls, 2);
|
||||||
|
TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls3));
|
||||||
|
p->get_downloaders(dls, 3);
|
||||||
|
TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls4));
|
||||||
|
|
||||||
|
p->clear_peer(&tmp2);
|
||||||
|
p->get_downloaders(dls, 0);
|
||||||
|
TEST_CHECK(std::equal(dls.begin(), dls.end(), expected_dls5));
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
|
@ -505,7 +766,7 @@ int test_main()
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// test have_all and have_none with sequential download
|
// test have_all and have_none
|
||||||
print_title("test have_all and have_none with sequential download");
|
print_title("test have_all and have_none with sequential download");
|
||||||
p = setup_picker("0123333", "* ", "", "");
|
p = setup_picker("0123333", "* ", "", "");
|
||||||
dc = p->distributed_copies();
|
dc = p->distributed_copies();
|
||||||
|
@ -515,17 +776,6 @@ int test_main()
|
||||||
dc = p->distributed_copies();
|
dc = p->distributed_copies();
|
||||||
std::cout << "distributed copies: " << dc << std::endl;
|
std::cout << "distributed copies: " << dc << std::endl;
|
||||||
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
|
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
|
||||||
p->sequential_download(true);
|
|
||||||
p->dec_refcount_all();
|
|
||||||
dc = p->distributed_copies();
|
|
||||||
std::cout << "distributed copies: " << dc << std::endl;
|
|
||||||
TEST_CHECK(fabs(dc - (1.f + 5.f / 7.f)) < 0.01f);
|
|
||||||
p->inc_refcount(0);
|
|
||||||
p->dec_refcount_all();
|
|
||||||
dc = p->distributed_copies();
|
|
||||||
std::cout << "distributed copies: " << dc << std::endl;
|
|
||||||
TEST_CHECK(fabs(dc - (0.f + 6.f / 7.f)) < 0.01f);
|
|
||||||
p->inc_refcount(1);
|
|
||||||
TEST_CHECK(test_pick(p) == 1);
|
TEST_CHECK(test_pick(p) == 1);
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
@ -546,40 +796,15 @@ int test_main()
|
||||||
p->dec_refcount(5);
|
p->dec_refcount(5);
|
||||||
p->inc_refcount(5);
|
p->inc_refcount(5);
|
||||||
|
|
||||||
p->inc_refcount(0);
|
bitfield bits(7);
|
||||||
p->dec_refcount(4);
|
bits.clear_all();
|
||||||
|
bits.set_bit(0);
|
||||||
|
p->inc_refcount(bits);
|
||||||
|
bits.clear_all();
|
||||||
|
bits.set_bit(4);
|
||||||
|
p->dec_refcount(bits);
|
||||||
TEST_CHECK(test_pick(p) == 0);
|
TEST_CHECK(test_pick(p) == 0);
|
||||||
|
|
||||||
// ========================================================
|
|
||||||
/*
|
|
||||||
// test have_all and have_none, with a sequenced download threshold
|
|
||||||
p = setup_picker("1233333", "* ", "", "");
|
|
||||||
p->set_sequenced_download_threshold(3);
|
|
||||||
p->inc_refcount_all();
|
|
||||||
dc = p->distributed_copies();
|
|
||||||
TEST_CHECK(fabs(dc - (3.f + 5.f / 7.f)) < 0.01f);
|
|
||||||
p->dec_refcount_all();
|
|
||||||
dc = p->distributed_copies();
|
|
||||||
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
|
|
||||||
p->dec_refcount(2);
|
|
||||||
dc = p->distributed_copies();
|
|
||||||
TEST_CHECK(fabs(dc - (2.f + 4.f / 7.f)) < 0.01f);
|
|
||||||
p->mark_as_downloading(piece_block(1,0), &peer_struct, piece_picker::fast);
|
|
||||||
p->mark_as_downloading(piece_block(1,1), &peer_struct, piece_picker::fast);
|
|
||||||
p->we_have(1);
|
|
||||||
dc = p->distributed_copies();
|
|
||||||
TEST_CHECK(fabs(dc - (2.f + 5.f / 7.f)) < 0.01f);
|
|
||||||
picked.clear();
|
|
||||||
// make sure it won't pick the piece we just got
|
|
||||||
p->pick_pieces(string2vec(" * ****"), picked, 100, false, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(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);
|
|
||||||
*/
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
// test unverified_blocks, marking blocks and get_downloader
|
// test unverified_blocks, marking blocks and get_downloader
|
||||||
|
@ -592,7 +817,6 @@ int test_main()
|
||||||
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0);
|
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == 0);
|
||||||
p->mark_as_downloading(piece_block(4, 3), &peer_struct, piece_picker::fast);
|
p->mark_as_downloading(piece_block(4, 3), &peer_struct, piece_picker::fast);
|
||||||
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
|
TEST_CHECK(p->get_downloader(piece_block(4, 3)) == &peer_struct);
|
||||||
piece_picker::downloading_piece st;
|
|
||||||
p->piece_info(4, st);
|
p->piece_info(4, st);
|
||||||
TEST_CHECK(st.requested == 1);
|
TEST_CHECK(st.requested == 1);
|
||||||
TEST_CHECK(st.writing == 0);
|
TEST_CHECK(st.writing == 0);
|
||||||
|
@ -625,10 +849,7 @@ int test_main()
|
||||||
// test prefer_whole_pieces
|
// test prefer_whole_pieces
|
||||||
print_title("test prefer whole pieces");
|
print_title("test prefer whole pieces");
|
||||||
p = setup_picker("1111111", " ", "", "");
|
p = setup_picker("1111111", " ", "", "");
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 3, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, true, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
|
TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
|
||||||
piece_block b = picked.front();
|
piece_block b = picked.front();
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
|
@ -638,10 +859,7 @@ int test_main()
|
||||||
b = picked[i];
|
b = picked[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 3, 0, piece_picker::fast, options, empty_vector);
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, 3, 0, piece_picker::fast, false, false, empty_vector);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
|
TEST_CHECK(int(picked.size()) >= 3 * blocks_per_piece);
|
||||||
b = picked.front();
|
b = picked.front();
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
|
@ -650,6 +868,17 @@ int test_main()
|
||||||
== b.piece_index * blocks_per_piece + b.block_index + 1);
|
== b.piece_index * blocks_per_piece + b.block_index + 1);
|
||||||
b = picked[i];
|
b = picked[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure pieces that don't match the 'whole pieces' requirement
|
||||||
|
// 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);
|
||||||
|
TEST_CHECK(picked.size() == 7 * blocks_per_piece - 1);
|
||||||
|
TEST_CHECK(std::find(picked.begin(), picked.end(), piece_block(2,2)) == picked.end());
|
||||||
|
|
||||||
|
//#error test picking with partial pieces and other peers present so that both backup_pieces and backup_pieces2 are used
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
|
@ -657,28 +886,19 @@ int test_main()
|
||||||
print_title("test parole mode");
|
print_title("test parole mode");
|
||||||
p = setup_picker("3333133", " ", "", "");
|
p = setup_picker("3333133", " ", "", "");
|
||||||
p->mark_as_finished(piece_block(0, 0), 0);
|
p->mark_as_finished(piece_block(0, 0), 0);
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 1, 0, piece_picker::fast
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, 1, 0, piece_picker::fast, true, true, empty_vector);
|
, options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector);
|
||||||
print_pick(picked);
|
TEST_CHECK(int(picked.size()) == blocks_per_piece - 1);
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece - 1);
|
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
{
|
TEST_CHECK(picked[i] == piece_block(0, i + 1));
|
||||||
TEST_CHECK(picked[i].piece_index == 0);
|
|
||||||
TEST_CHECK(picked[i].block_index == i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure that the partial piece is not picked by a
|
// make sure that the partial piece is not picked by a
|
||||||
// peer that is has not downloaded/requested the other blocks
|
// peer that is has not downloaded/requested the other blocks
|
||||||
picked.clear();
|
picked = pick_pieces(p, "*******", 1, 1, &peer_struct, piece_picker::fast
|
||||||
p->pick_pieces(string2vec("*******"), picked, 1, 1, &peer_struct, piece_picker::fast, true, true, empty_vector);
|
, options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector);
|
||||||
print_pick(picked);
|
TEST_CHECK(int(picked.size()) == blocks_per_piece);
|
||||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
{
|
TEST_CHECK(picked[i] == piece_block(4, i));
|
||||||
TEST_CHECK(picked[i].piece_index == 4);
|
|
||||||
TEST_CHECK(picked[i].block_index == i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
|
|
||||||
|
@ -688,53 +908,29 @@ int test_main()
|
||||||
int v[] = {1, 5};
|
int v[] = {1, 5};
|
||||||
std::vector<int> suggested_pieces(v, v + 2);
|
std::vector<int> suggested_pieces(v, v + 2);
|
||||||
|
|
||||||
picked.clear();
|
picked = pick_pieces(p, "****************", 1, 1, 0, piece_picker::fast, options, suggested_pieces);
|
||||||
p->pick_pieces(string2vec("****************"), picked, 1, 1, 0, piece_picker::fast, true, true, suggested_pieces);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
{
|
TEST_CHECK(picked[i] == piece_block(1, i));
|
||||||
TEST_CHECK(picked[i].piece_index == 1);
|
|
||||||
TEST_CHECK(picked[i].block_index == i);
|
|
||||||
}
|
|
||||||
p->set_piece_priority(0, 0);
|
p->set_piece_priority(0, 0);
|
||||||
p->set_piece_priority(1, 0);
|
p->set_piece_priority(1, 0);
|
||||||
p->set_piece_priority(2, 0);
|
p->set_piece_priority(2, 0);
|
||||||
p->set_piece_priority(3, 0);
|
p->set_piece_priority(3, 0);
|
||||||
|
|
||||||
picked.clear();
|
picked = pick_pieces(p, "****************", 1, 1, 0, piece_picker::fast, options, suggested_pieces);
|
||||||
p->pick_pieces(string2vec("****************"), picked, 1, 1, 0, piece_picker::fast, true, true, suggested_pieces);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
{
|
TEST_CHECK(picked[i] == piece_block(5, i));
|
||||||
TEST_CHECK(picked[i].piece_index == 5);
|
|
||||||
TEST_CHECK(picked[i].block_index == i);
|
|
||||||
}
|
|
||||||
|
|
||||||
p = setup_picker("1111222233334444", "**** ", "", "");
|
p = setup_picker("1111222233334444", "**** ", "", "");
|
||||||
picked.clear();
|
picked = pick_pieces(p, "****************", 1, 1, 0, piece_picker::fast, options, suggested_pieces);
|
||||||
p->pick_pieces(string2vec("****************"), picked, 1, 1, 0, piece_picker::fast, true, true, suggested_pieces);
|
|
||||||
print_pick(picked);
|
|
||||||
TEST_CHECK(verify_pick(p, picked));
|
|
||||||
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
TEST_CHECK(int(picked.size()) >= blocks_per_piece);
|
||||||
for (int i = 1; i < int(picked.size()); ++i)
|
for (int i = 1; i < int(picked.size()); ++i)
|
||||||
{
|
TEST_CHECK(picked[i] == piece_block(5, i));
|
||||||
TEST_CHECK(picked[i].piece_index == 5);
|
|
||||||
TEST_CHECK(picked[i].block_index == i);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MISSING TESTS:
|
// MISSING TESTS:
|
||||||
// 2. inc_ref() from 0 to 1 while sequenced download threshold is 1
|
// 1. abort_download
|
||||||
// 4. filtered_pieces
|
// 2. write_failed
|
||||||
// 5. clear peer
|
|
||||||
// 6. pick_pieces with prefer whole pieces
|
|
||||||
// 7. is_requested
|
|
||||||
// 8. is_downloaded
|
|
||||||
// 9. get_downloaders
|
|
||||||
// 10. abort_download
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue