improve piece picker performance in tracking pad-blocks

This commit is contained in:
arvidn 2018-08-19 11:08:09 +02:00 committed by Arvid Norberg
parent 28c94b54ed
commit 37d85ac2f7
2 changed files with 35 additions and 10 deletions

View File

@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <cstdint>
#include <tuple>
#include <set>
#include <unordered_map>
#include "libtorrent/peer_id.hpp"
#include "libtorrent/assert.hpp"
@ -464,7 +465,7 @@ namespace libtorrent {
private:
int num_pad_blocks() const { return int(m_pad_blocks.size()); }
int num_pad_blocks() const { return m_num_pad_blocks; }
aux::typed_span<block_info> mutable_blocks_for_piece(downloading_piece const& dp);
@ -725,10 +726,19 @@ namespace libtorrent {
// TODO: should this be allocated lazily?
mutable aux::vector<piece_pos, piece_index_t> m_piece_map;
// this maps pieces to a range of blocks that are pad files and should not
// be picked
// this indicates whether a block has been marked as a pad
// block or not. It's indexed by block index, i.e. piece_index
// * blocks_per_piece + block. These blocks should not be
// picked and are considered to be had
// TODO: this could be a much more efficient data structure
std::set<piece_block> m_pad_blocks;
bitfield m_pad_blocks;
// tracks the number of blocks in a specific piece that are pad blocks
std::unordered_map<piece_index_t, int> m_pads_in_piece;
// the number of bits set in the m_pad_blocks bitfield, i.e.
// the number of blocks marked as pads
int m_num_pad_blocks = 0;
// the number of pad blocks that we already have
int m_have_pad_blocks = 0;

View File

@ -234,7 +234,7 @@ namespace libtorrent {
{
info.num_peers = 0;
info.state = block_info::state_none;
if (m_pad_blocks.count(piece_block(piece, block_idx)))
if (!m_pad_blocks.empty() && m_pad_blocks.get_bit(static_cast<int>(piece) * m_blocks_per_piece + block_idx))
{
info.state = block_info::state_finished;
++ret.finished;
@ -3506,7 +3506,23 @@ get_out:
void piece_picker::mark_as_pad(piece_block block)
{
m_pad_blocks.insert(block);
// if this is the first block we mark as a pad, allocate the bitfield
if (m_pad_blocks.empty())
{
m_pad_blocks.resize(int(m_piece_map.size() * m_blocks_per_piece));
}
int const block_index = static_cast<int>(block.piece_index) * m_blocks_per_piece + block.block_index;
TORRENT_ASSERT(block_index < m_pad_blocks.size());
TORRENT_ASSERT(block_index >= 0);
TORRENT_ASSERT(m_pad_blocks.get_bit(block_index) == false);
m_pad_blocks.set_bit(block_index);
++m_num_pad_blocks;
TORRENT_ASSERT(m_pad_blocks.count() == m_num_pad_blocks);
++m_pads_in_piece[block.piece_index];
// if we mark and entire piece as a pad file, we need to also
// consder that piece as "had" and increment some counters
int const blocks = blocks_in_piece(block.piece_index);
@ -3519,10 +3535,9 @@ get_out:
int piece_picker::pad_blocks_in_piece(piece_index_t const index) const
{
int const blocks = blocks_in_piece(index);
auto const begin = m_pad_blocks.lower_bound(piece_block(index, 0));
auto const end = m_pad_blocks.upper_bound(piece_block(index, blocks));
return int(std::distance(begin, end));
auto const it = m_pads_in_piece.find(index);
if (it == m_pads_in_piece.end()) return 0;
return it->second;
}
void piece_picker::get_downloaders(std::vector<torrent_peer*>& d