improve piece picker support for reverse picking (used for snubbed peers) to not cause priority inversion for regular peers
This commit is contained in:
parent
bc9281a27c
commit
097d5b484d
|
@ -1,3 +1,5 @@
|
|||
* improve piece picker support for reverse picking (used for snubbed peers)
|
||||
to not cause priority inversion for regular peers
|
||||
* improve piece picker to better support torrents with very large pieces
|
||||
and web seeds. (request large contiguous ranges, but not necessarily a
|
||||
whole piece).
|
||||
|
|
|
@ -53,7 +53,10 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/time.hpp"
|
||||
|
||||
// this is really only useful for debugging unit tests
|
||||
//#define TORRENT_PICKER_LOG
|
||||
|
||||
// heavy weight reference counting invariant checks
|
||||
//#define TORRENT_DEBUG_REFCOUNTS
|
||||
|
||||
#ifdef TORRENT_DEBUG_REFCOUNTS
|
||||
|
@ -112,7 +115,7 @@ namespace libtorrent
|
|||
// the number of priority levels
|
||||
priority_levels = 8,
|
||||
// priority factor
|
||||
prio_factor = priority_levels - 4
|
||||
prio_factor = 3
|
||||
};
|
||||
|
||||
struct block_info
|
||||
|
@ -139,6 +142,8 @@ namespace libtorrent
|
|||
// are considered fast peers or slow peers.
|
||||
// none is set if the blocks were downloaded
|
||||
// in a previous session
|
||||
// TODO:3 perhaps the piece_state feature could be removed. It's not
|
||||
// obvious that it has any effect
|
||||
enum piece_state_t
|
||||
{ none, slow, medium, fast };
|
||||
|
||||
|
@ -354,8 +359,10 @@ namespace libtorrent
|
|||
bool is_finished(piece_block block) const;
|
||||
|
||||
// marks this piece-block as queued for downloading
|
||||
// options are flags from options_t.
|
||||
bool mark_as_downloading(piece_block block, void* peer
|
||||
, piece_state_t s);
|
||||
, piece_state_t s, int options = 0);
|
||||
|
||||
// returns true if the block was marked as writing,
|
||||
// and false if the block is already finished or writing
|
||||
bool mark_as_writing(piece_block block, void* peer);
|
||||
|
@ -418,7 +425,8 @@ namespace libtorrent
|
|||
std::vector<piece_picker::downloading_piece> get_download_queue() const;
|
||||
int get_download_queue_size() const;
|
||||
|
||||
void get_download_queue_sizes(int* partial, int* full, int* finished, int* zero_prio) const;
|
||||
void get_download_queue_sizes(int* partial
|
||||
, int* full, int* finished, int* zero_prio) const;
|
||||
|
||||
void* get_downloader(piece_block block) const;
|
||||
|
||||
|
@ -454,7 +462,7 @@ namespace libtorrent
|
|||
void check_peer_invariant(bitfield const& have, void const* p) const;
|
||||
void check_invariant(const torrent* t = 0) const;
|
||||
#endif
|
||||
#if defined TORRENT_PICKER_LOG
|
||||
#if defined TORRENT_PICKER_LOG || defined TORRENT_DEBUG
|
||||
void print_pieces() const;
|
||||
#endif
|
||||
|
||||
|
@ -488,30 +496,86 @@ namespace libtorrent
|
|||
piece_pos() {}
|
||||
piece_pos(int peer_count_, int index_)
|
||||
: peer_count(peer_count_)
|
||||
, state(piece_pos::piece_open)
|
||||
, piece_priority(1)
|
||||
, download_state(piece_pos::piece_open)
|
||||
, piece_priority(4)
|
||||
, index(index_)
|
||||
{
|
||||
TORRENT_ASSERT(peer_count_ >= 0);
|
||||
TORRENT_ASSERT(index_ >= 0);
|
||||
}
|
||||
|
||||
// state of this piece.
|
||||
// download_state of this piece.
|
||||
enum state_t
|
||||
{
|
||||
// the piece is open to be picked
|
||||
piece_open,
|
||||
// the piece is partially downloaded or requested
|
||||
piece_downloading,
|
||||
// all blocks in the piece have been requested
|
||||
// partial pieces where all blocks in the piece have been requested
|
||||
piece_full,
|
||||
// all blocks in the piece have been received and
|
||||
// are either finished or writing
|
||||
// partial pieces where all blocks in the piece have been received
|
||||
// and are either finished or writing
|
||||
piece_finished,
|
||||
// pieces whose priority is 0
|
||||
piece_zero_prio
|
||||
// partial pieces whose priority is 0
|
||||
piece_zero_prio,
|
||||
|
||||
// the states up to this point indicate the piece is being
|
||||
// downloaded (or at least has a partially downloaded piece
|
||||
// in one of the m_downloads buckets).
|
||||
num_download_categories,
|
||||
|
||||
// the piece is open to be picked
|
||||
piece_open = num_download_categories,
|
||||
|
||||
// this is not a new download category/download list bucket.
|
||||
// it still goes into the piece_downloading bucket. However,
|
||||
// it indicates that this piece only has outstanding requests
|
||||
// form reverse peers. This is to de-prioritize it somewhat
|
||||
piece_downloading_reverse,
|
||||
piece_full_reverse
|
||||
};
|
||||
|
||||
// returns one of the valid download categories of state_t or
|
||||
// piece_open if this piece is not being downloaded
|
||||
int download_queue() const
|
||||
{
|
||||
if (download_state == piece_downloading_reverse)
|
||||
return piece_downloading;
|
||||
if (download_state == piece_full_reverse)
|
||||
return piece_full;
|
||||
return download_state;
|
||||
}
|
||||
|
||||
bool reverse() const
|
||||
{
|
||||
return download_state == piece_downloading_reverse
|
||||
|| download_state == piece_full_reverse;
|
||||
}
|
||||
|
||||
void unreverse()
|
||||
{
|
||||
switch (download_state)
|
||||
{
|
||||
case piece_downloading_reverse:
|
||||
download_state = piece_downloading;
|
||||
break;
|
||||
case piece_full_reverse:
|
||||
download_state = piece_full;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void make_reverse()
|
||||
{
|
||||
switch (download_state)
|
||||
{
|
||||
case piece_downloading:
|
||||
download_state = piece_downloading_reverse;
|
||||
break;
|
||||
case piece_full:
|
||||
download_state = piece_full_reverse;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the number of peers that has this piece
|
||||
// (availability)
|
||||
#if TORRENT_OPTIMIZE_MEMORY_USAGE
|
||||
|
@ -520,16 +584,31 @@ namespace libtorrent
|
|||
boost::uint32_t peer_count : 16;
|
||||
#endif
|
||||
|
||||
boost::uint32_t state : 3;
|
||||
// one of the enums from state_t. This indicates whether this piece
|
||||
// is currently being downloaded or not, and what state it's in if
|
||||
// it is. Specifically, as an optimization, pieces that have all blocks
|
||||
// requested from them are separated out into separate lists to make
|
||||
// lookups quicker. The main oddity is that whether a downloading piece
|
||||
// has only been requested from peers that are reverse, that's
|
||||
// recorded as piece_downloading_reverse, which really means the same
|
||||
// as piece_downloading, it just saves space to also indicate that it
|
||||
// has a bit lower priority. The reverse bit is only relevant if the
|
||||
// state is piece_downloadin.
|
||||
boost::uint32_t download_state : 3;
|
||||
|
||||
// TODO: 2 having 8 priority levels is probably excessive. It should
|
||||
// probably be changed to 3 levels + dont-download
|
||||
|
||||
// is 0 if the piece is filtered (not to be downloaded)
|
||||
// 1 is normal priority (default)
|
||||
// 2 is higher priority than pieces at the same availability level
|
||||
// 3 is same priority as partial pieces
|
||||
// 4 is higher priority than partial pieces
|
||||
// 5 and 6 same priority as availability 1 (ignores availability)
|
||||
// 7 is maximum priority (ignores availability)
|
||||
// 1 is low priority
|
||||
// 2 is low priority
|
||||
// 3 is mid priority
|
||||
// 4 is default priority
|
||||
// 5 is mid priority
|
||||
// 6 is high priority
|
||||
// 7 is high priority
|
||||
boost::uint32_t piece_priority : 3;
|
||||
|
||||
// index in to the piece_info vector
|
||||
#if TORRENT_OPTIMIZE_MEMORY_USAGE
|
||||
boost::uint32_t index : 17;
|
||||
|
@ -565,22 +644,29 @@ namespace libtorrent
|
|||
bool have() const { return index == we_have_index; }
|
||||
void set_have() { index = we_have_index; TORRENT_ASSERT(have()); }
|
||||
void set_not_have() { index = 0; TORRENT_ASSERT(!have()); }
|
||||
bool downloading() const { return state > 0; }
|
||||
bool downloading() const { return download_state != piece_open; }
|
||||
|
||||
bool filtered() const { return piece_priority == filter_priority; }
|
||||
|
||||
// prio 7 is always top priority
|
||||
// prio 0 is always -1 (don't pick)
|
||||
// downloading pieces are always on an even prio_factor priority
|
||||
// this function returns the effective priority of the piece. It's
|
||||
// actually the sort order of this piece compared to other pieces. A
|
||||
// lower index means it will be picked before a piece with a higher
|
||||
// index.
|
||||
// The availability of the piece (the number of peers that have this
|
||||
// piece) is fundamentally controlling the priority. It's multiplied
|
||||
// by 3 to form 3 levels of priority for each availability.
|
||||
//
|
||||
// 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 |
|
||||
// +---+---+---+---+
|
||||
// downloading pieces (not reverse)
|
||||
// | open pieces (not downloading)
|
||||
// | | downloading pieces (reverse peers)
|
||||
// | | |
|
||||
// +---+---+---+
|
||||
// | 0 | 1 | 2 |
|
||||
// +---+---+---+
|
||||
// this '3' is called prio_factor
|
||||
//
|
||||
// the manually set priority takes presedence over the availability
|
||||
// by multiplying availability by priority.
|
||||
|
||||
int priority(piece_picker const* picker) const
|
||||
{
|
||||
|
@ -588,23 +674,28 @@ namespace libtorrent
|
|||
// 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
|
||||
|| state == piece_full || state == piece_finished)
|
||||
|| download_state == piece_full
|
||||
|| download_state == piece_finished)
|
||||
return -1;
|
||||
|
||||
// prio 7 disregards availability
|
||||
if (piece_priority == priority_levels - 1) return 1 - downloading();
|
||||
TORRENT_ASSERT(piece_priority > 0);
|
||||
|
||||
// prio 4,5,6 halves the availability of a piece
|
||||
int availability = peer_count;
|
||||
int p = piece_priority;
|
||||
if (piece_priority >= priority_levels / 2)
|
||||
{
|
||||
availability /= 2;
|
||||
p -= (priority_levels - 2) / 2;
|
||||
}
|
||||
// this is to keep downloading pieces at higher priority than
|
||||
// pieces that are not being downloaded, and to make reverse
|
||||
// downloading pieces to be lower priority
|
||||
int adjustment = -2;
|
||||
if (reverse()) adjustment = -1;
|
||||
else if (download_state != piece_open) adjustment = -3;
|
||||
|
||||
if (downloading()) return availability * prio_factor;
|
||||
return availability * prio_factor + (priority_levels / 2) - p;
|
||||
// the + 1 here is because peer_count count be 0, it m_seeds
|
||||
// is > 0. We don't actually care about seeds (except for the
|
||||
// first one) since the order of the pieces is unaffected.
|
||||
int availability = int(peer_count) + 1;
|
||||
TORRENT_ASSERT(availability > 0);
|
||||
TORRENT_ASSERT(int(priority_levels - piece_priority) > 0);
|
||||
|
||||
return availability * int(priority_levels - piece_priority)
|
||||
* prio_factor + adjustment;
|
||||
}
|
||||
|
||||
bool operator!=(piece_pos p) const
|
||||
|
@ -654,10 +745,9 @@ namespace libtorrent
|
|||
|
||||
// returns an iterator to the downloading piece, whichever
|
||||
// download list it may live in now
|
||||
std::vector<downloading_piece>::iterator update_piece_state(std::vector<downloading_piece>::iterator dp);
|
||||
std::vector<downloading_piece>::iterator update_piece_state(
|
||||
std::vector<downloading_piece>::iterator dp);
|
||||
|
||||
// some compilers (e.g. gcc 2.95, does not inherit access
|
||||
// privileges to nested classes)
|
||||
private:
|
||||
|
||||
// the following vectors are mutable because they sometimes may
|
||||
|
@ -689,21 +779,15 @@ namespace libtorrent
|
|||
// 0, priority 1 starts at m_priority_boundries[0] etc.
|
||||
mutable std::vector<int> m_priority_boundries;
|
||||
|
||||
// each piece that's currently being downloaded
|
||||
// has an entry in this list with block allocations.
|
||||
// i.e. it says wich parts of the piece that
|
||||
// is being downloaded. This list is ordered
|
||||
// by piece index to make lookups efficient
|
||||
// there are 3 buckets of downloading pieces, each
|
||||
// is individually sorted by piece index.
|
||||
// 0: downloading pieces with unrequested blocks
|
||||
// 1: downloading pieces where every block is busy
|
||||
// and some are still in the requested state
|
||||
// 2: downloading pieces where every block is
|
||||
// finished or writing
|
||||
// 3: partial pieces whose priority is 0
|
||||
enum { num_download_categories = 4 };
|
||||
std::vector<downloading_piece> m_downloads[num_download_categories];
|
||||
// each piece that's currently being downloaded has an entry in this list
|
||||
// with block allocations. i.e. it says wich parts of the piece that is
|
||||
// being downloaded. This list is ordered by piece index to make lookups
|
||||
// efficient there are as many buckets as there are piece states. See
|
||||
// piece_pos::state_t. The only download state that does not have a
|
||||
// corresponding downloading_piece vector is piece_open and
|
||||
// piece_downloading_reverse (the latter uses the same as
|
||||
// piece_downloading).
|
||||
std::vector<downloading_piece> m_downloads[piece_pos::num_download_categories];
|
||||
|
||||
// this holds the information of the
|
||||
// blocks in partially downloaded pieces.
|
||||
|
|
|
@ -943,26 +943,13 @@ namespace libtorrent
|
|||
void piece_availability(std::vector<int>& avail) const;
|
||||
|
||||
// These functions are used to set and get the prioritiy of individual
|
||||
// pieces. By default all pieces have priority 1. That means that the
|
||||
// pieces. By default all pieces have priority 4. That means that the
|
||||
// random rarest first algorithm is effectively active for all pieces.
|
||||
// You may however change the priority of individual pieces. There are 8
|
||||
// different priority levels:
|
||||
//
|
||||
// 0. piece is not downloaded at all
|
||||
// 1. normal priority. Download order is dependent on availability
|
||||
// 2. higher than normal priority. Pieces are preferred over pieces with
|
||||
// the same availability, but not over pieces with lower availability
|
||||
// 3. pieces are as likely to be picked as partial pieces.
|
||||
// 4. pieces are preferred over partial pieces, but not over pieces with
|
||||
// lower availability
|
||||
// 5. *currently the same as 4*
|
||||
// 6. piece is as likely to be picked as any piece with availability 1
|
||||
// 7. maximum priority, availability is disregarded, the piece is
|
||||
// preferred over any other piece with lower priority
|
||||
//
|
||||
// The exact definitions of these priorities are implementation details,
|
||||
// and subject to change. The interface guarantees that higher number
|
||||
// means higher priority, and that 0 means do not download.
|
||||
// priority levels. 0 means not to download the piece at all. Otherwise,
|
||||
// lower priority values means less likely to be picked. Piece priority
|
||||
// takes presedence over piece availability. Every priority 7 piece will
|
||||
// be attempted to be picked before a priority 6 piece and so on.
|
||||
//
|
||||
// ``piece_priority`` sets or gets the priority for an individual piece,
|
||||
// specified by ``index``.
|
||||
|
|
|
@ -3367,7 +3367,8 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
if (!t->picker().mark_as_downloading(block, peer_info_struct(), state))
|
||||
if (!t->picker().mark_as_downloading(block, peer_info_struct(), state
|
||||
, picker_options()))
|
||||
{
|
||||
#if defined TORRENT_LOGGING
|
||||
peer_log("*** PIECE_PICKER [ not_picking: %d,%d failed to mark_as_downloading ]"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4435,14 +4435,16 @@ namespace libtorrent
|
|||
if (k->timed_out || k->not_wanted) continue;
|
||||
if (int(k->block.piece_index) != j->piece) continue;
|
||||
m_picker->mark_as_downloading(k->block, p->peer_info_struct()
|
||||
, (piece_picker::piece_state_t)p->peer_speed());
|
||||
, (piece_picker::piece_state_t)p->peer_speed()
|
||||
, p->picker_options());
|
||||
}
|
||||
for (std::vector<pending_block>::const_iterator k = rq.begin()
|
||||
, end(rq.end()); k != end; ++k)
|
||||
{
|
||||
if (int(k->block.piece_index) != j->piece) continue;
|
||||
m_picker->mark_as_downloading(k->block, p->peer_info_struct()
|
||||
, (piece_picker::piece_state_t)p->peer_speed());
|
||||
, (piece_picker::piece_state_t)p->peer_speed()
|
||||
, p->picker_options());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -625,7 +625,7 @@ void web_peer_connection::on_receive(error_code const& error
|
|||
// if the status code is not one of the accepted ones, abort
|
||||
if (!is_ok_status(m_parser.status_code()))
|
||||
{
|
||||
// TODO: 3 just make this peer not have the pieces
|
||||
// TODO: 2 just make this peer not have the pieces
|
||||
// associated with the file we just requested. Only
|
||||
// when it doesn't have any of the file do the following
|
||||
int retry_time = atoi(m_parser.header("retry-after").c_str());
|
||||
|
|
|
@ -257,14 +257,16 @@ std::vector<piece_block> pick_pieces(boost::shared_ptr<piece_picker> const& p
|
|||
{
|
||||
std::vector<piece_block> picked;
|
||||
counters pc;
|
||||
p->pick_pieces(string2vec(availability), picked, num_blocks, prefer_contiguous_blocks, 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));
|
||||
return picked;
|
||||
}
|
||||
|
||||
int test_pick(boost::shared_ptr<piece_picker> const& p, int options = piece_picker::rarest_first)
|
||||
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
|
||||
|
@ -360,14 +362,14 @@ int test_main()
|
|||
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);
|
||||
TEST_EQUAL(st.requested, 1);
|
||||
TEST_EQUAL(st.finished, 1);
|
||||
TEST_EQUAL(st.state, piece_picker::fast);
|
||||
p->abort_download(piece_block(0,0), tmp_peer);
|
||||
p->piece_info(0, st);
|
||||
TEST_CHECK(st.requested == 0);
|
||||
TEST_CHECK(st.finished == 1);
|
||||
TEST_CHECK(st.state == piece_picker::none);
|
||||
TEST_EQUAL(st.requested, 0);
|
||||
TEST_EQUAL(st.finished, 1);
|
||||
TEST_EQUAL(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);
|
||||
|
@ -437,9 +439,15 @@ int test_main()
|
|||
// make sure the block that is picked is from piece 5, since it
|
||||
// has the highest priority among the available pieces
|
||||
print_title("test pick highest priority");
|
||||
p = setup_picker("1111111", "* * * ", "1111121", "");
|
||||
p = setup_picker("1111111", " ", "1111121", "");
|
||||
TEST_CHECK(test_pick(p) == 5);
|
||||
|
||||
p = setup_picker("1111111", " ", "1171121", "");
|
||||
TEST_CHECK(test_pick(p) == 2);
|
||||
|
||||
p = setup_picker("1111111", " ", "1131521", "");
|
||||
TEST_CHECK(test_pick(p) == 4);
|
||||
|
||||
// ========================================================
|
||||
|
||||
print_title("test reverse rarest first");
|
||||
|
@ -450,9 +458,10 @@ int test_main()
|
|||
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
|
||||
// piece 3 should NOT be prioritized since it's a partial, and not
|
||||
// reversed. Reversed partials are considered reversed
|
||||
p = setup_picker("1122111", " ", "3333333", " 1 ");
|
||||
TEST_CHECK(test_pick(p, piece_picker::rarest_first | piece_picker::reverse) == 3);
|
||||
TEST_CHECK(test_pick(p, piece_picker::rarest_first | piece_picker::reverse) == 2);
|
||||
|
||||
// ========================================================
|
||||
|
||||
|
@ -462,14 +471,14 @@ 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 * blocks_per_piece
|
||||
picked = pick_pieces(p, "****** ", 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_EQUAL(picked[i].piece_index, 2);
|
||||
|
||||
p = setup_picker("1111111", " ", "1111111", "");
|
||||
picked = pick_pieces(p, "****** ", 1, 1 * blocks_per_piece
|
||||
picked = pick_pieces(p, "****** ", 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)
|
||||
|
@ -641,8 +650,9 @@ int test_main()
|
|||
picked = pick_pieces(p, "*******", 7 * blocks_per_piece, 0, 0, piece_picker::fast
|
||||
, piece_picker::sequential, empty_vector);
|
||||
|
||||
// the piece with priority 0 was not picked
|
||||
TEST_CHECK(int(picked.size()) == 6 * blocks_per_piece);
|
||||
// the piece with priority 0 was not picked, everything else should
|
||||
// be picked
|
||||
TEST_EQUAL(int(picked.size()), 6 * blocks_per_piece);
|
||||
|
||||
// the first two pieces picked should be 3 and 5 since those have priority 7
|
||||
for (int i = 0; i < 2 * blocks_per_piece; ++i)
|
||||
|
@ -650,7 +660,7 @@ int test_main()
|
|||
|
||||
int expected[] = {-1, -1, 0, 1, 2, 6};
|
||||
for (int i = 2 * blocks_per_piece; i < int(picked.size()); ++i)
|
||||
TEST_CHECK(picked[i].piece_index == expected[i / blocks_per_piece]);
|
||||
TEST_EQUAL(picked[i].piece_index, expected[i / blocks_per_piece]);
|
||||
|
||||
// ========================================================
|
||||
|
||||
|
@ -782,7 +792,7 @@ int test_main()
|
|||
TEST_CHECK(int(picked.size()) >= 1);
|
||||
TEST_CHECK(picked.front().piece_index == 1);
|
||||
|
||||
p->set_piece_priority(0, 1);
|
||||
p->set_piece_priority(0, 7);
|
||||
picked = pick_pieces(p, "*******", 1, 0, 0, piece_picker::fast, options, empty_vector);
|
||||
TEST_CHECK(int(picked.size()) >= 1);
|
||||
TEST_CHECK(picked.front().piece_index == 0);
|
||||
|
@ -874,7 +884,7 @@ 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 * blocks_per_piece, 0
|
||||
p->pick_pieces(string2vec(" * "), picked, 1, blocks_per_piece, 0
|
||||
, piece_picker::fast, piece_picker::rarest_first
|
||||
| piece_picker::align_expanded_pieces, empty_vector, 20
|
||||
, pc);
|
||||
|
@ -1108,7 +1118,7 @@ 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 * blocks_per_piece
|
||||
picked = pick_pieces(p, "*******", 7 * blocks_per_piece - 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());
|
||||
|
@ -1141,7 +1151,7 @@ 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 * blocks_per_piece, 0
|
||||
picked = pick_pieces(p, "*******", 1, blocks_per_piece, 0
|
||||
, piece_picker::fast
|
||||
, options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector);
|
||||
TEST_EQUAL(int(picked.size()), blocks_per_piece - 1);
|
||||
|
@ -1150,7 +1160,7 @@ int test_main()
|
|||
|
||||
// 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 * blocks_per_piece
|
||||
picked = pick_pieces(p, "*******", 1, blocks_per_piece
|
||||
, &peer_struct, piece_picker::fast
|
||||
, options | piece_picker::on_parole | piece_picker::prioritize_partials, empty_vector);
|
||||
TEST_EQUAL(int(picked.size()), blocks_per_piece);
|
||||
|
@ -1165,7 +1175,7 @@ int test_main()
|
|||
int v[] = {1, 5};
|
||||
std::vector<int> suggested_pieces(v, v + 2);
|
||||
|
||||
picked = pick_pieces(p, "****************", 1, 1 * blocks_per_piece
|
||||
picked = pick_pieces(p, "****************", 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)
|
||||
|
@ -1175,14 +1185,14 @@ int test_main()
|
|||
p->set_piece_priority(2, 0);
|
||||
p->set_piece_priority(3, 0);
|
||||
|
||||
picked = pick_pieces(p, "****************", 1, 1 * blocks_per_piece
|
||||
picked = pick_pieces(p, "****************", 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 * blocks_per_piece
|
||||
picked = pick_pieces(p, "****************", 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)
|
||||
|
@ -1195,13 +1205,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 * blocks_per_piece, 0);
|
||||
pick_pieces(p, "****************", 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 * blocks_per_piece, 0);
|
||||
pick_pieces(p, "****************", 1, blocks_per_piece, 0);
|
||||
p->inc_refcount(string2vec(" ** ** * * "), &tmp8);
|
||||
print_availability(p);
|
||||
TEST_CHECK(verify_availability(p, "1132123201220322"));
|
||||
|
@ -1213,25 +1223,25 @@ int test_main()
|
|||
p = setup_picker("0000000000000000", " ", "", "");
|
||||
|
||||
// make sure it's not dirty
|
||||
pick_pieces(p, "****************", 1, 1 * blocks_per_piece, 0);
|
||||
pick_pieces(p, "****************", 1, blocks_per_piece, 0);
|
||||
|
||||
p->inc_refcount_all(&tmp0);
|
||||
print_availability(p);
|
||||
TEST_CHECK(verify_availability(p, "1111111111111111"));
|
||||
|
||||
// make sure it's not dirty
|
||||
pick_pieces(p, "****************", 1, 1, 0);
|
||||
pick_pieces(p, "****************", 1, blocks_per_piece, 0);
|
||||
p->dec_refcount(string2vec(" **** ** "), &tmp0);
|
||||
print_availability(p);
|
||||
TEST_CHECK(verify_availability(p, "1100001100111111"));
|
||||
|
||||
// make sure it's not dirty
|
||||
pick_pieces(p, "****************", 1, 1, 0);
|
||||
pick_pieces(p, "****************", 1, blocks_per_piece, 0);
|
||||
p->inc_refcount(string2vec(" **** ** "), &tmp0);
|
||||
TEST_CHECK(verify_availability(p, "1111111111111111"));
|
||||
|
||||
// make sure it's not dirty
|
||||
pick_pieces(p, "****************", 1, 1, 0);
|
||||
pick_pieces(p, "****************", 1, blocks_per_piece, 0);
|
||||
p->dec_refcount_all(&tmp0);
|
||||
TEST_CHECK(verify_availability(p, "0000000000000000"));
|
||||
|
||||
|
@ -1240,13 +1250,64 @@ int test_main()
|
|||
TEST_CHECK(verify_availability(p, "1111111111111111"));
|
||||
|
||||
// make sure it's not dirty
|
||||
pick_pieces(p, "****************", 1, 1, 0);
|
||||
pick_pieces(p, "****************", 1, blocks_per_piece, 0);
|
||||
p->dec_refcount(3, &tmp1);
|
||||
print_availability(p);
|
||||
TEST_CHECK(verify_availability(p, "1110111111111111"));
|
||||
|
||||
// ========================================================
|
||||
|
||||
// test reversed peers
|
||||
print_title("test reversed peers");
|
||||
p = setup_picker("3333333", " *****", "", "");
|
||||
|
||||
// a reversed peer picked a block from piece 0
|
||||
// This should make the piece reversed
|
||||
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::slow
|
||||
, piece_picker::reverse);
|
||||
|
||||
TEST_EQUAL(test_pick(p, piece_picker::rarest_first), 1);
|
||||
|
||||
// make sure another reversed peer pick the same piece
|
||||
TEST_EQUAL(test_pick(p, piece_picker::rarest_first | piece_picker::reverse), 0);
|
||||
|
||||
// ========================================================
|
||||
|
||||
// test reversed pieces upgrading to normal pieces
|
||||
print_title("test reversed piece upgrade");
|
||||
|
||||
p = setup_picker("3333333", " *****", "", "");
|
||||
|
||||
// make piece 0 partial and reversed
|
||||
p->mark_as_downloading(piece_block(0,1), &tmp1, piece_picker::slow
|
||||
, piece_picker::reverse);
|
||||
TEST_EQUAL(test_pick(p), 1);
|
||||
|
||||
// now have a regular peer pick the reversed block. It should now
|
||||
// have turned into a regular one and be prioritized
|
||||
p->mark_as_downloading(piece_block(0,2), &tmp1, piece_picker::fast);
|
||||
TEST_EQUAL(test_pick(p), 0);
|
||||
|
||||
|
||||
// ========================================================
|
||||
|
||||
// test pieces downgrading to reversed pieces
|
||||
print_title("test reversed piece downgrade");
|
||||
// now make sure a piece can be demoted to reversed if there are no
|
||||
// other outstanding requests
|
||||
|
||||
p = setup_picker("3333333", " ", "", "");
|
||||
|
||||
// make piece 0 partial and not reversed
|
||||
p->mark_as_finished(piece_block(0,1), &tmp1);
|
||||
|
||||
// a reversed peer picked a block from piece 0
|
||||
// This should make the piece reversed
|
||||
p->mark_as_downloading(piece_block(0,0), &tmp1, piece_picker::slow
|
||||
, piece_picker::reverse);
|
||||
|
||||
TEST_EQUAL(test_pick(p, piece_picker::rarest_first | piece_picker::reverse), 0);
|
||||
|
||||
// MISSING TESTS:
|
||||
// 2. write_failed
|
||||
|
||||
|
|
Loading…
Reference in New Issue