From cc3b064cff34b90660d5cfa7aba38bdb2a6507ac Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 4 Dec 2015 01:08:01 -0500 Subject: [PATCH] fix graceful pause issue. peers regularly check whether they should disconnect or not --- include/libtorrent/peer_connection.hpp | 1 + src/peer_connection.cpp | 49 ++++++++++++++++---------- src/request_blocks.cpp | 3 ++ src/torrent.cpp | 8 ++--- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 0255bb57a..8b0303f70 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -813,6 +813,7 @@ namespace libtorrent , peer_request r, boost::shared_ptr t); void on_seed_mode_hashed(disk_io_job const* j); int request_timeout() const; + void check_graceful_pause(); int wanted_transfer(int channel); int request_bandwidth(int channel, int bytes = 0); diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 878cfab5e..6536fc1ec 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -1234,13 +1234,14 @@ namespace libtorrent } if (t->is_paused() + && t->is_auto_managed() && m_settings.get_bool(settings_pack::incoming_starts_queued_torrents) && !t->is_aborted()) { t->resume(); } - if (t->is_paused() || t->is_aborted()) + if (t->is_paused() || t->is_aborted() || t->graceful_pause()) { // paused torrents will not accept // incoming connections unless they are auto managed @@ -1510,6 +1511,9 @@ namespace libtorrent m_suggested_pieces.erase(i); } + check_graceful_pause(); + if (is_disconnecting()) return; + if (m_request_queue.empty() && m_download_queue.size() < 2) { if (request_a_block(*t, *this)) @@ -2942,6 +2946,8 @@ namespace libtorrent t->verify_piece(p.piece); } + check_graceful_pause(); + if (is_disconnecting()) return; if (request_a_block(*t, *this)) @@ -2949,6 +2955,24 @@ namespace libtorrent send_block_requests(); } + void peer_connection::check_graceful_pause() + { + // TODO: 3 instead of having to ask the torrent whether it's in graceful + // pause mode or not, the peers should keep that state (and the torrent + // should update them when it enters graceful pause). When a peer enters + // graceful pause mode, it should cancel all outstanding requests and + // clear its request queue. + boost::shared_ptr t = m_torrent.lock(); + if (!t || !t->graceful_pause()) return; + + if (m_outstanding_bytes > 0) return; + +#ifndef TORRENT_DISABLE_LOGGING + peer_log(peer_log_alert::info, "GRACEFUL_PAUSE", "NO MORE DOWNLOAD"); +#endif + disconnect(errors::torrent_paused, op_bittorrent); + } + void peer_connection::on_disk_write_complete(disk_io_job const* j , peer_request p, boost::shared_ptr t) { @@ -3803,23 +3827,9 @@ namespace libtorrent if (m_disconnecting) return; - if (t->graceful_pause() && m_outstanding_bytes == 0) - { -#ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::info, "GRACEFUL_PAUSE", "NO MORE DOWNLOAD"); -#endif - disconnect(errors::torrent_paused, op_bittorrent); - - // if this was the last connection, post the alert - // TODO: it would be nice if none of this logic would leak outside of - // the torrent object) - if (t->num_peers() == 0) - { - if (t->alerts().should_post()) - t->alerts().emplace_alert(t->get_handle()); - } - return; - } + // TODO: 3 once peers are properly put in graceful pause mode, they can + // cancel all outstanding requests and this test can be removed. + if (t->graceful_pause()) return; // we can't download pieces in these states if (t->state() == torrent_status::checking_files @@ -6127,6 +6137,9 @@ namespace libtorrent if (m_extension_outstanding_bytes > 0) m_extension_outstanding_bytes -= (std::min)(m_extension_outstanding_bytes, int(bytes_transferred)); + check_graceful_pause(); + if (m_disconnecting) return; + int num_loops = 0; do { diff --git a/src/request_blocks.cpp b/src/request_blocks.cpp index 8d7970c4f..eb7002404 100644 --- a/src/request_blocks.cpp +++ b/src/request_blocks.cpp @@ -73,6 +73,9 @@ namespace libtorrent // initialized after we have the metadata if (!t.are_files_checked()) return false; + // we don't want to request more blocks while trying to gracefully pause + if (t.graceful_pause()) return false; + TORRENT_ASSERT(c.peer_info_struct() != 0 || c.type() != peer_connection::bittorrent_connection); bool time_critical_mode = t.num_time_critical_pieces() > 0; diff --git a/src/torrent.cpp b/src/torrent.cpp index 2d1f2eb9b..3fac8f919 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -6111,6 +6111,8 @@ namespace libtorrent // disconnected. This will clear the graceful_pause_mode and post the // torrent_paused_alert. TORRENT_ASSERT(is_paused()); + + // this will post torrent_paused alert set_allow_peers(false); } @@ -8180,7 +8182,7 @@ namespace libtorrent if (m_connections.size() >= m_max_connections) return false; // if we're paused, obviously we're not connecting to peers - if (is_paused() || m_abort) return false; + if (is_paused() || m_abort || m_graceful_pause_mode) return false; if ((m_state == torrent_status::checking_files || m_state == torrent_status::checking_resume_data) @@ -9609,7 +9611,7 @@ namespace libtorrent INVARIANT_CHECK; if (!m_allow_peers) return; - if (!graceful) set_allow_peers(false); + set_allow_peers(graceful ? true : false, graceful); m_announce_to_dht = false; m_announce_to_trackers = false; @@ -9619,11 +9621,9 @@ namespace libtorrent set_need_save_resume(); state_updated(); - m_graceful_pause_mode = graceful; update_gauge(); update_want_peers(); update_want_scrape(); - } void torrent::do_pause()