prioritize more complete partial pieces over less complete ones

This commit is contained in:
Arvid Norberg 2007-07-15 15:41:55 +00:00
parent 96430f5edd
commit 1acedb39dc
2 changed files with 78 additions and 30 deletions

View File

@ -279,7 +279,8 @@ namespace libtorrent
assert(index_ >= 0); assert(index_ >= 0);
} }
// selects which vector to look in // the number of peers that has this piece
// (availability)
unsigned peer_count : 10; unsigned peer_count : 10;
// is 1 if the piece is marked as being downloaded // is 1 if the piece is marked as being downloaded
unsigned downloading : 1; unsigned downloading : 1;
@ -350,13 +351,15 @@ namespace libtorrent
void add(int index); void add(int index);
void move(int vec_index, int elem_index); void move(int vec_index, int elem_index);
void sort_piece(std::vector<downloading_piece>::iterator dp);
int add_interesting_blocks(const std::vector<int>& piece_list int add_interesting_blocks(const std::vector<int>& piece_list
, const std::vector<bool>& pieces , const std::vector<bool>& 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
, int num_blocks, bool prefer_whole_pieces , int num_blocks, bool prefer_whole_pieces
, void* peer, piece_state_t speed) const; , void* peer, piece_state_t speed
, bool ignore_downloading_pieces) const;
downloading_piece& add_download_piece(); downloading_piece& add_download_piece();
void erase_download_piece(std::vector<downloading_piece>::iterator i); void erase_download_piece(std::vector<downloading_piece>::iterator i);

View File

@ -196,12 +196,13 @@ namespace libtorrent
int block_index = num_downloads * m_blocks_per_piece; int block_index = num_downloads * m_blocks_per_piece;
if (int(m_block_info.size()) < block_index + m_blocks_per_piece) if (int(m_block_info.size()) < block_index + m_blocks_per_piece)
{ {
block_info* base = &m_block_info[0];
m_block_info.resize(block_index + m_blocks_per_piece); m_block_info.resize(block_index + m_blocks_per_piece);
if (!m_downloads.empty() && &m_block_info[0] != m_downloads.front().info) if (!m_downloads.empty() && &m_block_info[0] != base)
{ {
// this means the memory was reallocated, update the pointers // this means the memory was reallocated, update the pointers
for (int i = 0; i < int(m_downloads.size()); ++i) for (int i = 0; i < int(m_downloads.size()); ++i)
m_downloads[i].info = &m_block_info[i * m_blocks_per_piece]; m_downloads[i].info = &m_block_info[m_downloads[i].info - base];
} }
} }
m_downloads.push_back(downloading_piece()); m_downloads.push_back(downloading_piece());
@ -218,21 +219,18 @@ namespace libtorrent
void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i) void piece_picker::erase_download_piece(std::vector<downloading_piece>::iterator i)
{ {
if (i != m_downloads.end() - 1) std::vector<downloading_piece>::iterator other = std::find_if(
m_downloads.begin(), m_downloads.end()
, bind(&downloading_piece::info, _1)
== &m_block_info[(m_downloads.size() - 1) * m_blocks_per_piece]);
assert(other != m_downloads.end());
if (i != other)
{ {
int remove_index = i - m_downloads.begin(); std::copy(other->info, other->info + m_blocks_per_piece, i->info);
int last_index = m_downloads.size() - 1; other->info = i->info;
assert(remove_index < last_index);
assert(int(m_block_info.size()) >= last_index * m_blocks_per_piece + m_blocks_per_piece);
std::copy(m_block_info.begin() + (last_index * m_blocks_per_piece)
, m_block_info.begin() + (last_index * m_blocks_per_piece + m_blocks_per_piece)
, m_block_info.begin() + (remove_index * m_blocks_per_piece));
m_downloads[remove_index] = m_downloads[last_index];
m_downloads[remove_index].info = &m_block_info[remove_index * m_blocks_per_piece];
} }
m_downloads.erase(i);
m_downloads.pop_back();
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -242,6 +240,17 @@ namespace libtorrent
assert(m_piece_info.empty() || m_piece_info[0].empty()); assert(m_piece_info.empty() || m_piece_info[0].empty());
if (!m_downloads.empty())
{
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin();
i != m_downloads.end() - 1; ++i)
{
downloading_piece const& dp = *i;
downloading_piece const& next = *(i + 1);
assert(dp.finished + dp.writing >= next.finished + next.writing);
}
}
if (t != 0) if (t != 0)
assert((int)m_piece_map.size() == t->torrent_file().num_pieces()); assert((int)m_piece_map.size() == t->torrent_file().num_pieces());
@ -593,6 +602,20 @@ namespace libtorrent
} }
} }
void piece_picker::sort_piece(std::vector<downloading_piece>::iterator dp)
{
assert(m_piece_map[dp->index].downloading);
int complete = dp->writing + dp->finished;
for (std::vector<downloading_piece>::iterator i = dp, j(dp-1);
i != m_downloads.begin(); --i, --j)
{
assert(j >= m_downloads.begin());
if (j->finished + j->writing >= complete) return;
using std::swap;
swap(*j, *i);
}
}
void piece_picker::restore_piece(int index) void piece_picker::restore_piece(int index)
{ {
TORRENT_PIECE_PICKER_INVARIANT_CHECK; TORRENT_PIECE_PICKER_INVARIANT_CHECK;
@ -1028,6 +1051,22 @@ namespace libtorrent
// downloaded to // downloaded to
std::vector<piece_block> backup_blocks; std::vector<piece_block> backup_blocks;
bool ignore_downloading_pieces = false;
if (!prefer_whole_pieces)
{
std::vector<int> downloading_pieces;
downloading_pieces.reserve(m_downloads.size());
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
, end(m_downloads.end()); i != end; ++i)
{
downloading_pieces.push_back(i->index);
}
num_blocks = add_interesting_blocks(downloading_pieces, pieces
, interesting_blocks, backup_blocks, num_blocks
, prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
ignore_downloading_pieces = true;
}
// this loop will loop from pieces with priority 1 and up // this loop will loop from pieces with priority 1 and up
// until we either reach the end of the piece list or // until we either reach the end of the piece list or
// has filled the interesting_blocks with num_blocks // has filled the interesting_blocks with num_blocks
@ -1049,7 +1088,7 @@ namespace libtorrent
if (bucket->empty()) continue; if (bucket->empty()) continue;
num_blocks = add_interesting_blocks(*bucket, pieces num_blocks = add_interesting_blocks(*bucket, pieces
, interesting_blocks, backup_blocks, num_blocks , interesting_blocks, backup_blocks, num_blocks
, prefer_whole_pieces, peer, speed); , prefer_whole_pieces, peer, speed, ignore_downloading_pieces);
assert(num_blocks >= 0); assert(num_blocks >= 0);
if (num_blocks == 0) return; if (num_blocks == 0) return;
if (rarest_first) continue; if (rarest_first) continue;
@ -1135,7 +1174,8 @@ namespace libtorrent
, std::vector<piece_block>& interesting_blocks , std::vector<piece_block>& interesting_blocks
, std::vector<piece_block>& backup_blocks , std::vector<piece_block>& backup_blocks
, int num_blocks, bool prefer_whole_pieces , int num_blocks, bool prefer_whole_pieces
, void* peer, piece_state_t speed) const , void* peer, piece_state_t speed
, bool ignore_downloading_pieces) const
{ {
// if we have less than 1% of the pieces, ignore speed priorities and just try // if we have less than 1% of the pieces, ignore speed priorities and just try
// to finish any downloading piece // to finish any downloading piece
@ -1154,6 +1194,7 @@ namespace libtorrent
if (m_piece_map[*i].downloading == 1) if (m_piece_map[*i].downloading == 1)
{ {
if (ignore_downloading_pieces) continue;
std::vector<downloading_piece>::const_iterator p std::vector<downloading_piece>::const_iterator p
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i)); = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i));
assert(p != m_downloads.end()); assert(p != m_downloads.end());
@ -1422,7 +1463,7 @@ namespace libtorrent
assert(info.state == block_info::state_requested); assert(info.state == block_info::state_requested);
if (info.state == block_info::state_requested) --i->requested; if (info.state == block_info::state_requested) --i->requested;
assert(i->requested >= 0); assert(i->requested >= 0);
assert (info.state != block_info::state_writing); assert(info.state != block_info::state_writing);
++i->writing; ++i->writing;
info.state = block_info::state_writing; info.state = block_info::state_writing;
if (info.num_peers > 0) --info.num_peers; if (info.num_peers > 0) --info.num_peers;
@ -1434,6 +1475,7 @@ namespace libtorrent
// remove the fast/slow state from it // remove the fast/slow state from it
i->state = none; i->state = none;
} }
sort_piece(i);
} }
void piece_picker::mark_as_finished(piece_block block, void* peer) void piece_picker::mark_as_finished(piece_block block, void* peer)
@ -1461,9 +1503,11 @@ namespace libtorrent
block_info& info = dp.info[block.block_index]; block_info& info = dp.info[block.block_index];
info.peer = peer; info.peer = peer;
assert(info.state == block_info::state_none); assert(info.state == block_info::state_none);
// if (info.state == block_info::state_writing) --dp.writing; if (info.state != block_info::state_finished)
// assert(dp.writing >= 0); {
if (info.state != block_info::state_finished) ++dp.finished; ++dp.finished;
sort_piece(m_downloads.end() - 1);
}
info.state = block_info::state_finished; info.state = block_info::state_finished;
} }
else else
@ -1477,16 +1521,17 @@ namespace libtorrent
info.peer = peer; info.peer = peer;
assert(info.state == block_info::state_writing assert(info.state == block_info::state_writing
|| peer == 0); || peer == 0);
if (info.state == block_info::state_writing) --i->writing;
assert(i->writing >= 0); assert(i->writing >= 0);
++i->finished; ++i->finished;
info.state = block_info::state_finished; if (info.state == block_info::state_writing)
if (i->requested == 0)
{ {
// there are no blocks requested in this piece. --i->writing;
// remove the fast/slow state from it info.state = block_info::state_finished;
i->state = none; }
else
{
info.state = block_info::state_finished;
sort_piece(i);
} }
} }
} }