From 2fdb7499fa6a0db7cceef13453c6fb813010af5a Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 14 Feb 2015 21:32:41 +0000 Subject: [PATCH] optimize block_info allocation and downloading_piece size in piece_picker --- include/libtorrent/piece_picker.hpp | 43 ++-- include/libtorrent/torrent.hpp | 7 +- src/peer_connection.cpp | 4 +- src/piece_picker.cpp | 353 ++++++++++++++-------------- src/torrent.cpp | 45 ++-- 5 files changed, 244 insertions(+), 208 deletions(-) diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 634052391..1b0bc73d6 100644 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #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 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 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 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 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 m_free_block_infos; + boost::uint16_t m_blocks_per_piece; boost::uint16_t m_blocks_in_last_piece; diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index acf6cac23..5e80e1cc2 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -679,7 +679,7 @@ namespace libtorrent void get_full_peer_list(std::vector& v) const; void get_peer_info(std::vector& v); - void get_download_queue(std::vector* queue); + void get_download_queue(std::vector* 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 { diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 446c0e8d7..fe2b14942 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -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 diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 2cb11e7b0..fd7b91319 100644 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -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::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::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(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(p->connection)->m_in_use); + TORRENT_ASSERT(p->connection == NULL + || static_cast(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(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(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(i->info[k].peer)->in_use); + TORRENT_ASSERT(info[k].piece_index == i->index); + TORRENT_ASSERT(info[k].peer == 0 + || static_cast(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::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(info.peer)->in_use); + block_info const& info = binfo[j]; + TORRENT_ASSERT(info.peer == 0 + || static_cast(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::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 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 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(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(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::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::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::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::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::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::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::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(i->info[j].peer)->in_use); - d.push_back(i->info[j].peer); + TORRENT_ASSERT(binfo[j].peer == 0 + || static_cast(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(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(info.peer)->in_use); TORRENT_ASSERT(info.piece_index == block.piece_index); diff --git a/src/torrent.cpp b/src/torrent.cpp index 221b1a567..e5c01ca55 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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* queue) + void torrent::get_download_queue(std::vector* 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(i->info[j].peer); + torrent_peer* p = static_cast(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& 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& 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());