piece picker optimization

This commit is contained in:
Arvid Norberg 2011-08-16 06:30:53 +00:00
parent 25ad24ec68
commit 1c5399b736
3 changed files with 63 additions and 19 deletions

View File

@ -383,6 +383,7 @@ namespace libtorrent
piece_pos(int peer_count_, int index_)
: peer_count(peer_count_)
, downloading(0)
, full(0)
, piece_priority(1)
, index(index_)
{
@ -392,9 +393,11 @@ namespace libtorrent
// the number of peers that has this piece
// (availability)
unsigned peer_count : 10;
unsigned peer_count : 9;
// is 1 if the piece is marked as being downloaded
unsigned downloading : 1;
// set when downloading, but no free blocks to request left
unsigned full : 1;
// 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
@ -415,7 +418,7 @@ namespace libtorrent
// the priority value that means the piece is filtered
filter_priority = 0,
// the max number the peer count can hold
max_peer_count = 0x3ff
max_peer_count = 0x1ff
};
bool have() const { return index == we_have_index; }
@ -499,6 +502,8 @@ namespace libtorrent
std::vector<downloading_piece>::const_iterator find_dl_piece(int index) const;
std::vector<downloading_piece>::iterator find_dl_piece(int index);
void update_full(downloading_piece& dp);
// some compilers (e.g. gcc 2.95, does not inherit access
// privileges to nested classes)
public:

View File

@ -276,7 +276,8 @@ namespace libtorrent
{
downloading_piece const& dp = *i;
downloading_piece const& next = *(i + 1);
TORRENT_ASSERT(dp.finished + dp.writing >= next.finished + next.writing);
// TORRENT_ASSERT(dp.finished + dp.writing >= next.finished + next.writing);
TORRENT_ASSERT(dp.index < next.index);
}
}
@ -314,6 +315,8 @@ namespace libtorrent
TORRENT_ASSERT(num_requested == i->requested);
TORRENT_ASSERT(num_writing == i->writing);
TORRENT_ASSERT(num_finished == i->finished);
if (m_piece_map[i->index].full)
TORRENT_ASSERT(num_finished + num_writing + num_requested == num_blocks);
}
int num_pieces = int(m_piece_map.size());
TORRENT_ASSERT(m_cursor >= 0);
@ -1399,6 +1402,11 @@ namespace libtorrent
, end(m_downloads.end()); i != end; ++i)
{
if (!pieces[i->index]) continue;
if (m_piece_map[i->index].full
&& backup_blocks.size() >= num_blocks
&& backup_blocks2.size() >= num_blocks)
continue;
num_blocks = add_blocks_downloading(*i, pieces
, interesting_blocks, backup_blocks, backup_blocks2
, num_blocks, prefer_whole_pieces, peer, speed, options);
@ -1563,22 +1571,27 @@ namespace libtorrent
if (num_blocks <= 0) return;
// we might have to re-pick some backup blocks
// from full pieces, since we skipped those the
// first pass over
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
, end(m_downloads.end()); i != end; ++i)
{
if (!pieces[i->index]) continue;
// we've already considered the non-full pieces
if (!m_piece_map[i->index].full) continue;
std::vector<piece_block> temp;
add_blocks_downloading(*i, pieces
, temp, backup_blocks, backup_blocks2
, num_blocks, prefer_whole_pieces, peer, speed, options);
}
#ifdef TORRENT_DEBUG
verify_pick(interesting_blocks, pieces);
verify_pick(backup_blocks, pieces);
verify_pick(backup_blocks2, pieces);
#endif
num_blocks = append_blocks(interesting_blocks, backup_blocks
, num_blocks);
if (num_blocks <= 0) return;
num_blocks = append_blocks(interesting_blocks, backup_blocks2, num_blocks);
if (num_blocks <= 0) return;
// don't double-pick anything if the peer is on parole
if (options & on_parole) return;
std::vector<piece_block> temp;
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
, end(m_downloads.end()); i != end; ++i)
@ -1603,6 +1616,16 @@ namespace libtorrent
if (done) break;
}
num_blocks = append_blocks(interesting_blocks, backup_blocks
, num_blocks);
if (num_blocks <= 0) return;
num_blocks = append_blocks(interesting_blocks, backup_blocks2, num_blocks);
if (num_blocks <= 0) return;
// don't double-pick anything if the peer is on parole
if (options & on_parole) return;
// pick one random block from the first busy piece we encountered
// none of these blocks have more than one request to them
if (!temp.empty()) interesting_blocks.push_back(temp[random() % temp.size()]);
@ -1762,6 +1785,8 @@ namespace libtorrent
TORRENT_ASSERT(m_piece_map[piece].priority(this) >= 0);
if (m_piece_map[piece].downloading)
{
if (m_piece_map[piece].full) return num_blocks;
// if we're prioritizing partials, we've already
// looked through the downloading pieces
if (options & prioritize_partials) return num_blocks;
@ -1823,11 +1848,11 @@ namespace libtorrent
// if all blocks have been requested (and we don't need any backup
// blocks), we might as well return immediately
if (int(backup_blocks2.size()) >= 1
/* if (int(backup_blocks2.size()) >= num_blocks
&& int(backup_blocks.size()) >= num_blocks
&& dp.requested + dp.writing + dp.finished == num_blocks_in_piece)
return num_blocks;
*/
// is true if all the other pieces that are currently
// requested from this piece are from the same
// peer as 'peer'.
@ -1844,7 +1869,7 @@ namespace libtorrent
// downloading from this piece, add it as backups
if (prefer_whole_pieces > 0 && !exclusive_active)
{
if (int(backup_blocks2.size()) >= 1)
if (int(backup_blocks2.size()) >= num_blocks)
return num_blocks;
for (int j = 0; j < num_blocks_in_piece; ++j)
@ -1881,7 +1906,7 @@ namespace libtorrent
else
{
// don't pick too many back-up blocks
if (int(backup_blocks2.size()) >= 1) return num_blocks;
if (int(backup_blocks2.size()) >= num_blocks) return num_blocks;
backup_blocks2.push_back(piece_block(dp.index, j));
}
continue;
@ -1967,6 +1992,7 @@ namespace libtorrent
// return std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
std::vector<piece_picker::downloading_piece>::iterator i = std::lower_bound(
m_downloads.begin(), m_downloads.end(), index, compare_index());
if (i == m_downloads.end()) return i;
if (i->index == index) return i;
return m_downloads.end();
}
@ -1976,10 +2002,17 @@ namespace libtorrent
// return std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
std::vector<piece_picker::downloading_piece>::const_iterator i = std::lower_bound(
m_downloads.begin(), m_downloads.end(), index, compare_index());
if (i == m_downloads.end()) return i;
if (i->index == index) return i;
return m_downloads.end();
}
void piece_picker::update_full(downloading_piece& dp)
{
int num_blocks = blocks_in_piece(dp.index);
m_piece_map[dp.index].full = dp.requested + dp.finished + dp.writing == num_blocks;
}
bool piece_picker::is_requested(piece_block block) const
{
TORRENT_ASSERT(block.piece_index >= 0);
@ -2049,6 +2082,7 @@ namespace libtorrent
info.peer = peer;
info.num_peers = 1;
++dp.requested;
update_full(dp);
}
else
{
@ -2069,6 +2103,7 @@ namespace libtorrent
{
info.state = block_info::state_requested;
++i->requested;
update_full(*i);
}
++info.num_peers;
if (i->state == none) i->state = state;
@ -2140,6 +2175,7 @@ namespace libtorrent
info.peer = peer;
info.num_peers = 0;
dp.writing = 1;
update_full(dp);
// sort_piece(m_downloads.end()-1);
}
else
@ -2195,6 +2231,8 @@ namespace libtorrent
info.state = block_info::state_none;
update_full(*i);
if (i->finished + i->writing + i->requested == 0)
{
piece_pos& p = m_piece_map[block.piece_index];
@ -2358,6 +2396,7 @@ namespace libtorrent
// clear this block as being downloaded
info.state = block_info::state_none;
--i->requested;
update_full(*i);
}
// if there are no other blocks in this piece

View File

@ -467,7 +467,7 @@ int test_main()
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");
@ -476,7 +476,7 @@ int test_main()
, options | piece_picker::prioritize_partials, empty_vector);
TEST_CHECK(int(picked.size()) > 0);
TEST_CHECK(picked.front() == piece_block(3, 3));
*/
// ========================================================
// test sequential download