introduce a prio_index_t type (#1453)
* introduce a prio_index_t type for indexing into the priority sorted piece list, m_pieces, in piece_picker * some piece picker simplification * fix msvc warning for prio_index_t
This commit is contained in:
parent
5ed0086b51
commit
42a27b3ebc
|
@ -66,6 +66,30 @@ namespace libtorrent { namespace aux {
|
|||
{ return IndexType(static_cast<underlying_index>(this->size())); }
|
||||
};
|
||||
|
||||
template <typename Iter>
|
||||
struct iterator_range
|
||||
{
|
||||
Iter _begin, _end;
|
||||
Iter begin() { return _begin; }
|
||||
Iter end() { return _end; }
|
||||
};
|
||||
|
||||
template <typename T, typename IndexType>
|
||||
iterator_range<T*> range(vector<T, IndexType>& vec
|
||||
, IndexType begin, IndexType end)
|
||||
{
|
||||
using type = typename IndexType::underlying_type;
|
||||
return { vec.data() + static_cast<type>(begin), vec.data() + static_cast<type>(end) };
|
||||
}
|
||||
|
||||
template <typename T, typename IndexType>
|
||||
iterator_range<T const*> range(vector<T, IndexType> const& vec
|
||||
, IndexType begin, IndexType end)
|
||||
{
|
||||
using type = typename IndexType::underlying_type;
|
||||
return { vec.data() + static_cast<type>(begin), vec.data() + static_cast<type>(end) };
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -67,6 +67,9 @@ namespace libtorrent
|
|||
struct counters;
|
||||
struct torrent_peer;
|
||||
|
||||
struct prio_index_tag_t {};
|
||||
using prio_index_t = aux::strong_typedef<int, prio_index_tag_t>;
|
||||
|
||||
class TORRENT_EXTRA_EXPORT piece_picker
|
||||
{
|
||||
public:
|
||||
|
@ -405,7 +408,7 @@ namespace libtorrent
|
|||
#if TORRENT_USE_INVARIANT_CHECKS
|
||||
void check_piece_state() const;
|
||||
// used in debug mode
|
||||
void verify_priority(int start, int end, int prio) const;
|
||||
void verify_priority(prio_index_t start, prio_index_t end, int prio) const;
|
||||
void verify_pick(std::vector<piece_block> const& picked
|
||||
, typed_bitfield<piece_index_t> const& bits) const;
|
||||
|
||||
|
@ -569,19 +572,29 @@ namespace libtorrent
|
|||
std::uint32_t piece_priority : 3;
|
||||
|
||||
// index in to the piece_info vector
|
||||
std::uint32_t index;
|
||||
prio_index_t index;
|
||||
|
||||
#ifdef TORRENT_DEBUG_REFCOUNTS
|
||||
// all the peers that have this piece
|
||||
std::set<const torrent_peer*> have_peers;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 1)
|
||||
#pragma warning(disable : 4268)
|
||||
#endif
|
||||
|
||||
// index is set to this to indicate that we have the
|
||||
// piece. There is no entry for the piece in the
|
||||
// buckets if this is the case.
|
||||
constexpr static prio_index_t we_have_index{-1};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
enum : std::uint32_t
|
||||
{
|
||||
// index is set to this to indicate that we have the
|
||||
// piece. There is no entry for the piece in the
|
||||
// buckets if this is the case.
|
||||
we_have_index = 0xffffffff,
|
||||
// the priority value that means the piece is filtered
|
||||
filter_priority = 0,
|
||||
// the max number the peer count can hold
|
||||
|
@ -590,7 +603,7 @@ namespace libtorrent
|
|||
|
||||
bool have() const { return index == we_have_index; }
|
||||
void set_have() { index = we_have_index; TORRENT_ASSERT(have()); }
|
||||
void set_not_have() { index = 0; TORRENT_ASSERT(!have()); }
|
||||
void set_not_have() { index = prio_index_t(0); TORRENT_ASSERT(!have()); }
|
||||
bool downloading() const { return download_state != piece_open; }
|
||||
|
||||
bool filtered() const { return piece_priority == filter_priority; }
|
||||
|
@ -663,20 +676,23 @@ namespace libtorrent
|
|||
|
||||
void update_pieces() const;
|
||||
|
||||
prio_index_t priority_begin(int prio) const;
|
||||
prio_index_t priority_end(int prio) const;
|
||||
|
||||
// fills in the range [start, end) of pieces in
|
||||
// m_pieces that have priority 'prio'
|
||||
std::pair<int, int> priority_range(int prio);
|
||||
std::pair<prio_index_t, prio_index_t> priority_range(int prio) const;
|
||||
|
||||
// adds the piece 'index' to m_pieces
|
||||
void add(piece_index_t index);
|
||||
// removes the piece with the given priority and the
|
||||
// elem_index in the m_pieces vector
|
||||
void remove(int priority, int elem_index);
|
||||
void remove(int priority, prio_index_t elem_index);
|
||||
// updates the position of the piece with the given
|
||||
// priority and the elem_index in the m_pieces vector
|
||||
void update(int priority, int elem_index);
|
||||
void update(int priority, prio_index_t elem_index);
|
||||
// shuffles the given piece inside it's priority range
|
||||
void shuffle(int priority, int elem_index);
|
||||
void shuffle(int priority, prio_index_t elem_index);
|
||||
|
||||
std::vector<downloading_piece>::iterator add_download_piece(piece_index_t index);
|
||||
void erase_download_piece(std::vector<downloading_piece>::iterator i);
|
||||
|
@ -713,12 +729,12 @@ namespace libtorrent
|
|||
// this vector contains all piece indices that are pickable
|
||||
// sorted by priority. Pieces are in random random order
|
||||
// among pieces with the same priority
|
||||
mutable std::vector<piece_index_t> m_pieces;
|
||||
mutable aux::vector<piece_index_t, prio_index_t> m_pieces;
|
||||
|
||||
// these are indices to the priority boundaries inside
|
||||
// the m_pieces vector. priority 0 always start at
|
||||
// 0, priority 1 starts at m_priority_boundaries[0] etc.
|
||||
mutable std::vector<int> m_priority_boundaries;
|
||||
mutable std::vector<prio_index_t> m_priority_boundaries;
|
||||
|
||||
// each piece that's currently being downloaded has an entry in this list
|
||||
// with block allocations. i.e. it says which parts of the piece that is
|
||||
|
|
|
@ -44,11 +44,15 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace libtorrent {
|
||||
namespace aux {
|
||||
|
||||
template <typename Tag>
|
||||
struct difference_tag {};
|
||||
|
||||
template<typename UnderlyingType, typename Tag
|
||||
, typename Cond = typename std::enable_if<std::is_integral<UnderlyingType>::value>::type>
|
||||
struct strong_typedef
|
||||
{
|
||||
using underlying_type = UnderlyingType;
|
||||
using diff_type = strong_typedef<UnderlyingType, difference_tag<Tag>>;
|
||||
|
||||
constexpr strong_typedef(strong_typedef const& rhs) : m_val(rhs.m_val) {}
|
||||
strong_typedef() = default;
|
||||
|
@ -71,6 +75,20 @@ namespace aux {
|
|||
strong_typedef operator++(int) { return strong_typedef{m_val++}; }
|
||||
strong_typedef operator--(int) { return strong_typedef{m_val--}; }
|
||||
|
||||
friend diff_type operator-(strong_typedef lhs, strong_typedef rhs)
|
||||
{ return diff_type{lhs.m_val - rhs.m_val}; }
|
||||
friend strong_typedef operator+(strong_typedef lhs, diff_type rhs)
|
||||
{ return strong_typedef{lhs.m_val + static_cast<UnderlyingType>(rhs)}; }
|
||||
friend strong_typedef operator+(diff_type lhs, strong_typedef rhs)
|
||||
{ return strong_typedef{static_cast<UnderlyingType>(lhs) + rhs.m_val}; }
|
||||
friend strong_typedef operator-(strong_typedef lhs, diff_type rhs)
|
||||
{ return strong_typedef{lhs.m_val - static_cast<UnderlyingType>(rhs)}; }
|
||||
|
||||
strong_typedef& operator+=(diff_type rhs)
|
||||
{ m_val += static_cast<UnderlyingType>(rhs); return *this; }
|
||||
strong_typedef& operator-=(diff_type rhs)
|
||||
{ m_val -= static_cast<UnderlyingType>(rhs); return *this; }
|
||||
|
||||
strong_typedef& operator=(strong_typedef rhs) { m_val = rhs.m_val; return *this; }
|
||||
private:
|
||||
UnderlyingType m_val;
|
||||
|
|
|
@ -65,8 +65,10 @@ namespace libtorrent
|
|||
std::numeric_limits<piece_index_t>::max()
|
||||
, std::numeric_limits<int>::max());
|
||||
|
||||
constexpr prio_index_t piece_picker::piece_pos::we_have_index;
|
||||
|
||||
piece_picker::piece_picker()
|
||||
: m_priority_boundaries(1, int(m_pieces.size()))
|
||||
: m_priority_boundaries(1, m_pieces.end_index())
|
||||
{
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
std::cerr << "[" << this << "] " << "new piece_picker" << std::endl;
|
||||
|
@ -105,7 +107,7 @@ namespace libtorrent
|
|||
{
|
||||
i->peer_count = 0;
|
||||
i->download_state = piece_pos::piece_open;
|
||||
i->index = 0;
|
||||
i->index = prio_index_t(0);
|
||||
#ifdef TORRENT_DEBUG_REFCOUNTS
|
||||
i->have_peers.clear();
|
||||
#endif
|
||||
|
@ -119,10 +121,6 @@ namespace libtorrent
|
|||
m_reverse_cursor > piece_index_t(0) && (i->have() || i->filtered());
|
||||
++i, --m_reverse_cursor);
|
||||
|
||||
// the piece index is stored in 20 bits, which limits the allowed
|
||||
// number of pieces somewhat
|
||||
TORRENT_ASSERT(m_piece_map.size() < piece_pos::we_have_index);
|
||||
|
||||
m_blocks_per_piece = std::uint16_t(blocks_per_piece);
|
||||
m_blocks_in_last_piece = std::uint16_t(blocks_in_last_piece);
|
||||
if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = std::uint16_t(blocks_per_piece);
|
||||
|
@ -342,16 +340,14 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void piece_picker::verify_priority(int const range_start
|
||||
, int const range_end
|
||||
void piece_picker::verify_priority(prio_index_t const range_start
|
||||
, prio_index_t const range_end
|
||||
, int const prio) const
|
||||
{
|
||||
TORRENT_ASSERT(range_start <= range_end);
|
||||
TORRENT_ASSERT(range_end <= int(m_pieces.size()));
|
||||
for (auto i = m_pieces.begin() + range_start
|
||||
, end(m_pieces.begin() + range_end); i != end; ++i)
|
||||
TORRENT_ASSERT(range_end <= m_pieces.end_index());
|
||||
for (auto index : range(m_pieces, range_start, range_end))
|
||||
{
|
||||
piece_index_t const index = *i;
|
||||
int p = m_piece_map[index].priority(this);
|
||||
TORRENT_ASSERT(p == prio);
|
||||
}
|
||||
|
@ -368,16 +364,14 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
for (int b : m_priority_boundaries)
|
||||
{
|
||||
for (prio_index_t b : m_priority_boundaries)
|
||||
std::cerr << b << " ";
|
||||
}
|
||||
|
||||
std::cerr << std::endl;
|
||||
int index = 0;
|
||||
prio_index_t index(0);
|
||||
std::cerr << "[" << this << "] ";
|
||||
std::vector<int>::const_iterator j = m_priority_boundaries.begin();
|
||||
for (auto i = m_pieces.begin()
|
||||
, end(m_pieces.end()); i != end; ++i, ++index)
|
||||
auto j = m_priority_boundaries.begin();
|
||||
for (auto i = m_pieces.begin(), end(m_pieces.end()); i != end; ++i, ++index)
|
||||
{
|
||||
if (limit == 0)
|
||||
{
|
||||
|
@ -424,8 +418,8 @@ namespace libtorrent
|
|||
// make sure the priority boundaries are monotonically increasing. The
|
||||
// difference between two cursors cannot be negative, but ranges are
|
||||
// allowed to be empty.
|
||||
int last = 0;
|
||||
for (int b : m_priority_boundaries)
|
||||
prio_index_t last(0);
|
||||
for (prio_index_t b : m_priority_boundaries)
|
||||
{
|
||||
TORRENT_ASSERT(b >= last);
|
||||
last = b;
|
||||
|
@ -545,14 +539,14 @@ namespace libtorrent
|
|||
{
|
||||
TORRENT_ASSERT(!m_priority_boundaries.empty());
|
||||
int prio = 0;
|
||||
int start = 0;
|
||||
for (int b : m_priority_boundaries)
|
||||
prio_index_t start(0);
|
||||
for (prio_index_t b : m_priority_boundaries)
|
||||
{
|
||||
verify_priority(start, b, prio);
|
||||
++prio;
|
||||
start = b;
|
||||
}
|
||||
TORRENT_ASSERT(m_priority_boundaries.back() == int(m_pieces.size()));
|
||||
TORRENT_ASSERT(m_priority_boundaries.back() == m_pieces.end_index());
|
||||
}
|
||||
|
||||
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
||||
|
@ -582,10 +576,9 @@ namespace libtorrent
|
|||
int num_filtered = 0;
|
||||
int num_have_filtered = 0;
|
||||
int num_have = 0;
|
||||
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin();
|
||||
i != m_piece_map.end(); ++i)
|
||||
piece_index_t piece(0);
|
||||
for (auto i = m_piece_map.begin(); i != m_piece_map.end(); ++i, ++piece)
|
||||
{
|
||||
piece_index_t const index = piece_index_t(int(i - m_piece_map.begin()));
|
||||
piece_pos const& p = *i;
|
||||
|
||||
if (p.filtered())
|
||||
|
@ -604,12 +597,12 @@ namespace libtorrent
|
|||
|
||||
if (p.index == piece_pos::we_have_index)
|
||||
{
|
||||
TORRENT_ASSERT(t == nullptr || t->have_piece(index));
|
||||
TORRENT_ASSERT(t == nullptr || t->have_piece(piece));
|
||||
TORRENT_ASSERT(p.downloading() == false);
|
||||
}
|
||||
|
||||
if (t != nullptr)
|
||||
TORRENT_ASSERT(!t->have_piece(index));
|
||||
TORRENT_ASSERT(!t->have_piece(piece));
|
||||
|
||||
int const prio = p.priority(this);
|
||||
|
||||
|
@ -632,8 +625,8 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
||||
if (prio >= 0)
|
||||
{
|
||||
TORRENT_ASSERT(p.index < m_pieces.size());
|
||||
TORRENT_ASSERT(m_pieces[p.index] == index);
|
||||
TORRENT_ASSERT(p.index < m_pieces.end_index());
|
||||
TORRENT_ASSERT(m_pieces[p.index] == piece);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -641,29 +634,29 @@ namespace libtorrent
|
|||
// make sure there's no entry
|
||||
// with this index. (there shouldn't
|
||||
// be since the priority is -1)
|
||||
TORRENT_ASSERT(std::count(m_pieces.begin(), m_pieces.end(), index) == 0);
|
||||
TORRENT_ASSERT(std::count(m_pieces.begin(), m_pieces.end(), piece) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
int const count_downloading = int(std::count_if(
|
||||
m_downloads[piece_pos::piece_downloading].begin()
|
||||
, m_downloads[piece_pos::piece_downloading].end()
|
||||
, has_index(index)));
|
||||
, has_index(piece)));
|
||||
|
||||
int const count_full = int(std::count_if(
|
||||
m_downloads[piece_pos::piece_full].begin()
|
||||
, m_downloads[piece_pos::piece_full].end()
|
||||
, has_index(index)));
|
||||
, has_index(piece)));
|
||||
|
||||
int const count_finished = int(std::count_if(
|
||||
m_downloads[piece_pos::piece_finished].begin()
|
||||
, m_downloads[piece_pos::piece_finished].end()
|
||||
, has_index(index)));
|
||||
, has_index(piece)));
|
||||
|
||||
int const count_zero = int(std::count_if(
|
||||
m_downloads[piece_pos::piece_zero_prio].begin()
|
||||
, m_downloads[piece_pos::piece_zero_prio].end()
|
||||
, has_index(index)));
|
||||
, has_index(piece)));
|
||||
|
||||
TORRENT_ASSERT(i->download_queue() == piece_pos::piece_open
|
||||
|| count_zero + count_downloading + count_full
|
||||
|
@ -742,15 +735,25 @@ namespace libtorrent
|
|||
return std::make_pair(min_availability + m_seeds, fraction_part * 1000 / num_pieces);
|
||||
}
|
||||
|
||||
std::pair<int, int> piece_picker::priority_range(int const prio)
|
||||
prio_index_t piece_picker::priority_begin(int const prio) const
|
||||
{
|
||||
TORRENT_ASSERT(prio >= 0);
|
||||
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()) || m_dirty);
|
||||
std::pair<int, int> const ret{
|
||||
prio == 0 ? 0 : m_priority_boundaries[prio-1]
|
||||
, m_priority_boundaries[prio]};
|
||||
TORRENT_ASSERT(ret.first <= ret.second);
|
||||
return ret;
|
||||
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
||||
return prio == 0 ? prio_index_t(0) : m_priority_boundaries[prio-1];
|
||||
}
|
||||
|
||||
prio_index_t piece_picker::priority_end(int const prio) const
|
||||
{
|
||||
TORRENT_ASSERT(prio >= 0);
|
||||
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
||||
return m_priority_boundaries[prio];
|
||||
}
|
||||
|
||||
std::pair<prio_index_t, prio_index_t> piece_picker::priority_range(int const prio) const
|
||||
{
|
||||
TORRENT_ASSERT(prio >= 0);
|
||||
TORRENT_ASSERT(prio < int(m_priority_boundaries.size()));
|
||||
return { priority_begin(prio), priority_end(prio) };
|
||||
}
|
||||
|
||||
void piece_picker::add(piece_index_t index)
|
||||
|
@ -765,14 +768,14 @@ namespace libtorrent
|
|||
if (priority < 0) return;
|
||||
|
||||
if (int(m_priority_boundaries.size()) <= priority)
|
||||
m_priority_boundaries.resize(priority + 1, int(m_pieces.size()));
|
||||
m_priority_boundaries.resize(priority + 1, m_pieces.end_index());
|
||||
|
||||
TORRENT_ASSERT(int(m_priority_boundaries.size()) >= priority);
|
||||
|
||||
auto const range = priority_range(priority);
|
||||
int new_index = (range.second == range.first)
|
||||
prio_index_t new_index = (range.second == range.first)
|
||||
? range.first
|
||||
: random(range.second - range.first) + range.first;
|
||||
: prio_index_t(random(static_cast<int>(range.second - range.first)) + static_cast<int>(range.first));
|
||||
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
std::cerr << "[" << this << "] " << "add " << index << " (" << priority << ")" << std::endl;
|
||||
|
@ -786,14 +789,14 @@ namespace libtorrent
|
|||
|
||||
for (;;)
|
||||
{
|
||||
TORRENT_ASSERT(new_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(new_index < m_pieces.end_index());
|
||||
{
|
||||
piece_index_t temp = m_pieces[new_index];
|
||||
m_pieces[new_index] = index;
|
||||
m_piece_map[index].index = new_index;
|
||||
index = temp;
|
||||
}
|
||||
int temp = -1;
|
||||
prio_index_t temp(-1);
|
||||
do
|
||||
{
|
||||
temp = m_priority_boundaries[priority]++;
|
||||
|
@ -808,11 +811,11 @@ namespace libtorrent
|
|||
<< std::endl;
|
||||
#endif
|
||||
if (priority >= int(m_priority_boundaries.size())) break;
|
||||
TORRENT_ASSERT(temp >= 0);
|
||||
TORRENT_ASSERT(temp >= prio_index_t(0));
|
||||
}
|
||||
if (index != piece_index_t(-1))
|
||||
{
|
||||
TORRENT_ASSERT(new_index == int(m_pieces.size() - 1));
|
||||
TORRENT_ASSERT(new_index == prev(m_pieces.end_index()));
|
||||
m_pieces[new_index] = index;
|
||||
m_piece_map[index].index = new_index;
|
||||
|
||||
|
@ -822,25 +825,23 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void piece_picker::remove(int priority, int elem_index)
|
||||
void piece_picker::remove(int priority, prio_index_t elem_index)
|
||||
{
|
||||
TORRENT_ASSERT(!m_dirty);
|
||||
TORRENT_ASSERT(priority >= 0);
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(elem_index >= 0);
|
||||
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
std::cerr << "[" << this << "] " << "remove " << m_pieces[elem_index] << " (" << priority << ")" << std::endl;
|
||||
#endif
|
||||
int next_index = elem_index;
|
||||
prio_index_t next_index = elem_index;
|
||||
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == -1);
|
||||
for (;;)
|
||||
{
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
print_pieces();
|
||||
#endif
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
int temp;
|
||||
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
||||
prio_index_t temp;
|
||||
do
|
||||
{
|
||||
temp = --m_priority_boundaries[priority];
|
||||
|
@ -853,14 +854,14 @@ namespace libtorrent
|
|||
m_pieces[elem_index] = piece;
|
||||
m_piece_map[piece].index = elem_index;
|
||||
TORRENT_ASSERT(m_piece_map[piece].priority(this) == priority - 1);
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size() - 1));
|
||||
TORRENT_ASSERT(elem_index < prev(m_pieces.end_index()));
|
||||
elem_index = next_index;
|
||||
|
||||
if (priority == int(m_priority_boundaries.size()))
|
||||
break;
|
||||
}
|
||||
m_pieces.pop_back();
|
||||
TORRENT_ASSERT(next_index == int(m_pieces.size()));
|
||||
TORRENT_ASSERT(next_index == m_pieces.end_index());
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
print_pieces();
|
||||
#endif
|
||||
|
@ -868,11 +869,9 @@ namespace libtorrent
|
|||
|
||||
// will update the piece with the given properties (priority, elem_index)
|
||||
// to place it at the correct position
|
||||
void piece_picker::update(int priority, int elem_index)
|
||||
void piece_picker::update(int priority, prio_index_t elem_index)
|
||||
{
|
||||
TORRENT_ASSERT(!m_dirty);
|
||||
TORRENT_ASSERT(elem_index >= 0);
|
||||
TORRENT_ASSERT(elem_index < int(m_piece_map.size()));
|
||||
TORRENT_ASSERT(priority >= 0);
|
||||
TORRENT_ASSERT(int(m_priority_boundaries.size()) > priority);
|
||||
|
||||
|
@ -880,13 +879,13 @@ namespace libtorrent
|
|||
// priority bucket. If it doesn't, it means this piece changed
|
||||
// state without updating the corresponding entry in the pieces list
|
||||
TORRENT_ASSERT(m_priority_boundaries[priority] >= elem_index);
|
||||
TORRENT_ASSERT(priority == 0 || m_priority_boundaries[priority - 1] <= elem_index);
|
||||
TORRENT_ASSERT(priority + 1 == int(m_priority_boundaries.size()) || m_priority_boundaries[priority + 1] > elem_index);
|
||||
TORRENT_ASSERT(elem_index >= priority_begin(priority));
|
||||
TORRENT_ASSERT(elem_index < priority_end(priority));
|
||||
|
||||
piece_index_t const index = m_pieces[elem_index];
|
||||
// update the piece_map
|
||||
piece_pos& p = m_piece_map[index];
|
||||
TORRENT_ASSERT(int(p.index) == elem_index || p.have());
|
||||
TORRENT_ASSERT(p.index == elem_index || p.have());
|
||||
|
||||
int const new_priority = p.priority(this);
|
||||
|
||||
|
@ -899,14 +898,14 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
if (int(m_priority_boundaries.size()) <= new_priority)
|
||||
m_priority_boundaries.resize(new_priority + 1, int(m_pieces.size()));
|
||||
m_priority_boundaries.resize(new_priority + 1, m_pieces.end_index());
|
||||
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
std::cerr << "[" << this << "] " << "update " << index << " (" << priority << "->" << new_priority << ")" << std::endl;
|
||||
#endif
|
||||
if (priority > new_priority)
|
||||
{
|
||||
int new_index;
|
||||
prio_index_t new_index;
|
||||
piece_index_t temp = index;
|
||||
for (;;)
|
||||
{
|
||||
|
@ -916,14 +915,12 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(priority > 0);
|
||||
--priority;
|
||||
new_index = m_priority_boundaries[priority]++;
|
||||
TORRENT_ASSERT(new_index >= 0);
|
||||
TORRENT_ASSERT(new_index < int(m_pieces.size()));
|
||||
if (temp != m_pieces[new_index])
|
||||
{
|
||||
temp = m_pieces[new_index];
|
||||
m_pieces[elem_index] = temp;
|
||||
m_piece_map[temp].index = elem_index;
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
||||
}
|
||||
elem_index = new_index;
|
||||
if (priority == new_priority) break;
|
||||
|
@ -933,7 +930,7 @@ namespace libtorrent
|
|||
#endif
|
||||
m_pieces[elem_index] = index;
|
||||
m_piece_map[index].index = elem_index;
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
print_pieces();
|
||||
#endif
|
||||
|
@ -945,7 +942,7 @@ namespace libtorrent
|
|||
}
|
||||
else
|
||||
{
|
||||
int new_index;
|
||||
prio_index_t new_index;
|
||||
piece_index_t temp = index;
|
||||
for (;;)
|
||||
{
|
||||
|
@ -955,14 +952,12 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(priority >= 0);
|
||||
TORRENT_ASSERT(priority < int(m_priority_boundaries.size()));
|
||||
new_index = --m_priority_boundaries[priority];
|
||||
TORRENT_ASSERT(new_index >= 0);
|
||||
TORRENT_ASSERT(new_index < int(m_pieces.size()));
|
||||
if (temp != m_pieces[new_index])
|
||||
{
|
||||
temp = m_pieces[new_index];
|
||||
m_pieces[elem_index] = temp;
|
||||
m_piece_map[temp].index = elem_index;
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
||||
}
|
||||
elem_index = new_index;
|
||||
++priority;
|
||||
|
@ -973,7 +968,7 @@ namespace libtorrent
|
|||
#endif
|
||||
m_pieces[elem_index] = index;
|
||||
m_piece_map[index].index = elem_index;
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
print_pieces();
|
||||
#endif
|
||||
|
@ -985,7 +980,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void piece_picker::shuffle(int priority, int elem_index)
|
||||
void piece_picker::shuffle(int priority, prio_index_t elem_index)
|
||||
{
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
std::cerr << "[" << this << "] " << "shuffle()" << std::endl;
|
||||
|
@ -993,12 +988,12 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(!m_dirty);
|
||||
TORRENT_ASSERT(priority >= 0);
|
||||
TORRENT_ASSERT(elem_index >= 0);
|
||||
TORRENT_ASSERT(elem_index < int(m_pieces.size()));
|
||||
TORRENT_ASSERT(elem_index >= prio_index_t(0));
|
||||
TORRENT_ASSERT(elem_index < m_pieces.end_index());
|
||||
TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == priority);
|
||||
|
||||
auto const range = priority_range(priority);
|
||||
int const other_index = random(range.second - range.first - 1) + range.first;
|
||||
prio_index_t const other_index(random(static_cast<int>(range.second - range.first) - 1) + static_cast<int>(range.first));
|
||||
|
||||
if (other_index == elem_index) return;
|
||||
|
||||
|
@ -1429,19 +1424,23 @@ namespace libtorrent
|
|||
void piece_picker::update_pieces() const
|
||||
{
|
||||
TORRENT_ASSERT(m_dirty);
|
||||
if (m_priority_boundaries.empty()) m_priority_boundaries.resize(1, 0);
|
||||
if (m_priority_boundaries.empty()) m_priority_boundaries.resize(1, prio_index_t(0));
|
||||
#ifdef TORRENT_PICKER_LOG
|
||||
std::cerr << "[" << this << "] " << "update_pieces" << std::endl;
|
||||
#endif
|
||||
std::fill(m_priority_boundaries.begin(), m_priority_boundaries.end(), 0);
|
||||
for (std::vector<piece_pos>::iterator i = m_piece_map.begin()
|
||||
, end(m_piece_map.end()); i != end; ++i)
|
||||
|
||||
// This code is unfortunately not very straight-forward. What we do here
|
||||
// is to count the number of pieces at every priority level. After this
|
||||
// first step, m_priority_boundaries will contain *deltas* rather than
|
||||
// absolute indices. This is fixed up in a second pass below
|
||||
std::fill(m_priority_boundaries.begin(), m_priority_boundaries.end(), prio_index_t(0));
|
||||
for (auto& pos : m_piece_map)
|
||||
{
|
||||
int prio = i->priority(this);
|
||||
int prio = pos.priority(this);
|
||||
if (prio == -1) continue;
|
||||
if (prio >= int(m_priority_boundaries.size()))
|
||||
m_priority_boundaries.resize(prio + 1, 0);
|
||||
i->index = m_priority_boundaries[prio];
|
||||
m_priority_boundaries.resize(prio + 1, prio_index_t(0));
|
||||
pos.index = m_priority_boundaries[prio];
|
||||
++m_priority_boundaries[prio];
|
||||
}
|
||||
|
||||
|
@ -1449,11 +1448,15 @@ namespace libtorrent
|
|||
print_pieces();
|
||||
#endif
|
||||
|
||||
// m_priority_boundaries just contain counters of
|
||||
// each priority level at this point. Now, make the m_priority_boundaries
|
||||
// be cumulative indices into m_pieces (but m_pieces hasn't been set up
|
||||
// yet)
|
||||
int new_size = 0;
|
||||
for (int& b : m_priority_boundaries)
|
||||
for (prio_index_t& b : m_priority_boundaries)
|
||||
{
|
||||
new_size += b;
|
||||
b = new_size;
|
||||
new_size += static_cast<int>(b);
|
||||
b = prio_index_t(new_size);
|
||||
}
|
||||
m_pieces.resize(new_size, piece_index_t(0));
|
||||
|
||||
|
@ -1461,26 +1464,32 @@ namespace libtorrent
|
|||
print_pieces();
|
||||
#endif
|
||||
|
||||
// set up m_pieces to contain valid piece indices, based on piece
|
||||
// priority. m_piece_map[].index is still just an index relative to the
|
||||
// respective priority range.
|
||||
piece_index_t piece = piece_index_t(0);
|
||||
for (auto i = m_piece_map.begin()
|
||||
, end(m_piece_map.end()); i != end; ++i, ++piece)
|
||||
for (auto i = m_piece_map.begin(), end(m_piece_map.end()); i != end; ++i, ++piece)
|
||||
{
|
||||
piece_pos& p = *i;
|
||||
int const prio = p.priority(this);
|
||||
if (prio == -1) continue;
|
||||
int const new_index = (prio == 0 ? 0 : m_priority_boundaries[prio - 1]) + p.index;
|
||||
prio_index_t const new_index(priority_begin(prio)
|
||||
+ prio_index_t::diff_type(static_cast<int>(p.index)));
|
||||
m_pieces[new_index] = piece;
|
||||
}
|
||||
|
||||
int start = 0;
|
||||
for (int b : m_priority_boundaries)
|
||||
prio_index_t start(0);
|
||||
for (auto b : m_priority_boundaries)
|
||||
{
|
||||
if (start == b) continue;
|
||||
aux::random_shuffle(&m_pieces[0] + start, &m_pieces[0] + b);
|
||||
auto r = range(m_pieces, start, b);
|
||||
aux::random_shuffle(r.begin(), r.end());
|
||||
start = b;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
// this is where we set fix up the m_piece_map[].index to actually map
|
||||
// back to the piece list ordered by priority (m_pieces)
|
||||
prio_index_t index(0);
|
||||
for (auto p : m_pieces)
|
||||
{
|
||||
m_piece_map[p].index = index;
|
||||
|
@ -1585,7 +1594,7 @@ namespace libtorrent
|
|||
<< index << ")" << std::endl;
|
||||
#endif
|
||||
piece_pos& p = m_piece_map[index];
|
||||
int const info_index = p.index;
|
||||
prio_index_t const info_index = p.index;
|
||||
int const priority = p.priority(this);
|
||||
TORRENT_ASSERT(priority < int(m_priority_boundaries.size()) || m_dirty);
|
||||
|
||||
|
@ -2068,9 +2077,9 @@ namespace libtorrent
|
|||
{
|
||||
for (int i = int(m_priority_boundaries.size()) - 1; i >= 0; --i)
|
||||
{
|
||||
int const start = (i == 0) ? 0 : m_priority_boundaries[i - 1];
|
||||
int const end = m_priority_boundaries[i];
|
||||
for (int p = end - 1; p >= start; --p)
|
||||
prio_index_t const start = priority_begin(i);
|
||||
prio_index_t const end = priority_end(i);
|
||||
for (prio_index_t p = prev(end); p >= start; --p)
|
||||
{
|
||||
pc.inc_stats_counter(counters::piece_picker_reverse_rare_loops);
|
||||
|
||||
|
|
Loading…
Reference in New Issue