added peer/piece categories to the piece picker. fixes #18
This commit is contained in:
@@ -205,6 +205,24 @@ namespace libtorrent
|
||||
for (int i = m_sequenced_download_threshold * 2 + 1; i < int(m_piece_info.size()); ++i)
|
||||
assert(m_piece_info[i].empty());
|
||||
|
||||
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
|
||||
, end(m_downloads.end()); i != end; ++i)
|
||||
{
|
||||
bool blocks_requested = false;
|
||||
int num_blocks = blocks_in_piece(i->index);
|
||||
for (int k = 0; k < num_blocks; ++k)
|
||||
{
|
||||
if (i->finished_blocks[k]) continue;
|
||||
if (i->requested_blocks[k])
|
||||
{
|
||||
blocks_requested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(blocks_requested == (i->state != none));
|
||||
}
|
||||
|
||||
|
||||
int num_filtered = 0;
|
||||
int num_have_filtered = 0;
|
||||
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin();
|
||||
@@ -971,28 +989,40 @@ namespace libtorrent
|
||||
}
|
||||
|
||||
// ============ end deprecation ==============
|
||||
|
||||
|
||||
// pieces describes which pieces the peer we're requesting from
|
||||
// has.
|
||||
// interesting_blocks is an out parameter, and will be filled
|
||||
// with (up to) num_blocks of interesting blocks that the peer has.
|
||||
// prefer_whole_pieces can be set if this peer should download
|
||||
// whole pieces rather than trying to download blocks from the
|
||||
// same piece as other peers.
|
||||
// the endpoint is the address of the peer we're picking pieces
|
||||
// from. This is used when downloading whole pieces, to only
|
||||
// pick from the same piece the same peer is downloading from.
|
||||
// state is supposed to be set to fast if the peer is downloading
|
||||
// relatively fast, by some notion. Slow peers will prefer not
|
||||
// to pick blocks from the same pieces as fast peers, and vice
|
||||
// versa. Downloading pieces are marked as being fast, medium
|
||||
// or slow once they're started.
|
||||
void piece_picker::pick_pieces(const std::vector<bool>& pieces
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, tcp::endpoint peer) const
|
||||
, tcp::endpoint peer, piece_state_t speed) const
|
||||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
assert(num_blocks > 0);
|
||||
assert(pieces.size() == m_piece_map.size());
|
||||
assert(m_files_checked_called);
|
||||
|
||||
// free refers to pieces that are free to download, no one else
|
||||
// is downloading them.
|
||||
// partial is pieces that are partially being downloaded, and
|
||||
// parts of them may be free for download as well, the
|
||||
// partially downloaded pieces will be prioritized
|
||||
assert(m_piece_info.begin() != m_piece_info.end());
|
||||
// +1 is to ignore pieces that no peer has. The bucket with index 0 contains
|
||||
// pieces that 0 other peers has.
|
||||
std::vector<std::vector<int> >::const_iterator free
|
||||
= m_piece_info.begin() + 1;
|
||||
|
||||
// this will be filled with blocks that we should not request
|
||||
// unless we can't find num_blocks among the other ones.
|
||||
// blocks that belong to pieces with a mismatching speed
|
||||
// category for instance, or if we prefer whole pieces,
|
||||
// blocks belonging to a piece that others have
|
||||
// downloaded to
|
||||
std::vector<piece_block> backup_blocks;
|
||||
|
||||
// this loop will loop from pieces with priority 1 and up
|
||||
@@ -1004,29 +1034,29 @@ namespace libtorrent
|
||||
// fast peers) the partial pieces will not be prioritized, but actually
|
||||
// ignored as long as possible.
|
||||
|
||||
while (free != m_piece_info.end())
|
||||
// +1 is to ignore pieces that no peer has. The bucket with index 0 contains
|
||||
// pieces that 0 other peers have. bucket will point to a bucket with
|
||||
// pieces with the same priority. It will be iterated in priority
|
||||
// order (high priority/rare pices first). The content of each
|
||||
// bucket is randomized
|
||||
for (std::vector<std::vector<int> >::const_iterator bucket
|
||||
= m_piece_info.begin() + 1; bucket != m_piece_info.end();
|
||||
++bucket)
|
||||
{
|
||||
num_blocks = add_interesting_blocks(*free, pieces
|
||||
if (bucket->empty()) continue;
|
||||
num_blocks = add_interesting_blocks(*bucket, pieces
|
||||
, interesting_blocks, backup_blocks, num_blocks
|
||||
, prefer_whole_pieces, peer);
|
||||
, prefer_whole_pieces, peer, speed);
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return;
|
||||
++free;
|
||||
}
|
||||
|
||||
// TODO: what's up with this?
|
||||
if (!prefer_whole_pieces) return;
|
||||
assert(num_blocks > 0);
|
||||
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
// std::ofstream f("piece_picker.log", std::ios_base::app);
|
||||
// f << "backup_blocks: " << backup_blocks.size() << "\n"
|
||||
// << "used: " << std::min(num_blocks, (int)backup_blocks.size()) << "\n----\n";
|
||||
#endif
|
||||
|
||||
interesting_blocks.insert(interesting_blocks.end()
|
||||
, backup_blocks.begin(), backup_blocks.begin()
|
||||
+ (std::min)(num_blocks, (int)backup_blocks.size()));
|
||||
if (!backup_blocks.empty())
|
||||
interesting_blocks.insert(interesting_blocks.end()
|
||||
, backup_blocks.begin(), backup_blocks.begin()
|
||||
+ (std::min)(num_blocks, (int)backup_blocks.size()));
|
||||
}
|
||||
|
||||
namespace
|
||||
@@ -1053,7 +1083,7 @@ namespace libtorrent
|
||||
, std::vector<piece_block>& interesting_blocks
|
||||
, std::vector<piece_block>& backup_blocks
|
||||
, int num_blocks, bool prefer_whole_pieces
|
||||
, tcp::endpoint peer) const
|
||||
, tcp::endpoint peer, piece_state_t speed) const
|
||||
{
|
||||
for (std::vector<int>::const_iterator i = piece_list.begin();
|
||||
i != piece_list.end(); ++i)
|
||||
@@ -1083,7 +1113,7 @@ namespace libtorrent
|
||||
if (prefer_whole_pieces
|
||||
&& !exclusively_requested_from(*p, num_blocks_in_piece, peer))
|
||||
{
|
||||
if ((int)backup_blocks.size() >= num_blocks) continue;
|
||||
if (int(backup_blocks.size()) >= num_blocks) continue;
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
if (p->finished_blocks[j] == 1) continue;
|
||||
@@ -1096,9 +1126,19 @@ namespace libtorrent
|
||||
|
||||
for (int j = 0; j < num_blocks_in_piece; ++j)
|
||||
{
|
||||
// ignore completed blocks
|
||||
if (p->finished_blocks[j] == 1) continue;
|
||||
// ignore blocks requested from this peer already
|
||||
if (p->requested_blocks[j] == 1
|
||||
&& p->info[j].peer == peer) continue;
|
||||
// if the piece is fast and the peer is slow, or vice versa,
|
||||
// add the block as a backup
|
||||
if (p->state != none && p->state != speed)
|
||||
{
|
||||
if (int(backup_blocks.size()) >= num_blocks) continue;
|
||||
backup_blocks.push_back(piece_block(*i, j));
|
||||
continue;
|
||||
}
|
||||
// this block is interesting (we don't have it
|
||||
// yet). But it may already have been requested
|
||||
// from another peer. We have to add it anyway
|
||||
@@ -1113,6 +1153,8 @@ namespace libtorrent
|
||||
{
|
||||
// we have found a block that's free to download
|
||||
num_blocks--;
|
||||
// if we prefer whole pieces, continue picking from this
|
||||
// piece even though we have num_blocks
|
||||
if (prefer_whole_pieces) continue;
|
||||
assert(num_blocks >= 0);
|
||||
if (num_blocks == 0) return num_blocks;
|
||||
@@ -1193,7 +1235,8 @@ namespace libtorrent
|
||||
}
|
||||
|
||||
|
||||
void piece_picker::mark_as_downloading(piece_block block, const tcp::endpoint& peer)
|
||||
void piece_picker::mark_as_downloading(piece_block block
|
||||
, const tcp::endpoint& peer, piece_state_t state)
|
||||
{
|
||||
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
|
||||
|
||||
@@ -1210,6 +1253,7 @@ namespace libtorrent
|
||||
move(prio, p.index);
|
||||
|
||||
downloading_piece dp;
|
||||
dp.state = state;
|
||||
dp.index = block.piece_index;
|
||||
dp.requested_blocks[block.block_index] = 1;
|
||||
dp.info[block.block_index].peer = peer;
|
||||
@@ -1223,6 +1267,7 @@ namespace libtorrent
|
||||
assert(i->requested_blocks[block.block_index] == 0);
|
||||
i->info[block.block_index].peer = peer;
|
||||
i->requested_blocks[block.block_index] = 1;
|
||||
if (i->state == none) i->state = state;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1245,6 +1290,7 @@ namespace libtorrent
|
||||
else assert(p.priority(m_sequenced_download_threshold) == 0);
|
||||
|
||||
downloading_piece dp;
|
||||
dp.state = none;
|
||||
dp.index = block.piece_index;
|
||||
dp.requested_blocks[block.block_index] = 1;
|
||||
dp.finished_blocks[block.block_index] = 1;
|
||||
@@ -1259,6 +1305,27 @@ namespace libtorrent
|
||||
i->info[block.block_index].peer = peer;
|
||||
i->requested_blocks[block.block_index] = 1;
|
||||
i->finished_blocks[block.block_index] = 1;
|
||||
|
||||
// TODO: maintain requested and finished counters so that
|
||||
// we don't have to count every time
|
||||
bool blocks_requested = false;
|
||||
int num_blocks = blocks_in_piece(i->index);
|
||||
for (int k = 0; k < num_blocks; ++k)
|
||||
{
|
||||
if (i->finished_blocks[k]) continue;
|
||||
if (i->requested_blocks[k])
|
||||
{
|
||||
blocks_requested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!blocks_requested)
|
||||
{
|
||||
// there are no blocks requested in this piece.
|
||||
// remove the fast/slow state from it
|
||||
i->state = none;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
@@ -1373,6 +1440,27 @@ namespace libtorrent
|
||||
assert(std::find_if(m_downloads.begin(), m_downloads.end()
|
||||
, has_index(block.piece_index)) == m_downloads.end());
|
||||
}
|
||||
|
||||
// TODO: maintain requested and finished counters so that
|
||||
// we don't have to count every time
|
||||
bool blocks_requested = false;
|
||||
int num_blocks = blocks_in_piece(i->index);
|
||||
for (int k = 0; k < num_blocks; ++k)
|
||||
{
|
||||
if (i->finished_blocks[k]) continue;
|
||||
if (i->requested_blocks[k])
|
||||
{
|
||||
blocks_requested = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!blocks_requested)
|
||||
{
|
||||
// there are no blocks requested in this piece.
|
||||
// remove the fast/slow state from it
|
||||
i->state = none;
|
||||
}
|
||||
}
|
||||
|
||||
int piece_picker::unverified_blocks() const
|
||||
|
Reference in New Issue
Block a user