diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index d3520cdf2..6ef1041e9 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -88,8 +88,6 @@ namespace libtorrent { public: - enum { max_blocks_per_piece = 256 }; - struct block_info { block_info(): num_downloads(0), requested(0), finished(0) {} @@ -117,7 +115,9 @@ namespace libtorrent // the index of the piece int index; // info about each block - block_info info[max_blocks_per_piece]; + // this is a pointer into the m_block_info + // vector owned by the piece_picker + block_info* info; boost::uint16_t finished; boost::uint16_t requested; }; @@ -339,6 +339,9 @@ namespace libtorrent , int num_blocks, bool prefer_whole_pieces , tcp::endpoint peer, piece_state_t speed) const; + downloading_piece& add_download_piece(); + void erase_download_piece(std::vector::iterator i); + // this vector contains all pieces we don't have. // in the first entry (index 0) is a vector of all pieces // that no peer have, the vector at index 1 contains @@ -363,6 +366,15 @@ namespace libtorrent // is being downloaded std::vector m_downloads; + // this holds the information of the + // blocks in partially downloaded pieces. + // the first m_blocks_per_piece entries + // in the vector belongs to the first + // entry in m_downloads, the second + // m_blocks_per_piece entries to the + // second entry in m_downloads and so on. + std::vector m_block_info; + int m_blocks_per_piece; int m_blocks_in_last_piece; diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 1edd06cf8..bd22f0e9b 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -204,7 +204,7 @@ namespace libtorrent struct TORRENT_EXPORT partial_piece_info { - enum { max_blocks_per_piece = piece_picker::max_blocks_per_piece }; + enum { max_blocks_per_piece = 256 }; int piece_index; int blocks_in_piece; std::bitset requested_blocks; diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index d8d157c59..5d8f15bf9 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -76,9 +76,7 @@ namespace libtorrent m_blocks_in_last_piece = total_num_blocks % blocks_per_piece; if (m_blocks_in_last_piece == 0) m_blocks_in_last_piece = blocks_per_piece; - assert(m_blocks_per_piece <= max_blocks_per_piece); assert(m_blocks_in_last_piece <= m_blocks_per_piece); - assert(m_blocks_in_last_piece <= max_blocks_per_piece); // allocate the piece_map to cover all pieces // and make them invalid (as if though we already had every piece) @@ -191,6 +189,51 @@ namespace libtorrent } } + piece_picker::downloading_piece& piece_picker::add_download_piece() + { + int num_downloads = m_downloads.size(); + int block_index = num_downloads * m_blocks_per_piece; + if (int(m_block_info.size()) < block_index + m_blocks_per_piece) + { + m_block_info.resize(block_index + m_blocks_per_piece); + if (!m_downloads.empty() && &m_block_info[0] != m_downloads.front().info) + { + // this means the memory was reallocated, update the pointers + for (int i = 0; i < int(m_downloads.size()); ++i) + m_downloads[i].info = &m_block_info[i * m_blocks_per_piece]; + } + } + m_downloads.push_back(downloading_piece()); + downloading_piece& ret = m_downloads.back(); + ret.info = &m_block_info[block_index]; + for (int i = 0; i < m_blocks_per_piece; ++i) + { + ret.info[i].num_downloads = 0; + ret.info[i].requested = 0; + ret.info[i].finished = 0; + ret.info[i].peer = tcp::endpoint(); + } + return ret; + } + + void piece_picker::erase_download_piece(std::vector::iterator i) + { + if (i != m_downloads.end() - 1) + { + int remove_index = i - m_downloads.begin(); + int last_index = m_downloads.size() - 1; + assert(remove_index < last_index); + + assert(int(m_block_info.size()) >= last_index * m_blocks_per_piece + m_blocks_per_piece); + std::copy(m_block_info.begin() + (last_index * m_blocks_per_piece) + , m_block_info.begin() + (last_index * m_blocks_per_piece + m_blocks_per_piece) + , m_block_info.begin() + (remove_index * m_blocks_per_piece)); + m_downloads[remove_index] = m_downloads[last_index]; + m_downloads[remove_index].info = &m_block_info[remove_index * m_blocks_per_piece]; + } + + m_downloads.pop_back(); + } #ifndef NDEBUG void piece_picker::check_invariant(const torrent* t) const @@ -557,7 +600,7 @@ namespace libtorrent m_downloads.end(), has_index(index)); assert(i != m_downloads.end()); - m_downloads.erase(i); + erase_download_piece(i); piece_pos& p = m_piece_map[index]; int prev_priority = p.priority(m_sequenced_download_threshold); @@ -841,7 +884,7 @@ namespace libtorrent , m_downloads.end() , has_index(index)); assert(i != m_downloads.end()); - m_downloads.erase(i); + erase_download_piece(i); p.downloading = 0; assert(std::find_if(m_downloads.begin(), m_downloads.end() @@ -1168,7 +1211,6 @@ namespace libtorrent assert(block.piece_index >= 0); assert(block.block_index >= 0); assert(block.piece_index < (int)m_piece_map.size()); - assert(block.block_index < (int)max_blocks_per_piece); if (m_piece_map[block.piece_index].downloading == 0) return false; std::vector::const_iterator i @@ -1186,7 +1228,6 @@ namespace libtorrent assert(block.piece_index >= 0); assert(block.block_index >= 0); assert(block.piece_index < (int)m_piece_map.size()); - assert(block.block_index < (int)max_blocks_per_piece); if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true; if (m_piece_map[block.piece_index].downloading == 0) return false; @@ -1214,14 +1255,13 @@ namespace libtorrent p.downloading = 1; move(prio, p.index); - downloading_piece dp; + downloading_piece& dp = add_download_piece(); dp.state = state; dp.index = block.piece_index; block_info& info = dp.info[block.block_index]; info.requested = 1; info.peer = peer; ++dp.requested; - m_downloads.push_back(dp); } else { @@ -1255,7 +1295,7 @@ namespace libtorrent if (prio > 0) move(prio, p.index); else assert(p.priority(m_sequenced_download_threshold) == 0); - downloading_piece dp; + downloading_piece& dp = add_download_piece(); dp.state = none; dp.index = block.piece_index; block_info& info = dp.info[block.block_index]; @@ -1264,7 +1304,6 @@ namespace libtorrent ++dp.requested; ++dp.finished; dp.info[block.block_index].peer = peer; - m_downloads.push_back(dp); } else { @@ -1311,7 +1350,6 @@ namespace libtorrent if (i == m_downloads.end()) return boost::optional(); - assert(block.block_index < max_blocks_per_piece); assert(block.block_index >= 0); if (i->info[block.block_index].requested == false @@ -1344,8 +1382,6 @@ namespace libtorrent if (i->info[block.block_index].finished) { assert(i->info[block.block_index].requested); - assert(std::find_if(m_downloads.begin(), m_downloads.end() - , has_index(block.piece_index)) == m_downloads.end()); return; } @@ -1363,7 +1399,7 @@ namespace libtorrent // that's being downloaded, remove it from the list if (i->requested == 0) { - m_downloads.erase(i); + erase_download_piece(i); piece_pos& p = m_piece_map[block.piece_index]; int prio = p.priority(m_sequenced_download_threshold); p.downloading = 0; diff --git a/src/torrent.cpp b/src/torrent.cpp index ebadd35a7..d99fccc9d 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -105,12 +105,6 @@ namespace return static_cast(i.piece_length()); } - // if pieces are too large, adjust the block size - if (i.piece_length() / default_block_size > piece_picker::max_blocks_per_piece) - { - return static_cast(i.piece_length() / piece_picker::max_blocks_per_piece); - } - // otherwise, go with the default return default_block_size; } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 4e8dff66c..7b9567eb0 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -769,7 +769,8 @@ namespace libtorrent { partial_piece_info pi; pi.piece_state = (partial_piece_info::state_t)i->state; - for (int j = 0; j < partial_piece_info::max_blocks_per_piece; ++j) + pi.blocks_in_piece = p.blocks_in_piece(i->index); + for (int j = 0; j < pi.blocks_in_piece; ++j) { pi.peer[j] = i->info[j].peer; pi.num_downloads[j] = i->info[j].num_downloads; @@ -777,7 +778,6 @@ namespace libtorrent pi.requested_blocks[j] = i->info[j].requested; } pi.piece_index = i->index; - pi.blocks_in_piece = p.blocks_in_piece(i->index); queue.push_back(pi); } }