Merge pull request #309 from arvidn/graceful-pause-fix

fix graceful pause issue.
This commit is contained in:
Arvid Norberg 2015-12-06 00:48:06 -05:00
commit c1cb1393fb
5 changed files with 49 additions and 22 deletions

View File

@ -813,6 +813,7 @@ namespace libtorrent
, peer_request r, boost::shared_ptr<torrent> t); , peer_request r, boost::shared_ptr<torrent> t);
void on_seed_mode_hashed(disk_io_job const* j); void on_seed_mode_hashed(disk_io_job const* j);
int request_timeout() const; int request_timeout() const;
void check_graceful_pause();
int wanted_transfer(int channel); int wanted_transfer(int channel);
int request_bandwidth(int channel, int bytes = 0); int request_bandwidth(int channel, int bytes = 0);

View File

@ -85,3 +85,13 @@ TORRENT_TEST(shutdown)
simulate_swarm(early_shutdown); simulate_swarm(early_shutdown);
} }
// TODO: the swarm_suite is probably not a very good abstraction, it's not
// configurable enough.
// TODO: add test that makes sure a torrent in graceful pause mode won't make
// outgoing connections
// TODO: add test that makes sure a torrent in graceful pause mode won't accept
// incoming connections
// TODO: add test that makes sure a torrent in graceful pause mode only posts
// the torrent_paused_alert once, and exactly once

View File

@ -1234,13 +1234,14 @@ namespace libtorrent
} }
if (t->is_paused() if (t->is_paused()
&& t->is_auto_managed()
&& m_settings.get_bool(settings_pack::incoming_starts_queued_torrents) && m_settings.get_bool(settings_pack::incoming_starts_queued_torrents)
&& !t->is_aborted()) && !t->is_aborted())
{ {
t->resume(); t->resume();
} }
if (t->is_paused() || t->is_aborted()) if (t->is_paused() || t->is_aborted() || t->graceful_pause())
{ {
// paused torrents will not accept // paused torrents will not accept
// incoming connections unless they are auto managed // incoming connections unless they are auto managed
@ -1510,6 +1511,9 @@ namespace libtorrent
m_suggested_pieces.erase(i); m_suggested_pieces.erase(i);
} }
check_graceful_pause();
if (is_disconnecting()) return;
if (m_request_queue.empty() && m_download_queue.size() < 2) if (m_request_queue.empty() && m_download_queue.size() < 2)
{ {
if (request_a_block(*t, *this)) if (request_a_block(*t, *this))
@ -2942,6 +2946,8 @@ namespace libtorrent
t->verify_piece(p.piece); t->verify_piece(p.piece);
} }
check_graceful_pause();
if (is_disconnecting()) return; if (is_disconnecting()) return;
if (request_a_block(*t, *this)) if (request_a_block(*t, *this))
@ -2949,6 +2955,24 @@ namespace libtorrent
send_block_requests(); 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<torrent> 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 void peer_connection::on_disk_write_complete(disk_io_job const* j
, peer_request p, boost::shared_ptr<torrent> t) , peer_request p, boost::shared_ptr<torrent> t)
{ {
@ -3803,23 +3827,9 @@ namespace libtorrent
if (m_disconnecting) return; if (m_disconnecting) return;
if (t->graceful_pause() && m_outstanding_bytes == 0) // TODO: 3 once peers are properly put in graceful pause mode, they can
{ // cancel all outstanding requests and this test can be removed.
#ifndef TORRENT_DISABLE_LOGGING if (t->graceful_pause()) return;
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<torrent_paused_alert>())
t->alerts().emplace_alert<torrent_paused_alert>(t->get_handle());
}
return;
}
// we can't download pieces in these states // we can't download pieces in these states
if (t->state() == torrent_status::checking_files if (t->state() == torrent_status::checking_files
@ -6127,6 +6137,9 @@ namespace libtorrent
if (m_extension_outstanding_bytes > 0) if (m_extension_outstanding_bytes > 0)
m_extension_outstanding_bytes -= (std::min)(m_extension_outstanding_bytes, int(bytes_transferred)); m_extension_outstanding_bytes -= (std::min)(m_extension_outstanding_bytes, int(bytes_transferred));
check_graceful_pause();
if (m_disconnecting) return;
int num_loops = 0; int num_loops = 0;
do do
{ {

View File

@ -73,6 +73,9 @@ namespace libtorrent
// initialized after we have the metadata // initialized after we have the metadata
if (!t.are_files_checked()) return false; 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); TORRENT_ASSERT(c.peer_info_struct() != 0 || c.type() != peer_connection::bittorrent_connection);
bool time_critical_mode = t.num_time_critical_pieces() > 0; bool time_critical_mode = t.num_time_critical_pieces() > 0;

View File

@ -6111,6 +6111,8 @@ namespace libtorrent
// disconnected. This will clear the graceful_pause_mode and post the // disconnected. This will clear the graceful_pause_mode and post the
// torrent_paused_alert. // torrent_paused_alert.
TORRENT_ASSERT(is_paused()); TORRENT_ASSERT(is_paused());
// this will post torrent_paused alert
set_allow_peers(false); set_allow_peers(false);
} }
@ -8180,7 +8182,7 @@ namespace libtorrent
if (m_connections.size() >= m_max_connections) return false; if (m_connections.size() >= m_max_connections) return false;
// if we're paused, obviously we're not connecting to peers // 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 if ((m_state == torrent_status::checking_files
|| m_state == torrent_status::checking_resume_data) || m_state == torrent_status::checking_resume_data)
@ -9609,7 +9611,7 @@ namespace libtorrent
INVARIANT_CHECK; INVARIANT_CHECK;
if (!m_allow_peers) return; 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_dht = false;
m_announce_to_trackers = false; m_announce_to_trackers = false;
@ -9619,11 +9621,9 @@ namespace libtorrent
set_need_save_resume(); set_need_save_resume();
state_updated(); state_updated();
m_graceful_pause_mode = graceful;
update_gauge(); update_gauge();
update_want_peers(); update_want_peers();
update_want_scrape(); update_want_scrape();
} }
void torrent::do_pause() void torrent::do_pause()