diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index bedddc1c0..d3520cdf2 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -92,12 +92,14 @@ namespace libtorrent struct block_info { - block_info(): num_downloads(0) {} + block_info(): num_downloads(0), requested(0), finished(0) {} // the peer this block was requested or // downloaded from tcp::endpoint peer; // the number of times this block has been downloaded - int num_downloads; + unsigned num_downloads:14; + unsigned requested:1; + unsigned finished:1; }; // the peers that are downloading this piece @@ -109,17 +111,15 @@ namespace libtorrent struct downloading_piece { + downloading_piece(): finished(0), requested(0) {} piece_state_t state; // the index of the piece int index; - // each bit represents a block in the piece - // set to one if the block has been requested - std::bitset requested_blocks; - // the bit is set to one if the block has been acquired - std::bitset finished_blocks; // info about each block block_info info[max_blocks_per_piece]; + boost::uint16_t finished; + boost::uint16_t requested; }; piece_picker(int blocks_per_piece diff --git a/include/libtorrent/storage.hpp b/include/libtorrent/storage.hpp index 7c6eeecd3..5bf8c3991 100755 --- a/include/libtorrent/storage.hpp +++ b/include/libtorrent/storage.hpp @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" +#include "libtorrent/piece_picker.hpp" #include "libtorrent/config.hpp" namespace libtorrent @@ -153,7 +154,7 @@ namespace libtorrent unsigned long piece_crc( int slot_index , int block_size - , const std::bitset<256>& bitmask); + , piece_picker::block_info const* bi); int slot_for_piece(int piece_index) const; size_type read( diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 33154ab7c..0d33acff9 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -995,7 +995,7 @@ namespace libtorrent for (std::vector::const_iterator i = dl_queue.begin(); i != dl_queue.end(); ++i) { - assert(int(i->finished_blocks.count()) < blocks_per_piece); + assert(i->finished < blocks_per_piece); } } } diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index bba6f0474..d8d157c59 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -117,7 +117,7 @@ namespace libtorrent tcp::endpoint peer; for (int j = 0; j < m_blocks_per_piece; ++j) { - if (i->finished_blocks[j]) + if (i->info[j].finished) mark_as_finished(piece_block(i->index, j), peer); } if (is_piece_finished(i->index)) @@ -210,20 +210,27 @@ namespace libtorrent { bool blocks_requested = false; int num_blocks = blocks_in_piece(i->index); + int num_requested = 0; + int num_finished = 0; for (int k = 0; k < num_blocks; ++k) { - if (i->finished_blocks[k]) + if (i->info[k].finished) { - assert(i->requested_blocks[k]); + ++num_finished; + assert(i->info[k].requested); + ++num_requested; continue; } - if (i->requested_blocks[k]) + if (i->info[k].requested) { + ++num_requested; blocks_requested = true; - break; } } assert(blocks_requested == (i->state != none)); + assert(num_requested == i->requested); + assert(num_finished == i->finished); + assert(num_finished <= num_requested); } @@ -1010,10 +1017,11 @@ namespace libtorrent { for (int j = 0; j < num_blocks_in_piece; ++j) { - if ((p.finished_blocks[j] == 1 - || p.requested_blocks[j] == 1) - && p.info[j].peer != peer - && p.info[j].peer != tcp::endpoint()) + piece_picker::block_info const& info = p.info[j]; + if ((info.finished == 1 + || info.requested == 1) + && info.peer != peer + && info.peer != tcp::endpoint()) { return false; } @@ -1065,9 +1073,10 @@ namespace libtorrent if (int(backup_blocks.size()) >= num_blocks) continue; for (int j = 0; j < num_blocks_in_piece; ++j) { - if (p->finished_blocks[j] == 1) continue; - if (p->requested_blocks[j] == 1 - && p->info[j].peer == peer) continue; + block_info const& info = p->info[j]; + if (info.finished) continue; + if (info.requested + && info.peer == peer) continue; backup_blocks.push_back(piece_block(*i, j)); } continue; @@ -1076,10 +1085,10 @@ namespace libtorrent for (int j = 0; j < num_blocks_in_piece; ++j) { // ignore completed blocks - if (p->finished_blocks[j] == 1) continue; + block_info const& info = p->info[j]; + if (info.finished) continue; // ignore blocks requested from this peer already - if (p->requested_blocks[j] == 1 - && p->info[j].peer == peer) continue; + if (info.requested && info.peer == peer) continue; // if the piece is fast and the peer is slow, or vice versa, // add the block as a backup. // override this behavior if all the other blocks @@ -1102,7 +1111,7 @@ namespace libtorrent // blocks that have not been requested from any // other peer. interesting_blocks.push_back(piece_block(*i, j)); - if (p->requested_blocks[j] == 0) + if (p->info[j].requested == 0) { // we have found a block that's free to download num_blocks--; @@ -1146,11 +1155,11 @@ namespace libtorrent std::vector::const_iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index)); assert(i != m_downloads.end()); - assert((int)i->finished_blocks.count() <= m_blocks_per_piece); + assert((int)i->finished <= m_blocks_per_piece); int max_blocks = blocks_in_piece(index); - if ((int)i->finished_blocks.count() < max_blocks) return false; + if ((int)i->finished < max_blocks) return false; - assert((int)i->requested_blocks.count() == max_blocks); + assert((int)i->requested == max_blocks); return true; } @@ -1169,7 +1178,7 @@ namespace libtorrent , has_index(block.piece_index)); assert(i != m_downloads.end()); - return i->requested_blocks[block.block_index]; + return i->info[block.block_index].requested; } bool piece_picker::is_finished(piece_block block) const @@ -1184,7 +1193,7 @@ namespace libtorrent std::vector::const_iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); - return i->finished_blocks[block.block_index]; + return i->info[block.block_index].finished; } @@ -1208,8 +1217,10 @@ namespace libtorrent downloading_piece dp; dp.state = state; dp.index = block.piece_index; - dp.requested_blocks[block.block_index] = 1; - dp.info[block.block_index].peer = peer; + block_info& info = dp.info[block.block_index]; + info.requested = 1; + info.peer = peer; + ++dp.requested; m_downloads.push_back(dp); } else @@ -1217,9 +1228,11 @@ namespace libtorrent std::vector::iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); - assert(i->requested_blocks[block.block_index] == 0); - i->info[block.block_index].peer = peer; - i->requested_blocks[block.block_index] = 1; + block_info& info = i->info[block.block_index]; + assert(info.requested == 0); + info.peer = peer; + info.requested = 1; + ++i->requested; if (i->state == none) i->state = state; } } @@ -1245,8 +1258,11 @@ namespace libtorrent downloading_piece dp; dp.state = none; dp.index = block.piece_index; - dp.requested_blocks[block.block_index] = 1; - dp.finished_blocks[block.block_index] = 1; + block_info& info = dp.info[block.block_index]; + info.requested = 1; + info.finished = 1; + ++dp.requested; + ++dp.finished; dp.info[block.block_index].peer = peer; m_downloads.push_back(dp); } @@ -1255,25 +1271,14 @@ namespace libtorrent std::vector::iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); - i->info[block.block_index].peer = peer; - i->requested_blocks[block.block_index] = 1; - i->finished_blocks[block.block_index] = 1; + block_info& info = i->info[block.block_index]; + info.peer = peer; + if (!info.requested) ++i->requested; + info.requested = 1; + if (!info.finished) ++i->finished; + info.finished = 1; - // TODO: maintain requested and finished counters so that - // we don't have to count every time - bool blocks_requested = false; - int num_blocks = blocks_in_piece(i->index); - for (int k = 0; k < num_blocks; ++k) - { - if (i->finished_blocks[k]) continue; - if (i->requested_blocks[k]) - { - blocks_requested = true; - break; - } - } - - if (!blocks_requested) + if (i->requested == i->finished) { // there are no blocks requested in this piece. // remove the fast/slow state from it @@ -1309,8 +1314,8 @@ namespace libtorrent assert(block.block_index < max_blocks_per_piece); assert(block.block_index >= 0); - if (i->requested_blocks[block.block_index] == false - || i->finished_blocks[block.block_index] == true) + if (i->info[block.block_index].requested == false + || i->info[block.block_index].requested == true) return boost::optional(); return boost::optional(i->info[block.block_index].peer); @@ -1336,26 +1341,27 @@ namespace libtorrent , m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); - if (i->finished_blocks[block.block_index]) + if (i->info[block.block_index].finished) { - assert(i->requested_blocks[block.block_index]); + 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; } assert(block.block_index < blocks_in_piece(block.piece_index)); - assert(i->requested_blocks[block.block_index]); + assert(i->info[block.block_index].requested); // clear this block as being downloaded - i->requested_blocks[block.block_index] = false; + i->info[block.block_index].requested = false; + --i->requested; // clear the downloader of this block i->info[block.block_index].peer = tcp::endpoint(); // if there are no other blocks in this piece // that's being downloaded, remove it from the list - if (i->requested_blocks.count() == 0) + if (i->requested == 0) { m_downloads.erase(i); piece_pos& p = m_piece_map[block.piece_index]; @@ -1366,28 +1372,11 @@ namespace libtorrent assert(std::find_if(m_downloads.begin(), m_downloads.end() , has_index(block.piece_index)) == m_downloads.end()); } - else + else if (i->requested == i->finished) { - // TODO: maintain requested and finished counters so that - // we don't have to count every time - bool blocks_requested = false; - int num_blocks = blocks_in_piece(i->index); - for (int k = 0; k < num_blocks; ++k) - { - if (i->finished_blocks[k]) continue; - if (i->requested_blocks[k]) - { - blocks_requested = true; - break; - } - } - - if (!blocks_requested) - { - // there are no blocks requested in this piece. - // remove the fast/slow state from it - i->state = none; - } + // there are no blocks requested in this piece. + // remove the fast/slow state from it + i->state = none; } } @@ -1397,7 +1386,7 @@ namespace libtorrent for (std::vector::const_iterator i = m_downloads.begin(); i != m_downloads.end(); ++i) { - counter += (int)i->finished_blocks.count(); + counter += (int)i->finished; } return counter; } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 253ddfa6f..11b2ce8aa 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1906,11 +1906,14 @@ namespace libtorrent { namespace detail { const int bit = j * 8 + k; if (bits & (1 << k)) - p.finished_blocks[bit] = true; + { + p.info[bit].finished = true; + ++p.finished; + } } } - if (p.finished_blocks.count() == 0) continue; + if (p.finished == 0) continue; std::vector::iterator slot_iter = std::find(tmp_pieces.begin(), tmp_pieces.end(), p.index); @@ -1929,7 +1932,7 @@ namespace libtorrent { namespace detail = torrent_ptr->filesystem().piece_crc( slot_index , torrent_ptr->block_size() - , p.finished_blocks); + , p.info); const entry& ad = (*i)["adler32"]; diff --git a/src/storage.cpp b/src/storage.cpp index 4aa4b014c..8e7ec6713 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -959,7 +959,7 @@ namespace libtorrent unsigned long piece_crc( int slot_index , int block_size - , const std::bitset<256>& bitmask); + , piece_picker::block_info const* bi); int slot_for_piece(int piece_index) const; @@ -1208,15 +1208,15 @@ namespace libtorrent unsigned long piece_manager::piece_crc( int index , int block_size - , const std::bitset<256>& bitmask) + , piece_picker::block_info const* bi) { - return m_pimpl->piece_crc(index, block_size, bitmask); + return m_pimpl->piece_crc(index, block_size, bi); } unsigned long piece_manager::impl::piece_crc( int slot_index , int block_size - , const std::bitset<256>& bitmask) + , piece_picker::block_info const* bi) { assert(slot_index >= 0); assert(slot_index < m_info.num_pieces()); @@ -1230,7 +1230,7 @@ namespace libtorrent for (int i = 0; i < num_blocks-1; ++i) { - if (!bitmask[i]) continue; + if (!bi[i].finished) continue; m_storage->read( &buf[0] , slot_index @@ -1238,7 +1238,7 @@ namespace libtorrent , block_size); crc.update(&buf[0], block_size); } - if (bitmask[num_blocks - 1]) + if (bi[num_blocks - 1].finished) { m_storage->read( &buf[0] @@ -1260,7 +1260,8 @@ namespace libtorrent assert(offset >= 0); assert(size > 0); assert(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size()); - assert(m_piece_to_slot[piece_index] >= 0 && m_piece_to_slot[piece_index] < (int)m_slot_to_piece.size()); + assert(m_piece_to_slot[piece_index] >= 0 + && m_piece_to_slot[piece_index] < (int)m_slot_to_piece.size()); int slot = m_piece_to_slot[piece_index]; assert(slot >= 0 && slot < (int)m_slot_to_piece.size()); return m_storage->read(buf, slot, offset, size); diff --git a/src/torrent.cpp b/src/torrent.cpp index ebc2d9f67..ebadd35a7 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -738,8 +738,7 @@ namespace libtorrent int corr = 0; int index = i->index; assert(!m_have_pieces[index]); - assert(int(i->finished_blocks.count()) - < m_picker->blocks_in_piece(index)); + assert(i->finished < m_picker->blocks_in_piece(index)); #ifndef NDEBUG for (std::vector::const_iterator j = boost::next(i); @@ -751,17 +750,17 @@ namespace libtorrent for (int j = 0; j < blocks_per_piece; ++j) { - assert(i->finished_blocks[j] == 0 || i->finished_blocks[j] == 1); - assert(m_picker->is_finished(piece_block(index, j)) == i->finished_blocks[j]); - corr += i->finished_blocks[j] * m_block_size; + assert(i->info[j].finished == 0 || i->info[j].finished == 1); + assert(m_picker->is_finished(piece_block(index, j)) == i->info[j].finished); + corr += i->info[j].finished * m_block_size; assert(index != last_piece || j < m_picker->blocks_in_last_piece() - || i->finished_blocks[j] == 0); + || i->info[j].finished == 0); } // correction if this was the last piece // and if we have the last block if (i->index == last_piece - && i->finished_blocks[m_picker->blocks_in_last_piece()-1]) + && i->info[m_picker->blocks_in_last_piece()-1].finished) { corr -= m_block_size; corr += m_torrent_file.piece_size(last_piece) % m_block_size; @@ -836,7 +835,7 @@ namespace libtorrent std::cerr << " " << i->index << " "; for (int j = 0; j < blocks_per_piece; ++j) { - std::cerr << i->finished_blocks[j]; + std::cerr << i->info[j].finished; } std::cerr << std::endl; } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index dfdccf86e..4e8dff66c 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -542,7 +542,7 @@ namespace libtorrent for (std::vector::const_iterator i = q.begin(); i != q.end(); ++i) { - if (i->finished_blocks.count() == 0) continue; + if (i->finished == 0) continue; entry piece_struct(entry::dictionary_t); @@ -557,7 +557,7 @@ namespace libtorrent { unsigned char v = 0; for (int k = 0; k < 8; ++k) - v |= i->finished_blocks[j*8+k]?(1 << k):0; + v |= i->info[j*8+k].finished?(1 << k):0; bitmask.insert(bitmask.end(), v); } piece_struct["bitmask"] = bitmask; @@ -567,7 +567,7 @@ namespace libtorrent = t->filesystem().piece_crc( t->filesystem().slot_for_piece(i->index) , t->block_size() - , i->finished_blocks); + , i->info); piece_struct["adler32"] = adler; @@ -769,12 +769,12 @@ namespace libtorrent { partial_piece_info pi; pi.piece_state = (partial_piece_info::state_t)i->state; - pi.finished_blocks = i->finished_blocks; - pi.requested_blocks = i->requested_blocks; for (int j = 0; j < partial_piece_info::max_blocks_per_piece; ++j) { pi.peer[j] = i->info[j].peer; pi.num_downloads[j] = i->info[j].num_downloads; + pi.finished_blocks[j] = i->info[j].finished; + pi.requested_blocks[j] = i->info[j].requested; } pi.piece_index = i->index; pi.blocks_in_piece = p.blocks_in_piece(i->index);