piece picker optimization. O(log n), lookup of downloading pieces instead of O(n)

This commit is contained in:
Arvid Norberg 2011-08-15 04:16:43 +00:00
parent b9be2fe94b
commit 25ad24ec68
2 changed files with 75 additions and 74 deletions

View File

@ -353,6 +353,14 @@ namespace libtorrent
int index;
};
struct compare_index
{
bool operator()(const downloading_piece& p, int piece) const
{ return p.index < piece; }
bool operator()(int piece, const downloading_piece& p) const
{ return piece < p.index; }
};
int blocks_in_last_piece() const
{ return m_blocks_in_last_piece; }
@ -483,11 +491,14 @@ namespace libtorrent
// shuffles the given piece inside it's priority range
void shuffle(int priority, int elem_index);
void sort_piece(std::vector<downloading_piece>::iterator dp);
// void sort_piece(std::vector<downloading_piece>::iterator dp);
downloading_piece& add_download_piece();
downloading_piece& add_download_piece(int index);
void erase_download_piece(std::vector<downloading_piece>::iterator i);
std::vector<downloading_piece>::const_iterator find_dl_piece(int index) const;
std::vector<downloading_piece>::iterator find_dl_piece(int index);
// some compilers (e.g. gcc 2.95, does not inherit access
// privileges to nested classes)
public:
@ -520,7 +531,8 @@ namespace libtorrent
// 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
// is being downloaded. This list is ordered
// by piece index to make lookups efficient
std::vector<downloading_piece> m_downloads;
// this holds the information of the

View File

@ -137,9 +137,7 @@ namespace libtorrent
if (m_piece_map[index].downloading)
{
std::vector<downloading_piece>::const_iterator piece = std::find_if(
m_downloads.begin(), m_downloads.end()
, boost::bind(&downloading_piece::index, _1) == index);
std::vector<downloading_piece>::const_iterator piece = find_dl_piece(index);
TORRENT_ASSERT(piece != m_downloads.end());
st = *piece;
st.info = 0;
@ -157,7 +155,7 @@ namespace libtorrent
st.finished = 0;
}
piece_picker::downloading_piece& piece_picker::add_download_piece()
piece_picker::downloading_piece& piece_picker::add_download_piece(int piece)
{
int num_downloads = m_downloads.size();
int block_index = num_downloads * m_blocks_per_piece;
@ -173,8 +171,12 @@ namespace libtorrent
m_downloads[i].info = &m_block_info[m_downloads[i].info - base];
}
}
m_downloads.push_back(downloading_piece());
downloading_piece& ret = m_downloads.back();
std::vector<downloading_piece>::iterator i = std::lower_bound(m_downloads.begin()
, m_downloads.end(), piece, compare_index());
TORRENT_ASSERT(i == m_downloads.end() || i->index != piece);
i = m_downloads.insert(i, downloading_piece());
downloading_piece& ret = *i;
ret.index = piece;
ret.info = &m_block_info[block_index];
for (int i = 0; i < m_blocks_per_piece; ++i)
{
@ -764,7 +766,7 @@ namespace libtorrent
p2.index = temp;
std::swap(m_pieces[other_index], m_pieces[elem_index]);
}
/*
void piece_picker::sort_piece(std::vector<downloading_piece>::iterator dp)
{
TORRENT_ASSERT(m_piece_map[dp->index].downloading);
@ -793,7 +795,7 @@ namespace libtorrent
if (j == m_downloads.end() - 1) return;
}
}
*/
void piece_picker::restore_piece(int index)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
@ -803,9 +805,7 @@ namespace libtorrent
TORRENT_ASSERT(m_piece_map[index].downloading == 1);
std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(index));
std::vector<downloading_piece>::iterator i = find_dl_piece(index);
TORRENT_ASSERT(i != m_downloads.end());
#ifdef TORRENT_DEBUG
@ -1090,15 +1090,12 @@ namespace libtorrent
if (p.downloading)
{
std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin()
, m_downloads.end()
, has_index(index));
= find_dl_piece(index);
TORRENT_ASSERT(i != m_downloads.end());
erase_download_piece(i);
}
TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(index)) == m_downloads.end());
TORRENT_ASSERT(find_dl_piece(index) == m_downloads.end());
if (p.have()) return;
@ -1576,8 +1573,7 @@ namespace libtorrent
, num_blocks);
if (num_blocks <= 0) return;
num_blocks = append_blocks(interesting_blocks, backup_blocks2
, num_blocks);
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
@ -1659,8 +1655,7 @@ namespace libtorrent
if (piece_priority(i) == 0) continue;
if (have_piece(i)) continue;
std::vector<downloading_piece>::const_iterator k
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(i));
std::vector<downloading_piece>::const_iterator k = find_dl_piece(i);
TORRENT_ASSERT(k != m_downloads.end());
if (k == m_downloads.end()) continue;
@ -1771,8 +1766,7 @@ namespace libtorrent
// looked through the downloading pieces
if (options & prioritize_partials) return num_blocks;
std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(piece));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(piece);
TORRENT_ASSERT(i != m_downloads.end());
// std::cout << "add_blocks_downloading(" << piece << ")" << std::endl;
@ -1829,7 +1823,7 @@ 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()) >= num_blocks
if (int(backup_blocks2.size()) >= 1
&& int(backup_blocks.size()) >= num_blocks
&& dp.requested + dp.writing + dp.finished == num_blocks_in_piece)
return num_blocks;
@ -1850,7 +1844,7 @@ namespace libtorrent
// downloading from this piece, add it as backups
if (prefer_whole_pieces > 0 && !exclusive_active)
{
if (int(backup_blocks2.size()) >= num_blocks)
if (int(backup_blocks2.size()) >= 1)
return num_blocks;
for (int j = 0; j < num_blocks_in_piece; ++j)
@ -1887,7 +1881,7 @@ namespace libtorrent
else
{
// don't pick too many back-up blocks
if (int(backup_blocks2.size()) >= num_blocks) return num_blocks;
if (int(backup_blocks2.size()) >= 1) return num_blocks;
backup_blocks2.push_back(piece_block(dp.index, j));
}
continue;
@ -1947,12 +1941,10 @@ namespace libtorrent
if (m_piece_map[index].downloading == 0)
{
TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(index)) == m_downloads.end());
TORRENT_ASSERT(find_dl_piece(index) == m_downloads.end());
return false;
}
std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(index);
TORRENT_ASSERT(i != m_downloads.end());
TORRENT_ASSERT((int)i->finished <= m_blocks_per_piece);
int max_blocks = blocks_in_piece(index);
@ -1970,6 +1962,24 @@ namespace libtorrent
return true;
}
std::vector<piece_picker::downloading_piece>::iterator piece_picker::find_dl_piece(int index)
{
// 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->index == index) return i;
return m_downloads.end();
}
std::vector<piece_picker::downloading_piece>::const_iterator piece_picker::find_dl_piece(int index) const
{
// 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->index == index) return i;
return m_downloads.end();
}
bool piece_picker::is_requested(piece_block block) const
{
TORRENT_ASSERT(block.piece_index >= 0);
@ -1977,11 +1987,7 @@ namespace libtorrent
TORRENT_ASSERT(block.piece_index < m_piece_map.size());
if (m_piece_map[block.piece_index].downloading == 0) return false;
std::vector<downloading_piece>::const_iterator i
= std::find_if(
m_downloads.begin()
, m_downloads.end()
, has_index(block.piece_index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
return i->info[block.block_index].state == block_info::state_requested;
@ -1995,8 +2001,7 @@ namespace libtorrent
if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
if (m_piece_map[block.piece_index].downloading == 0) return false;
std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
return i->info[block.block_index].state == block_info::state_finished
|| i->info[block.block_index].state == block_info::state_writing;
@ -2010,8 +2015,7 @@ namespace libtorrent
if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
if (m_piece_map[block.piece_index].downloading == 0) return false;
std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
return i->info[block.block_index].state == block_info::state_finished;
}
@ -2038,8 +2042,7 @@ namespace libtorrent
p.downloading = 1;
if (prio >= 0 && !m_dirty) update(prio, p.index);
downloading_piece& dp = add_download_piece();
dp.index = block.piece_index;
downloading_piece& dp = add_download_piece(block.piece_index);
dp.state = state;
block_info& info = dp.info[block.block_index];
info.state = block_info::state_requested;
@ -2052,8 +2055,7 @@ namespace libtorrent
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
#endif
std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
block_info& info = i->info[block.block_index];
if (info.state == block_info::state_writing
@ -2084,8 +2086,7 @@ namespace libtorrent
piece_pos const& p = m_piece_map[block.piece_index];
if (!p.downloading) return 0;
std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
block_info const& info = i->info[block.block_index];
@ -2132,20 +2133,18 @@ namespace libtorrent
// the piece priority was set to 0
if (prio >= 0 && !m_dirty) update(prio, p.index);
downloading_piece& dp = add_download_piece();
dp.index = block.piece_index;
downloading_piece& dp = add_download_piece(block.piece_index);
dp.state = none;
block_info& info = dp.info[block.block_index];
info.state = block_info::state_writing;
info.peer = peer;
info.num_peers = 0;
dp.writing = 1;
sort_piece(m_downloads.end()-1);
// sort_piece(m_downloads.end()-1);
}
else
{
std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
block_info& info = i->info[block.block_index];
@ -2169,7 +2168,7 @@ namespace libtorrent
// remove the fast/slow state from it
i->state = none;
}
sort_piece(i);
// sort_piece(i);
}
return true;
}
@ -2178,8 +2177,7 @@ namespace libtorrent
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
if (i == m_downloads.end()) return;
@ -2211,7 +2209,7 @@ namespace libtorrent
}
else
{
sort_piece(i);
// sort_piece(i);
}
}
@ -2240,8 +2238,7 @@ namespace libtorrent
p.downloading = 1;
if (prio >= 0 && !m_dirty) update(prio, p.index);
downloading_piece& dp = add_download_piece();
dp.index = block.piece_index;
downloading_piece& dp = add_download_piece(block.piece_index);
dp.state = none;
block_info& info = dp.info[block.block_index];
info.peer = peer;
@ -2250,7 +2247,7 @@ namespace libtorrent
if (info.state != block_info::state_finished)
{
++dp.finished;
sort_piece(m_downloads.end() - 1);
// sort_piece(m_downloads.end() - 1);
}
info.state = block_info::state_finished;
}
@ -2260,8 +2257,7 @@ namespace libtorrent
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
#endif
std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
block_info& info = i->info[block.block_index];
@ -2282,7 +2278,7 @@ namespace libtorrent
{
TORRENT_ASSERT(info.state == block_info::state_none);
info.state = block_info::state_finished;
sort_piece(i);
// sort_piece(i);
}
}
}
@ -2290,8 +2286,7 @@ namespace libtorrent
void piece_picker::get_downloaders(std::vector<void*>& d, int index) const
{
TORRENT_ASSERT(index >= 0 && index <= (int)m_piece_map.size());
std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(index);
TORRENT_ASSERT(i != m_downloads.end());
d.clear();
@ -2303,10 +2298,7 @@ namespace libtorrent
void* piece_picker::get_downloader(piece_block block) const
{
std::vector<downloading_piece>::const_iterator i = std::find_if(
m_downloads.begin()
, m_downloads.end()
, has_index(block.piece_index));
std::vector<downloading_piece>::const_iterator i = find_dl_piece(block.piece_index);
if (i == m_downloads.end()) return 0;
@ -2333,13 +2325,11 @@ namespace libtorrent
if (m_piece_map[block.piece_index].downloading == 0)
{
TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(block.piece_index)) == m_downloads.end());
TORRENT_ASSERT(find_dl_piece(block.piece_index) == m_downloads.end());
return;
}
std::vector<downloading_piece>::iterator i = std::find_if(m_downloads.begin()
, m_downloads.end(), has_index(block.piece_index));
std::vector<downloading_piece>::iterator i = find_dl_piece(block.piece_index);
TORRENT_ASSERT(i != m_downloads.end());
block_info& info = i->info[block.block_index];
@ -2386,8 +2376,7 @@ namespace libtorrent
else if (prev_prio >= 0) update(prev_prio, p.index);
}
TORRENT_ASSERT(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(block.piece_index)) == m_downloads.end());
TORRENT_ASSERT(find_dl_piece(block.piece_index) == m_downloads.end());
}
else if (i->requested == 0)
{