optimize block_info allocation and downloading_piece size in piece_picker

This commit is contained in:
Arvid Norberg 2015-02-14 21:32:41 +00:00
parent e15e5fd80a
commit 2fdb7499fa
5 changed files with 244 additions and 208 deletions

View File

@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/tuple/tuple.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
@ -160,7 +161,8 @@ namespace libtorrent
struct downloading_piece
{
downloading_piece() : info(NULL), index(-1)
downloading_piece() : index(UINT32_MAX)
, info_idx(UINT16_MAX)
, finished(0)
, passed_hash_check(0)
, writing(0)
@ -170,15 +172,14 @@ namespace libtorrent
bool operator<(downloading_piece const& rhs) const { return index < rhs.index; }
// info about each block
// this is a pointer into the m_block_info
// vector owned by the piece_picker
// TODO: 2 if we could make this an index into m_block_info instead
// we would save at least 4 or 5 bytes
block_info* info;
// the index of the piece
int index;
boost::uint32_t index;
// info about each block in this piece. this is an index into the
// m_block_info array, when multiplied by m_blocks_per_piece.
// The m_blocks_per_piece following entries contain information about
// all blocks in this piece.
boost::uint16_t info_idx;
// the number of blocks in the finished state
boost::uint16_t finished:15;
@ -472,10 +473,19 @@ namespace libtorrent
void set_num_pad_files(int n) { m_num_pad_files = n; }
// return the array of block_info objects for a given downloading_piece.
// this array has m_blocks_per_piece elements in it
block_info* blocks_for_piece(downloading_piece const& dp);
block_info const* blocks_for_piece(downloading_piece const& dp) const;
private:
friend struct piece_pos;
boost::tuple<bool, bool, int, int> requested_from(
piece_picker::downloading_piece const& p
, int num_blocks_in_piece, void* peer) const;
bool can_pick(int piece, bitfield const& bitmask) const;
bool is_piece_free(int piece, bitfield const& bitmask) const;
std::pair<int, int> expand_piece(int piece, int whole_pieces
@ -518,7 +528,7 @@ namespace libtorrent
// this is not a new download category/download list bucket.
// it still goes into the piece_downloading bucket. However,
// it indicates that this piece only has outstanding requests
// form reverse peers. This is to de-prioritize it somewhat
// from reverse peers. This is to de-prioritize it somewhat
piece_downloading_reverse,
piece_full_reverse
};
@ -778,12 +788,17 @@ namespace libtorrent
// piece_downloading).
std::vector<downloading_piece> m_downloads[piece_pos::num_download_categories];
// this holds the information of the
// blocks in partially downloaded pieces.
// the downloading_piece::info pointers
// point into this vector for its storage
// this holds the information of the blocks in partially downloaded
// pieces. the downloading_piece::info index point into this vector for
// its storage
std::vector<block_info> m_block_info;
// these are block ranges in m_block_info that are free. The numbers
// in here, when multiplied by m_blocks_per_piece is the index to the
// first block in the range that's free to use by a new downloading_piece.
// this is a free-list.
std::vector<boost::uint16_t> m_free_block_infos;
boost::uint16_t m_blocks_per_piece;
boost::uint16_t m_blocks_in_last_piece;

View File

@ -679,7 +679,7 @@ namespace libtorrent
void get_full_peer_list(std::vector<peer_list_entry>& v) const;
void get_peer_info(std::vector<peer_info>& v);
void get_download_queue(std::vector<partial_piece_info>* queue);
void get_download_queue(std::vector<partial_piece_info>* queue) const;
void refresh_explicit_cache(int cache_size);
@ -971,6 +971,11 @@ namespace libtorrent
TORRENT_ASSERT(m_picker.get());
return *m_picker;
}
piece_picker const& picker() const
{
TORRENT_ASSERT(m_picker.get());
return *m_picker;
}
void need_picker();
bool has_picker() const
{

View File

@ -2936,7 +2936,9 @@ namespace libtorrent
{
if (i->index != block_finished.piece_index) continue;
piece_picker::downloading_piece const& p = *i;
TORRENT_ASSERT(p.info[block_finished.block_index].state == piece_picker::block_info::state_finished);
piece_picker::block_info* info = picker.blocks_for_piece(p);
TORRENT_ASSERT(info[block_finished.block_index].state
== piece_picker::block_info::state_finished);
}
}
#endif

View File

@ -152,12 +152,13 @@ namespace libtorrent
int state = m_piece_map[index].download_queue();
if (state != piece_pos::piece_open)
{
// TODO: 3 we need a different type to return to the outside here
std::vector<downloading_piece>::const_iterator piece = find_dl_piece(state, index);
TORRENT_ASSERT(piece != m_downloads[state].end());
st = *piece;
return;
}
st.info = 0;
st.info_idx = 0;
st.index = index;
st.writing = 0;
st.requested = 0;
@ -190,30 +191,22 @@ namespace libtorrent
check_piece_state();
#endif
int num_downloads = 0;
for (int k = 0; k < piece_pos::num_download_categories; ++k)
num_downloads += m_downloads[k].size();
int block_index;
int block_index = num_downloads * m_blocks_per_piece;
if (int(m_block_info.size()) < block_index + m_blocks_per_piece)
if (m_free_block_infos.empty())
{
block_info* base = NULL;
if (!m_block_info.empty()) base = &m_block_info[0];
m_block_info.resize(block_index + m_blocks_per_piece);
if (base != NULL && &m_block_info[0] != base)
{
for (int k = 0; k < piece_pos::num_download_categories; ++k)
{
// this means the memory was reallocated, update the pointers
for (int i = 0; i < int(m_downloads[k].size()); ++i)
{
TORRENT_ASSERT(m_downloads[k][i].info >= base);
TORRENT_ASSERT(m_downloads[k][i].info < base + m_block_info.size());
m_downloads[k][i].info = &m_block_info[m_downloads[k][i].info - base];
}
}
}
// we need to allocate more space in m_block_info
block_index = m_block_info.size() / m_blocks_per_piece;
TORRENT_ASSERT((m_block_info.size() % m_blocks_per_piece) == 0);
m_block_info.resize(m_block_info.size() + m_blocks_per_piece);
}
else
{
// there is already free space in m_block_info, grab one range
block_index = m_free_block_infos.back();
m_free_block_infos.pop_back();
}
// always insert into bucket 0 (piece_downloading)
downloading_piece ret;
ret.index = piece;
@ -222,24 +215,28 @@ namespace libtorrent
= std::lower_bound(m_downloads[download_state].begin()
, m_downloads[download_state].end(), ret);
TORRENT_ASSERT(i == m_downloads[download_state].end() || i->index != piece);
ret.info = &m_block_info[block_index];
TORRENT_ASSERT(ret.info >= &m_block_info[0]);
TORRENT_ASSERT(ret.info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(block_index >= 0);
TORRENT_ASSERT(block_index < UINT16_MAX);
ret.info_idx = block_index;
TORRENT_ASSERT(int(ret.info_idx) * m_blocks_per_piece
+ m_blocks_per_piece <= m_block_info.size());
#ifdef TORRENT_USE_VALGRIND
VALGRIND_CHECK_VALUE_IS_DEFINED(piece);
VALGRIND_CHECK_VALUE_IS_DEFINED(block_index);
#endif
block_info* info = blocks_for_piece(ret);
for (int i = 0; i < m_blocks_per_piece; ++i)
{
ret.info[i].num_peers = 0;
ret.info[i].state = block_info::state_none;
ret.info[i].peer = 0;
info[i].num_peers = 0;
info[i].state = block_info::state_none;
info[i].peer = 0;
#ifdef TORRENT_USE_VALGRIND
VALGRIND_CHECK_VALUE_IS_DEFINED(ret.info[i].peer);
VALGRIND_CHECK_VALUE_IS_DEFINED(info[i].peer);
#endif
#if TORRENT_USE_ASSERTS
ret.info[i].piece_index = piece;
ret.info[i].peers.clear();
info[i].piece_index = piece;
info[i].peers.clear();
#endif
}
#ifdef TORRENT_USE_VALGRIND
@ -267,30 +264,10 @@ namespace libtorrent
int prev_size = m_downloads[download_state].size();
#endif
int total_downloading_pieces = 0;
for (int k = 0; k < piece_pos::num_download_categories; ++k) total_downloading_pieces += m_downloads[k].size();
std::vector<downloading_piece>::iterator other;
bool found = false;
for (int k = 0; k < piece_pos::num_download_categories; ++k)
{
other = std::find_if(
m_downloads[k].begin(), m_downloads[k].end()
, boost::bind(&downloading_piece::info, _1)
== &m_block_info[(total_downloading_pieces - 1) * m_blocks_per_piece]);
if (other != m_downloads[k].end())
{
found = true;
break;
}
}
TORRENT_ASSERT(found);
if (found && i->index != other->index)
{
std::copy(other->info, other->info + m_blocks_per_piece, i->info);
other->info = i->info;
}
// since we're removing a downloading_piece, we also need to free its
// blocks that are allocated from the m_block_info array.
m_free_block_infos.push_back(i->info_idx);
m_piece_map[i->index].download_state = piece_pos::piece_open;
m_downloads[download_state].erase(i);
@ -330,6 +307,20 @@ namespace libtorrent
*zero_prio = m_downloads[piece_pos::piece_zero_prio].size();
}
piece_picker::block_info* piece_picker::blocks_for_piece(
downloading_piece const& dp)
{
int idx = int(dp.info_idx) * m_blocks_per_piece;
TORRENT_ASSERT(idx + m_blocks_per_piece <= m_block_info.size());
return &m_block_info[idx];
}
piece_picker::block_info const* piece_picker::blocks_for_piece(
downloading_piece const& dp) const
{
return const_cast<piece_picker*>(this)->blocks_for_piece(dp);
}
#if TORRENT_USE_INVARIANT_CHECKS
void piece_picker::check_piece_state() const
@ -346,16 +337,17 @@ namespace libtorrent
downloading_piece const& next = *(i + 1);
// TORRENT_ASSERT(dp.finished + dp.writing >= next.finished + next.writing);
TORRENT_ASSERT(dp.index < next.index);
TORRENT_ASSERT(dp.info >= &m_block_info[0]);
TORRENT_ASSERT(dp.info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT((dp.info - &m_block_info[0]) % m_blocks_per_piece == 0);
TORRENT_ASSERT(int(dp.info_idx) * m_blocks_per_piece
+ m_blocks_per_piece <= m_block_info.size());
block_info const* info = blocks_for_piece(dp);
for (int k = 0; k < m_blocks_per_piece; ++k)
{
if (dp.info[k].peer)
if (info[k].peer)
{
torrent_peer* p = (torrent_peer*)dp.info[k].peer;
torrent_peer* p = (torrent_peer*)info[k].peer;
TORRENT_ASSERT(p->in_use);
TORRENT_ASSERT(p->connection == NULL || static_cast<peer_connection*>(p->connection)->m_in_use);
TORRENT_ASSERT(p->connection == NULL
|| static_cast<peer_connection*>(p->connection)->m_in_use);
}
}
}
@ -475,19 +467,17 @@ namespace libtorrent
downloading_piece const& next = *(i + 1);
// TORRENT_ASSERT(dp.finished + dp.writing >= next.finished + next.writing);
TORRENT_ASSERT(dp.index < next.index);
TORRENT_ASSERT(dp.info >= &m_block_info[0]);
TORRENT_ASSERT(dp.info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT((dp.info - &m_block_info[0]) % m_blocks_per_piece == 0);
TORRENT_ASSERT(int(dp.info_idx) * m_blocks_per_piece
+ m_blocks_per_piece <= m_block_info.size());
#if TORRENT_USE_ASSERTS
block_info const* info = blocks_for_piece(dp);
for (int k = 0; k < m_blocks_per_piece; ++k)
{
if (dp.info[k].peer)
{
torrent_peer* p = (torrent_peer*)dp.info[k].peer;
TORRENT_ASSERT(p->in_use);
TORRENT_ASSERT(p->connection == NULL
|| static_cast<peer_connection*>(p->connection)->m_in_use);
}
if (!info[k].peer) continue;
torrent_peer* p = (torrent_peer*)info[k].peer;
TORRENT_ASSERT(p->in_use);
TORRENT_ASSERT(p->connection == NULL
|| static_cast<peer_connection*>(p->connection)->m_in_use);
}
#endif
}
@ -509,32 +499,33 @@ namespace libtorrent
int num_finished = 0;
int num_writing = 0;
int num_open = 0;
block_info const* info = blocks_for_piece(*i);
for (int k = 0; k < num_blocks; ++k)
{
TORRENT_ASSERT(i->info[k].piece_index == i->index);
TORRENT_ASSERT(i->info[k].peer == 0
|| static_cast<torrent_peer*>(i->info[k].peer)->in_use);
TORRENT_ASSERT(info[k].piece_index == i->index);
TORRENT_ASSERT(info[k].peer == 0
|| static_cast<torrent_peer*>(info[k].peer)->in_use);
if (i->info[k].state == block_info::state_finished)
if (info[k].state == block_info::state_finished)
{
++num_finished;
TORRENT_ASSERT(i->info[k].num_peers == 0);
TORRENT_ASSERT(info[k].num_peers == 0);
}
else if (i->info[k].state == block_info::state_requested)
else if (info[k].state == block_info::state_requested)
{
++num_requested;
blocks_requested = true;
TORRENT_ASSERT(i->info[k].num_peers > 0);
TORRENT_ASSERT(info[k].num_peers > 0);
}
else if (i->info[k].state == block_info::state_writing)
else if (info[k].state == block_info::state_writing)
{
++num_writing;
TORRENT_ASSERT(i->info[k].num_peers == 0);
TORRENT_ASSERT(info[k].num_peers == 0);
}
else if (i->info[k].state == block_info::state_none)
else if (info[k].state == block_info::state_none)
{
++num_open;
TORRENT_ASSERT(i->info[k].num_peers == 0);
TORRENT_ASSERT(info[k].num_peers == 0);
}
}
@ -1111,8 +1102,8 @@ namespace libtorrent
std::vector<downloading_piece>::iterator i = find_dl_piece(download_state, index);
TORRENT_ASSERT(i != m_downloads[download_state].end());
TORRENT_ASSERT(i->info >= &m_block_info[0]
&& i->info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(int(i->info_idx) * m_blocks_per_piece
+ m_blocks_per_piece <= m_block_info.size());
i->locked = false;
@ -2408,10 +2399,12 @@ get_out:
// as backups
int num_blocks_in_piece = blocks_in_piece(dp->index);
TORRENT_ASSERT(dp->requested > 0);
block_info const* binfo = blocks_for_piece(*dp);
for (int j = 0; j < num_blocks_in_piece; ++j)
{
block_info const& info = dp->info[j];
TORRENT_ASSERT(info.peer == 0 || static_cast<torrent_peer*>(info.peer)->in_use);
block_info const& info = binfo[j];
TORRENT_ASSERT(info.peer == 0
|| static_cast<torrent_peer*>(info.peer)->in_use);
TORRENT_ASSERT(info.piece_index == dp->index);
if (info.state != block_info::state_requested
|| info.peer == peer)
@ -2449,9 +2442,10 @@ get_out:
continue;
int num_blocks_in_piece = blocks_in_piece(i->index);
block_info const* binfo = blocks_for_piece(*i);
for (int j = 0; j < num_blocks_in_piece; ++j)
{
block_info const& info = i->info[j];
block_info const& info = binfo[j];
TORRENT_ASSERT(info.piece_index == i->index);
if (info.state != block_info::state_none) continue;
std::vector<piece_block>::iterator k = std::find(
@ -2468,10 +2462,11 @@ get_out:
= m_downloads[piece_pos::piece_downloading].begin()
, end(m_downloads[piece_pos::piece_downloading].end()); l != end; ++l)
{
block_info const* binfo2 = blocks_for_piece(*l);
fprintf(stderr, "%d : ", l->index);
int num_blocks_in_piece = blocks_in_piece(l->index);
for (int m = 0; m < num_blocks_in_piece; ++m)
fprintf(stderr, "%d", l->info[m].state);
fprintf(stderr, "%d", binfo2[m].state);
fprintf(stderr, "\n");
}
@ -2499,9 +2494,10 @@ get_out:
// this assert is not valid for web_seeds
/*
int num_blocks_in_piece = blocks_in_piece(k->index);
block_info const* binfo = blocks_for_piece(*k);
for (int j = 0; j < num_blocks_in_piece; ++j)
{
block_info const& info = k->info[j];
block_info const& info = binfo[j];
TORRENT_ASSERT(info.piece_index == k->index);
if (info.state == block_info::state_finished) continue;
TORRENT_ASSERT(info.peer != 0);
@ -2572,58 +2568,57 @@ get_out:
}
}
namespace
// the first bool is true if this is the only peer that has requested and downloaded
// blocks from this piece.
// the second bool is true if this is the only active peer that is requesting
// and downloading blocks from this piece. Active means having a connection.
// TODO: 2 the first_block returned here is the largest free range, not
// the first-fit range, which would be better
boost::tuple<bool, bool, int, int> piece_picker::requested_from(
piece_picker::downloading_piece const& p
, int num_blocks_in_piece, void* peer) const
{
// the first bool is true if this is the only peer that has requested and downloaded
// blocks from this piece.
// the second bool is true if this is the only active peer that is requesting
// and downloading blocks from this piece. Active means having a connection.
// TODO: 2 the first_block returned here is the largest free range, not
// the first-fit range, which would be better
boost::tuple<bool, bool, int, int> requested_from(
piece_picker::downloading_piece const& p
, int num_blocks_in_piece, void* peer)
bool exclusive = true;
bool exclusive_active = true;
int contiguous_blocks = 0;
int max_contiguous = 0;
int first_block = 0;
block_info const* binfo = blocks_for_piece(p);
for (int j = 0; j < num_blocks_in_piece; ++j)
{
bool exclusive = true;
bool exclusive_active = true;
int contiguous_blocks = 0;
int max_contiguous = 0;
int first_block = 0;
for (int j = 0; j < num_blocks_in_piece; ++j)
piece_picker::block_info const& info = binfo[j];
TORRENT_ASSERT(info.peer == 0 || static_cast<torrent_peer*>(info.peer)->in_use);
TORRENT_ASSERT(info.piece_index == p.index);
if (info.state == piece_picker::block_info::state_none)
{
piece_picker::block_info const& info = p.info[j];
TORRENT_ASSERT(info.peer == 0 || static_cast<torrent_peer*>(info.peer)->in_use);
TORRENT_ASSERT(info.piece_index == p.index);
if (info.state == piece_picker::block_info::state_none)
{
++contiguous_blocks;
continue;
}
if (contiguous_blocks > max_contiguous)
{
max_contiguous = contiguous_blocks;
first_block = j - contiguous_blocks;
}
contiguous_blocks = 0;
if (info.peer != peer)
{
exclusive = false;
if (info.state == piece_picker::block_info::state_requested
&& info.peer != 0)
{
exclusive_active = false;
}
}
++contiguous_blocks;
continue;
}
if (contiguous_blocks > max_contiguous)
{
max_contiguous = contiguous_blocks;
first_block = num_blocks_in_piece - contiguous_blocks;
first_block = j - contiguous_blocks;
}
contiguous_blocks = 0;
if (info.peer != peer)
{
exclusive = false;
if (info.state == piece_picker::block_info::state_requested
&& info.peer != 0)
{
exclusive_active = false;
}
}
return boost::make_tuple(exclusive, exclusive_active, max_contiguous
, first_block);
}
if (contiguous_blocks > max_contiguous)
{
max_contiguous = contiguous_blocks;
first_block = num_blocks_in_piece - contiguous_blocks;
}
return boost::make_tuple(exclusive, exclusive_active, max_contiguous
, first_block);
}
int piece_picker::add_blocks(int piece
, bitfield const& pieces
@ -2742,6 +2737,8 @@ get_out:
// pieces that only they have downloaded/requested from
if ((options & on_parole) && !exclusive) return num_blocks;
block_info const* binfo = blocks_for_piece(dp);
// we prefer whole blocks, but there are other peers
// downloading from this piece and there aren't enough contiguous blocks
// to pick, add it as backups.
@ -2758,7 +2755,7 @@ get_out:
{
// ignore completed blocks and already requested blocks
int block_idx = (j + first_block) % num_blocks_in_piece;
block_info const& info = dp.info[block_idx];
block_info const& info = binfo[block_idx];
TORRENT_ASSERT(info.piece_index == dp.index);
if (info.state != block_info::state_none) continue;
backup_blocks2.push_back(piece_block(dp.index, block_idx));
@ -2770,7 +2767,7 @@ get_out:
{
// ignore completed blocks and already requested blocks
int block_idx = (j + first_block) % num_blocks_in_piece;
block_info const& info = dp.info[block_idx];
block_info const& info = binfo[block_idx];
TORRENT_ASSERT(info.piece_index == dp.index);
if (info.state != block_info::state_none) continue;
@ -2869,11 +2866,12 @@ get_out:
TORRENT_ASSERT(int(i->finished) + int(i->writing) == max_blocks);
#if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
block_info const* info = blocks_for_piece(*i);
for (int k = 0; k < max_blocks; ++k)
{
TORRENT_ASSERT(i->info[k].piece_index == index);
TORRENT_ASSERT(i->info[k].state == block_info::state_finished
|| i->info[k].state == block_info::state_writing);
TORRENT_ASSERT(info[k].piece_index == index);
TORRENT_ASSERT(info[k].state == block_info::state_finished
|| info[k].state == block_info::state_writing);
}
#endif
@ -3020,8 +3018,10 @@ get_out:
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[state].end());
TORRENT_ASSERT(i->info[block.block_index].piece_index == block.piece_index);
return i->info[block.block_index].state;
block_info const* info = blocks_for_piece(*i);
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
return info[block.block_index].state;
}
bool piece_picker::is_requested(piece_block block) const
@ -3039,10 +3039,10 @@ get_out:
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[state].end());
TORRENT_ASSERT(i->info >= &m_block_info[0]
&& i->info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(i->info[block.block_index].piece_index == block.piece_index);
return i->info[block.block_index].state == block_info::state_requested;
block_info const* info = blocks_for_piece(*i);
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
return info[block.block_index].state == block_info::state_requested;
}
bool piece_picker::is_downloaded(piece_block block) const
@ -3060,11 +3060,11 @@ get_out:
std::vector<downloading_piece>::const_iterator i = find_dl_piece(state
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[state].end());
TORRENT_ASSERT(i->info >= &m_block_info[0]
&& i->info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(i->info[block.block_index].piece_index == block.piece_index);
return i->info[block.block_index].state == block_info::state_finished
|| i->info[block.block_index].state == block_info::state_writing;
block_info const* info = blocks_for_piece(*i);
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
return info[block.block_index].state == block_info::state_finished
|| info[block.block_index].state == block_info::state_writing;
}
bool piece_picker::is_finished(piece_block block) const
@ -3082,10 +3082,10 @@ get_out:
std::vector<downloading_piece>::const_iterator i = find_dl_piece(p.download_queue()
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
TORRENT_ASSERT(i->info >= &m_block_info[0]
&& i->info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(i->info[block.block_index].piece_index == block.piece_index);
return i->info[block.block_index].state == block_info::state_finished;
block_info const* info = blocks_for_piece(*i);
TORRENT_ASSERT(info[block.block_index].piece_index == block.piece_index);
return info[block.block_index].state == block_info::state_finished;
}
// options may be 0 or piece_picker::reverse
@ -3121,7 +3121,8 @@ get_out:
if (prio >= 0 && !m_dirty) update(prio, p.index);
dlpiece_iter dp = add_download_piece(block.piece_index);
block_info& info = dp->info[block.block_index];
block_info* binfo = blocks_for_piece(*dp);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(info.piece_index == block.piece_index);
info.state = block_info::state_requested;
info.peer = peer;
@ -3144,9 +3145,8 @@ get_out:
std::vector<downloading_piece>::iterator i = find_dl_piece(p.download_queue()
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
block_info& info = i->info[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
block_info* binfo = blocks_for_piece(*i);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(info.piece_index == block.piece_index);
if (info.state == block_info::state_writing
|| info.state == block_info::state_finished)
@ -3208,7 +3208,8 @@ get_out:
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
block_info const& info = i->info[block.block_index];
block_info const* binfo = blocks_for_piece(*i);
block_info const& info = binfo[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(info.piece_index == block.piece_index);
@ -3270,7 +3271,8 @@ get_out:
if (prio >= 0 && !m_dirty) update(prio, p.index);
dlpiece_iter dp = add_download_piece(block.piece_index);
block_info& info = dp->info[block.block_index];
block_info* binfo = blocks_for_piece(*dp);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(info.piece_index == block.piece_index);
@ -3289,7 +3291,8 @@ get_out:
std::vector<downloading_piece>::iterator i = find_dl_piece(p.download_queue()
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
block_info& info = i->info[block.block_index];
block_info* binfo = blocks_for_piece(*i);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
@ -3376,7 +3379,8 @@ get_out:
std::vector<downloading_piece>::iterator i = find_dl_piece(state, block.piece_index);
if (i == m_downloads[state].end()) return;
block_info& info = i->info[block.block_index];
block_info* binfo = blocks_for_piece(*i);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(info.piece_index == block.piece_index);
@ -3447,7 +3451,8 @@ get_out:
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
block_info& info = i->info[block.block_index];
block_info* binfo = blocks_for_piece(*i);
block_info& info = binfo[block.block_index];
if (info.state == block_info::state_finished) return;
@ -3521,7 +3526,8 @@ get_out:
if (prio >= 0 && !m_dirty) update(prio, p.index);
dlpiece_iter dp = add_download_piece(block.piece_index);
block_info& info = dp->info[block.block_index];
block_info* binfo = blocks_for_piece(*dp);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
TORRENT_ASSERT(info.piece_index == block.piece_index);
@ -3542,9 +3548,8 @@ get_out:
std::vector<downloading_piece>::iterator i = find_dl_piece(p.download_queue()
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[p.download_queue()].end());
block_info& info = i->info[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
block_info* binfo = blocks_for_piece(*i);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(info.piece_index == block.piece_index);
if (info.state == block_info::state_finished) return;
@ -3625,12 +3630,12 @@ get_out:
std::vector<downloading_piece>::const_iterator i
= find_dl_piece(state, index);
TORRENT_ASSERT(i != m_downloads[state].end());
TORRENT_ASSERT(i->info >= &m_block_info[0]
&& i->info < &m_block_info[0] + m_block_info.size());
block_info const* binfo = blocks_for_piece(*i);
for (int j = 0; j != num_blocks; ++j)
{
TORRENT_ASSERT(i->info[j].peer == 0 || static_cast<torrent_peer*>(i->info[j].peer)->in_use);
d.push_back(i->info[j].peer);
TORRENT_ASSERT(binfo[j].peer == 0
|| static_cast<torrent_peer*>(binfo[j].peer)->in_use);
d.push_back(binfo[j].peer);
}
}
@ -3643,11 +3648,12 @@ get_out:
, block.piece_index);
TORRENT_ASSERT(block.block_index != piece_block::invalid.block_index);
TORRENT_ASSERT(i->info[block.block_index].piece_index == block.piece_index);
if (i->info[block.block_index].state == block_info::state_none)
block_info const* binfo = blocks_for_piece(*i);
TORRENT_ASSERT(binfo[block.block_index].piece_index == block.piece_index);
if (binfo[block.block_index].state == block_info::state_none)
return 0;
void* peer = i->info[block.block_index].peer;
void* peer = binfo[block.block_index].peer;
TORRENT_ASSERT(peer == 0 || static_cast<torrent_peer*>(peer)->in_use);
return peer;
}
@ -3677,9 +3683,8 @@ get_out:
, block.piece_index);
TORRENT_ASSERT(i != m_downloads[state].end());
block_info& info = i->info[block.block_index];
TORRENT_ASSERT(&info >= &m_block_info[0]);
TORRENT_ASSERT(&info < &m_block_info[0] + m_block_info.size());
block_info* binfo = blocks_for_piece(*i);
block_info& info = binfo[block.block_index];
TORRENT_ASSERT(info.peer == 0 || static_cast<torrent_peer*>(info.peer)->in_use);
TORRENT_ASSERT(info.piece_index == block.piece_index);

View File

@ -3739,19 +3739,20 @@ namespace libtorrent
}
#endif
piece_picker::block_info* info = m_picker->blocks_for_piece(*i);
for (int j = 0; j < blocks_per_piece; ++j)
{
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j))
== (i->info[j].state == piece_picker::block_info::state_finished));
== (info[j].state == piece_picker::block_info::state_finished));
#endif
if (i->info[j].state == piece_picker::block_info::state_finished)
if (info[j].state == piece_picker::block_info::state_finished)
{
corr += block_bytes_wanted(piece_block(index, j));
}
TORRENT_ASSERT(corr >= 0);
TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
|| i->info[j].state != piece_picker::block_info::state_finished);
|| info[j].state != piece_picker::block_info::state_finished);
}
st.total_done += corr;
@ -3820,9 +3821,11 @@ namespace libtorrent
dl_queue.begin(); i != dl_queue.end(); ++i)
{
fprintf(stderr, " %d ", i->index);
piece_picker::block_info* info = m_picker->blocks_for_piece(*i);
for (int j = 0; j < blocks_per_piece; ++j)
{
char const* state = i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0";
char const* state = info[j].state
== piece_picker::block_info::state_finished ? "1" : "0";
fputs(state, stderr);
}
fputs("\n", stderr);
@ -6846,12 +6849,13 @@ namespace libtorrent
const int num_bitmask_bytes
= (std::max)(num_blocks_per_piece / 8, 1);
piece_picker::block_info const* info = m_picker->blocks_for_piece(*i);
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char v = 0;
int bits = (std::min)(num_blocks_per_piece - j*8, 8);
for (int k = 0; k < bits; ++k)
v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
v |= (info[j*8+k].state == piece_picker::block_info::state_finished)
? (1 << k) : 0;
bitmask.append(1, v);
TORRENT_ASSERT(bits == 8 || j == num_bitmask_bytes - 1);
@ -7126,7 +7130,7 @@ namespace libtorrent
}
}
void torrent::get_download_queue(std::vector<partial_piece_info>* queue)
void torrent::get_download_queue(std::vector<partial_piece_info>* queue) const
{
TORRENT_ASSERT(is_single_thread());
queue->clear();
@ -7159,22 +7163,23 @@ namespace libtorrent
TORRENT_ASSERT(counter * blocks_per_piece + pi.blocks_in_piece <= int(blk.size()));
pi.blocks = &blk[counter * blocks_per_piece];
int piece_size = int(torrent_file().piece_size(i->index));
piece_picker::block_info const* info = m_picker->blocks_for_piece(*i);
for (int j = 0; j < pi.blocks_in_piece; ++j)
{
block_info& bi = pi.blocks[j];
bi.state = i->info[j].state;
bi.state = info[j].state;
bi.block_size = j < pi.blocks_in_piece - 1 ? block_size()
: piece_size - (j * block_size());
bool complete = bi.state == block_info::writing
|| bi.state == block_info::finished;
if (i->info[j].peer == 0)
if (info[j].peer == 0)
{
bi.set_peer(tcp::endpoint());
bi.bytes_progress = complete ? bi.block_size : 0;
}
else
{
torrent_peer* p = static_cast<torrent_peer*>(i->info[j].peer);
torrent_peer* p = static_cast<torrent_peer*>(info[j].peer);
TORRENT_ASSERT(p->in_use);
if (p->connection)
{
@ -7207,7 +7212,7 @@ namespace libtorrent
}
}
pi.blocks[j].num_peers = i->info[j].num_peers;
pi.blocks[j].num_peers = info[j].num_peers;
}
pi.piece_index = i->index;
queue->push_back(pi);
@ -10134,7 +10139,9 @@ namespace libtorrent
bool operator<(busy_block_t rhs) const { return peers < rhs.peers; }
};
void pick_busy_blocks(int piece, int blocks_in_piece
void pick_busy_blocks(piece_picker const* picker
, int piece
, int blocks_in_piece
, int timed_out
, std::vector<piece_block>& interesting_blocks
, piece_picker::downloading_piece const& pi)
@ -10149,27 +10156,29 @@ namespace libtorrent
= TORRENT_ALLOCA(busy_block_t, blocks_in_piece);
int busy_count = 0;
piece_picker::block_info const* info = picker->blocks_for_piece(pi);
// pick busy blocks from the piece
for (int k = 0; k < blocks_in_piece; ++k)
{
// only consider blocks that have been requested
// and we're still waiting for them
if (pi.info[k].state != piece_picker::block_info::state_requested)
if (info[k].state != piece_picker::block_info::state_requested)
continue;
piece_block b(piece, k);
// only allow a single additional request per block, in order
// to spread it out evenly across all stalled blocks
if (pi.info[k].num_peers > timed_out)
if (info[k].num_peers > timed_out)
continue;
busy_blocks[busy_count].peers = pi.info[k].num_peers;
busy_blocks[busy_count].peers = info[k].num_peers;
busy_blocks[busy_count].index = k;
++busy_count;
#if TORRENT_DEBUG_STREAMING > 1
printf(" [%d (%d)]", b.block_index, pi.info[k].num_peers);
printf(" [%d (%d)]", b.block_index, info[k].num_peers);
#endif
}
#if TORRENT_DEBUG_STREAMING > 1
@ -10194,7 +10203,7 @@ namespace libtorrent
, std::set<peer_connection*>& peers_with_requests
, piece_picker::downloading_piece const& pi
, time_critical_piece* i
, piece_picker* picker
, piece_picker const* picker
, int blocks_in_piece
, int timed_out)
{
@ -10275,7 +10284,7 @@ namespace libtorrent
printf("pick busy blocks\n");
#endif
pick_busy_blocks(i->piece, blocks_in_piece, timed_out
pick_busy_blocks(picker, i->piece, blocks_in_piece, timed_out
, interesting_blocks, pi);
}
@ -11045,7 +11054,7 @@ namespace libtorrent
boost::int64_t offset = boost::int64_t(i->index) * m_torrent_file->piece_length();
int file = fs.file_index_at_offset(offset);
int num_blocks = m_picker->blocks_in_piece(i->index);
piece_picker::block_info const* info = i->info;
piece_picker::block_info const* info = m_picker->blocks_for_piece(*i);
for (int k = 0; k < num_blocks; ++k)
{
TORRENT_ASSERT(file < fs.num_files());