piece picker fix for random mode

This commit is contained in:
Arvid Norberg 2015-02-08 21:12:10 +00:00
parent a8623a9b23
commit 497f7a4a27
3 changed files with 83 additions and 33 deletions

View File

@ -493,6 +493,7 @@ namespace libtorrent
public:
// TODO: 2 this type should not be public
struct piece_pos
{
piece_pos() {}

View File

@ -2228,7 +2228,7 @@ namespace libtorrent
bool done = false;
// skip pieces we can't pick, and suggested pieces
// since we've already picked those
while (!can_pick(piece, pieces)
while (!is_piece_free(piece, pieces)
|| std::find(suggested_pieces.begin()
, suggested_pieces.end(), piece)
!= suggested_pieces.end())
@ -2237,38 +2237,52 @@ namespace libtorrent
++piece;
if (piece == int(m_piece_map.size())) piece = 0;
// could not find any more pieces
if (piece == start_piece) { done = true; break; }
if (piece == start_piece) { goto get_out; }
}
if (done) break;
TORRENT_ASSERT(can_pick(piece, pieces));
TORRENT_ASSERT(m_piece_map[piece].downloading() == false);
int start, end;
boost::tie(start, end) = expand_piece(piece
, prefer_contiguous_blocks, pieces, options);
for (int k = start; k < end; ++k)
if (prefer_contiguous_blocks > 1 && !m_piece_map[piece].downloading())
{
TORRENT_ASSERT(m_piece_map[k].downloading() == false);
TORRENT_ASSERT(m_piece_map[k].priority(this) >= 0);
int num_blocks_in_piece = blocks_in_piece(k);
for (int j = 0; j < num_blocks_in_piece; ++j)
TORRENT_ASSERT(can_pick(piece, pieces));
TORRENT_ASSERT(m_piece_map[piece].downloading() == false);
int start, end;
boost::tie(start, end) = expand_piece(piece
, prefer_contiguous_blocks, pieces, options);
TORRENT_ASSERT(end - start > 0);
for (int k = start; k < end; ++k)
{
pc.inc_stats_counter(counters::piece_picker_rand_loops);
TORRENT_ASSERT(is_piece_free(k, pieces));
interesting_blocks.push_back(piece_block(k, j));
--num_blocks;
--prefer_contiguous_blocks;
if (prefer_contiguous_blocks == 0
&& num_blocks <= 0) break;
TORRENT_ASSERT(m_piece_map[k].downloading() == false);
TORRENT_ASSERT(m_piece_map[k].priority(this) >= 0);
int num_blocks_in_piece = blocks_in_piece(k);
for (int j = 0; j < num_blocks_in_piece; ++j)
{
pc.inc_stats_counter(counters::piece_picker_rand_loops);
TORRENT_ASSERT(is_piece_free(k, pieces));
interesting_blocks.push_back(piece_block(k, j));
--num_blocks;
--prefer_contiguous_blocks;
if (prefer_contiguous_blocks <= 0
&& num_blocks <= 0) break;
}
}
piece = end;
}
piece = end;
else
{
num_blocks = add_blocks(piece, pieces
, interesting_blocks, backup_blocks
, backup_blocks2, num_blocks
, prefer_contiguous_blocks, peer, empty_vector
, speed, options);
++piece;
}
if (piece == int(m_piece_map.size())) piece = 0;
// could not find any more pieces
if (piece == start_piece) break;
}
}
get_out:
if (num_blocks <= 0) return;
@ -2314,6 +2328,8 @@ namespace libtorrent
int c = 0;
#ifdef TORRENT_DEBUG
// if we get here, we're about to pick a busy block. First, make sure
// we really exhausted the available blocks
for (std::vector<downloading_piece>::const_iterator i
= m_downloads[piece_pos::piece_downloading].begin()
, end(m_downloads[piece_pos::piece_downloading].end()); i != end; ++i)
@ -2325,6 +2341,19 @@ namespace libtorrent
continue;
// we either don't have this piece, or we've already requested from it
if (!pieces[dp.index]) continue;
// if we already have the piece, obviously we should not have
// since this is a partial piece in the piece_downloading state, we
// should not already have it
TORRENT_ASSERT(!m_piece_map[dp.index].have());
// if it was filtered, it would be in the prio_zero queue
TORRENT_ASSERT(!m_piece_map[dp.index].filtered());
// we're not allowed to pick from locked pieces
if (dp.locked) continue;
bool found = false;
for (std::vector<piece_block>::const_iterator j
= interesting_blocks.begin(), end(interesting_blocks.end());
@ -2334,7 +2363,9 @@ namespace libtorrent
found = true;
break;
}
TORRENT_ASSERT(!pieces[dp.index] || found || dp.locked);
// we expect to find this piece in our interesting_blocks list
TORRENT_ASSERT(found);
}
#endif
@ -2891,7 +2922,6 @@ namespace libtorrent
int queue, int index)
{
TORRENT_ASSERT(queue >= 0 && queue < piece_pos::num_download_categories);
// return std::find_if(m_downloads[queue].begin(), m_downloads[queue].end(), has_index(index));
downloading_piece cmp;
cmp.index = index;
std::vector<piece_picker::downloading_piece>::iterator i = std::lower_bound(
@ -2904,15 +2934,7 @@ namespace libtorrent
std::vector<piece_picker::downloading_piece>::const_iterator piece_picker::find_dl_piece(
int queue, int index) const
{
TORRENT_ASSERT(queue >= 0 && queue < piece_pos::num_download_categories);
// return std::find_if(m_downloads[queue].begin(), m_downloads[queue].end(), has_index(index));
downloading_piece cmp;
cmp.index = index;
std::vector<piece_picker::downloading_piece>::const_iterator i = std::lower_bound(
m_downloads[queue].begin(), m_downloads[queue].end(), cmp);
if (i == m_downloads[queue].end()) return i;
if (i->index == index) return i;
return m_downloads[queue].end();
return const_cast<piece_picker*>(this)->find_dl_piece(queue, index);
}
std::vector<piece_picker::downloading_piece>::iterator

View File

@ -642,6 +642,33 @@ int test_main()
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front() == piece_block(3, 3));
// TODO: 3 if we use prioritize_partials + sequential, we should prefer
// the the partial pieces based on piece index instead
// ========================================================
// make sure the random piece picker can still pick partial pieces
print_title("test random picking (downloading piece)");
p = setup_picker("1111111", " ", "", "013700f");
picked = pick_pieces(p, " *** *", 1, 0, 0, piece_picker::fast
, 0, empty_vector);
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front() == piece_block(1, 1)
|| picked.front() == piece_block(2, 2)
|| picked.front() == piece_block(3, 3));
// make sure the random piece picker can still pick partial pieces
// even when prefer_contiguous_blocks is set
print_title("test random picking (downloading piece, prefer contiguous)");
p = setup_picker("1111111", " ", "", "013700f");
picked = pick_pieces(p, " *** *", 1, 4, 0, piece_picker::fast
, 0, empty_vector);
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front() == piece_block(1, 1)
|| picked.front() == piece_block(2, 2)
|| picked.front() == piece_block(3, 3));
// ========================================================
// test sequential download