diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 336cb66b0..e3949fc51 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -242,6 +242,7 @@ namespace libtorrent , piece_state_t s); void mark_as_writing(piece_block block, void* peer); void mark_as_finished(piece_block block, void* peer); + void write_failed(piece_block block); int num_peers(piece_block block) const; // returns information about the given piece diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 090239a48..64506e0eb 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1476,7 +1476,7 @@ namespace libtorrent if (ret == -1 || !t) { - if (t->has_picker()) t->picker().abort_download(block_finished); + if (t->has_picker()) t->picker().write_failed(block_finished); if (!t) { diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index a5794b25f..bce355b34 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #endif //#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK +//#define TORRENT_NO_EXPENSIVE_INVARIANT_CHECK #define TORRENT_PIECE_PICKER_INVARIANT_CHECK //#define TORRENT_PICKER_LOG @@ -276,7 +277,7 @@ namespace libtorrent TORRENT_ASSERT(p == prio); } } -#ifndef NDEBUG + void piece_picker::print_pieces() const { for (std::vector::const_iterator i = m_priority_boundries.begin() @@ -300,32 +301,9 @@ namespace libtorrent } std::cout << std::endl; } -#endif + void piece_picker::check_invariant(const torrent* t) const { - if (m_sequential_download == -1 && !m_dirty) - { - TORRENT_ASSERT(!m_priority_boundries.empty()); - int prio = 0; - int start = 0; - for (std::vector::const_iterator i = m_priority_boundries.begin() - , end(m_priority_boundries.end()); i != end; ++i) - { - verify_priority(start, *i, prio); - ++prio; - start = *i; - } - TORRENT_ASSERT(m_priority_boundries.back() == int(m_pieces.size())); - } - else if (m_sequential_download >= 0) - { - int index = 0; - for (std::vector::const_iterator i = m_piece_map.begin() - , end(m_piece_map.end()); i != end && (i->have() || i->filtered()); - ++i, ++index); - TORRENT_ASSERT(m_sequential_download == index); - } - TORRENT_ASSERT(sizeof(piece_pos) == 4); TORRENT_ASSERT(m_num_have >= 0); TORRENT_ASSERT(m_num_have_filtered >= 0); @@ -358,17 +336,18 @@ namespace libtorrent if (i->info[k].state == block_info::state_finished) { ++num_finished; - continue; + TORRENT_ASSERT(i->info[k].num_peers == 0); } - if (i->info[k].state == block_info::state_requested) + else if (i->info[k].state == block_info::state_requested) { ++num_requested; blocks_requested = true; TORRENT_ASSERT(i->info[k].num_peers > 0); } - if (i->info[k].state == block_info::state_writing) + else if (i->info[k].state == block_info::state_writing) { ++num_writing; + TORRENT_ASSERT(i->info[k].num_peers == 0); } } TORRENT_ASSERT(blocks_requested == (i->state != none)); @@ -376,7 +355,32 @@ namespace libtorrent TORRENT_ASSERT(num_writing == i->writing); TORRENT_ASSERT(num_finished == i->finished); } +#ifdef TORRENT_NO_EXPENSIVE_INVARIANT_CHECK + return; +#endif + if (m_sequential_download == -1 && !m_dirty) + { + TORRENT_ASSERT(!m_priority_boundries.empty()); + int prio = 0; + int start = 0; + for (std::vector::const_iterator i = m_priority_boundries.begin() + , end(m_priority_boundries.end()); i != end; ++i) + { + verify_priority(start, *i, prio); + ++prio; + start = *i; + } + TORRENT_ASSERT(m_priority_boundries.back() == int(m_pieces.size())); + } + else if (m_sequential_download >= 0) + { + int index = 0; + for (std::vector::const_iterator i = m_piece_map.begin() + , end(m_piece_map.end()); i != end && (i->have() || i->filtered()); + ++i, ++index); + TORRENT_ASSERT(m_sequential_download == index); + } int num_filtered = 0; int num_have_filtered = 0; @@ -807,9 +811,9 @@ namespace libtorrent TORRENT_ASSERT(m_piece_map[index].downloading == 1); std::vector::iterator i - = std::find_if(m_downloads.begin(), - m_downloads.end(), - has_index(index)); + = std::find_if(m_downloads.begin(), m_downloads.end() + , has_index(index)); + TORRENT_ASSERT(i != m_downloads.end()); erase_download_piece(i); @@ -1814,7 +1818,8 @@ namespace libtorrent TORRENT_ASSERT(info.state != block_info::state_writing); ++i->writing; info.state = block_info::state_writing; - if (info.num_peers > 0) --info.num_peers; + TORRENT_ASSERT(info.num_peers > 0); + info.num_peers = 0; if (i->requested == 0) { @@ -1824,6 +1829,31 @@ namespace libtorrent } sort_piece(i); } + + void piece_picker::write_failed(piece_block block) + { + TORRENT_PIECE_PICKER_INVARIANT_CHECK; + + std::vector::iterator i + = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); + TORRENT_ASSERT(i != m_downloads.end()); + block_info& info = i->info[block.block_index]; + TORRENT_ASSERT(info.state == block_info::state_writing); + + --i->writing; + if (info.num_peers > 0) + { + // there are other peers on this block + // turn it back into requested + ++i->requested; + info.state = block_info::state_requested; + } + else + { + info.state = block_info::state_none; + } + info.peer = 0; + } void piece_picker::mark_as_finished(piece_block block, void* peer) { @@ -1851,6 +1881,7 @@ namespace libtorrent block_info& info = dp.info[block.block_index]; info.peer = peer; TORRENT_ASSERT(info.state == block_info::state_none); + TORRENT_ASSERT(info.num_peers == 0); if (info.state != block_info::state_finished) { ++dp.finished; @@ -1866,6 +1897,7 @@ namespace libtorrent = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); TORRENT_ASSERT(i != m_downloads.end()); block_info& info = i->info[block.block_index]; + TORRENT_ASSERT(info.num_peers == 0); info.peer = peer; TORRENT_ASSERT(info.state == block_info::state_writing || peer == 0); @@ -1936,25 +1968,35 @@ namespace libtorrent TORRENT_ASSERT(i != m_downloads.end()); block_info& info = i->info[block.block_index]; - --info.num_peers; - if (info.num_peers > 0) return; - if (i->info[block.block_index].state == block_info::state_finished - || i->info[block.block_index].state == block_info::state_writing) + TORRENT_ASSERT(info.state == block_info::state_requested); + TORRENT_ASSERT(info.num_peers > 0); + + --info.num_peers; + TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index)); + + // if there are other peers + if (info.num_peers > 0) { + if (i->info[block.block_index].state == block_info::state_writing) + { + ++i->requested; + --i->writing; + i->info[block.block_index].state = block_info::state_requested; + // since we just cleared the writing state, we know that + // the peer for this block was the one we canceled + info.peer = 0; + } return; } - TORRENT_ASSERT(block.block_index < blocks_in_piece(block.piece_index)); - TORRENT_ASSERT(i->info[block.block_index].state == block_info::state_requested); + // clear the downloader of this block + info.peer = 0; // clear this block as being downloaded info.state = block_info::state_none; --i->requested; - // clear the downloader of this block - info.peer = 0; - // if there are no other blocks in this piece // that's being downloaded, remove it from the list if (i->requested + i->finished + i->writing == 0) diff --git a/src/storage.cpp b/src/storage.cpp index 108c125bb..e874fcaf2 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1359,8 +1359,11 @@ namespace libtorrent std::map::iterator i = m_piece_hasher.find(piece_index); if (i != m_piece_hasher.end()) { +#ifndef NDEBUG TORRENT_ASSERT(i->second.offset > 0); - TORRENT_ASSERT(offset >= i->second.offset); + int hash_offset = i->second.offset; + TORRENT_ASSERT(offset >= hash_offset); +#endif if (offset == i->second.offset) { i->second.offset += size; diff --git a/src/torrent.cpp b/src/torrent.cpp index 6ae61f708..961f5ad7e 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -3069,6 +3069,16 @@ namespace libtorrent TORRENT_ASSERT(piece_index >= 0); TORRENT_ASSERT(piece_index < m_torrent_file->num_pieces()); TORRENT_ASSERT(piece_index < (int)m_have_pieces.size()); +#ifndef NDEBUG + if (m_picker) + { + int blocks_in_piece = m_picker->blocks_in_piece(piece_index); + for (int i = 0; i < blocks_in_piece; ++i) + { + TORRENT_ASSERT(m_picker->num_peers(piece_block(piece_index, i)) == 0); + } + } +#endif m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified , shared_from_this(), _1, _2, f));