forked from premiere/premiere-libtorrent
graceful disconnect mode which finishes transactions before disconnecting peers
This commit is contained in:
parent
0dbef9103a
commit
e4de1fc8b1
|
@ -1,3 +1,4 @@
|
|||
* graceful peer disconnect mode which finishes transactions before disconnecting peers
|
||||
* support chunked encoding for web seeds (only for BEP 19, web seeds)
|
||||
* optimized session startup time
|
||||
* support SSL for web seeds, through all proxies
|
||||
|
|
|
@ -299,7 +299,7 @@ void bind_torrent_handle()
|
|||
.def("is_seed", _(&torrent_handle::is_seed))
|
||||
.def("is_finished", _(&torrent_handle::is_finished))
|
||||
.def("is_paused", _(&torrent_handle::is_paused))
|
||||
.def("pause", _(&torrent_handle::pause))
|
||||
.def("pause", _(&torrent_handle::pause), arg("flags") = 0)
|
||||
.def("resume", _(&torrent_handle::resume))
|
||||
.def("clear_error", _(&torrent_handle::clear_error))
|
||||
.def("set_priority", _(&torrent_handle::set_priority))
|
||||
|
@ -366,6 +366,10 @@ void bind_torrent_handle()
|
|||
#endif
|
||||
;
|
||||
|
||||
enum_<torrent_handle::save_resume_flags_t>("pause_flags_t")
|
||||
.value("graceful_pause", torrent_handle::graceful_pause)
|
||||
;
|
||||
|
||||
enum_<torrent_handle::save_resume_flags_t>("save_resume_flags_t")
|
||||
.value("flush_disk_cache", torrent_handle::flush_disk_cache)
|
||||
;
|
||||
|
|
|
@ -1955,7 +1955,8 @@ Its declaration looks like this::
|
|||
|
||||
void use_interface(char const* net_interface) const;
|
||||
|
||||
void pause() const;
|
||||
enum pause_flags_t { graceful_pause = 1 };
|
||||
void pause(int flags = 0) const;
|
||||
void resume() const;
|
||||
bool is_paused() const;
|
||||
bool is_seed() const;
|
||||
|
@ -2393,7 +2394,8 @@ pause() resume() is_paused()
|
|||
|
||||
::
|
||||
|
||||
void pause() const;
|
||||
enum pause_flags_t { graceful_pause = 1 };
|
||||
void pause(int flags) const;
|
||||
void resume() const;
|
||||
bool is_paused() const;
|
||||
|
||||
|
@ -2403,6 +2405,12 @@ all potential (not connected) peers. You can use ``is_paused()`` to determine if
|
|||
is currently paused. Torrents may be paused automatically if there is a file error (e.g. disk full)
|
||||
or something similar. See file_error_alert_.
|
||||
|
||||
The ``flags`` argument to pause can be set to ``torrent_handle::graceful_pause`` which will
|
||||
delay the disconnect of peers that we're still downloading outstanding requests from. The torrent
|
||||
will not accept any more requests and will disconnect all idle peers. As soon as a peer is
|
||||
done transferring the blocks that were requested from it, it is disconnected. This is a graceful
|
||||
shut down of the torrent in the sense that no downloaded bytes are wasted.
|
||||
|
||||
torrents that are auto-managed may be automatically resumed again. It does not make sense to
|
||||
pause an auto-managed torrent without making it not automanaged first. Torrents are auto-managed
|
||||
by default when added to the session. For more information, see queuing_.
|
||||
|
|
|
@ -1222,7 +1222,7 @@ int main(int argc, char* argv[])
|
|||
else
|
||||
{
|
||||
h.auto_managed(false);
|
||||
h.pause();
|
||||
h.pause(torrent_handle::graceful_pause);
|
||||
}
|
||||
// the alert handler for save_resume_data_alert
|
||||
// will save it to disk
|
||||
|
@ -1336,7 +1336,9 @@ int main(int argc, char* argv[])
|
|||
out += str;
|
||||
}
|
||||
|
||||
if (h.is_paused()) out += esc("34");
|
||||
torrent_status s = h.status();
|
||||
|
||||
if (s.paused) out += esc("34");
|
||||
else out += esc("37");
|
||||
|
||||
std::string name = h.name();
|
||||
|
@ -1344,9 +1346,6 @@ int main(int argc, char* argv[])
|
|||
snprintf(str, sizeof(str), "%-40s %s ", name.c_str(), term);
|
||||
out += str;
|
||||
|
||||
torrent_status s = h.status();
|
||||
|
||||
bool paused = h.is_paused();
|
||||
bool auto_managed = h.is_auto_managed();
|
||||
bool sequential_download = h.is_sequential_download();
|
||||
|
||||
|
@ -1373,7 +1372,7 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
snprintf(str, sizeof(str), "%-13s down: (%s%s%s) up: %s%s%s (%s%s%s) swarm: %4d:%4d"
|
||||
" bw queue: (%d|%d) all-time (Rx: %s%s%s Tx: %s%s%s) seed rank: %x %c%s\n"
|
||||
, (paused && !auto_managed)?"paused":(paused && auto_managed)?"queued":state_str[s.state]
|
||||
, (s.paused && !auto_managed)?"paused":(s.paused && auto_managed)?"queued":state_str[s.state]
|
||||
, esc("32"), add_suffix(s.total_download).c_str(), term
|
||||
, esc("31"), add_suffix(s.upload_rate, "/s").c_str(), term
|
||||
, esc("31"), add_suffix(s.total_upload).c_str(), term
|
||||
|
|
|
@ -295,6 +295,8 @@ namespace libtorrent
|
|||
std::vector<pending_block> const& request_queue() const;
|
||||
std::vector<peer_request> const& upload_queue() const;
|
||||
|
||||
void clear_request_queue();
|
||||
|
||||
// estimate of how long it will take until we have
|
||||
// received all piece requests that we have sent
|
||||
// if extra_bytes is specified, it will include those
|
||||
|
@ -539,6 +541,8 @@ namespace libtorrent
|
|||
bool has_country() const { return m_country[0] != 0; }
|
||||
#endif
|
||||
|
||||
int outstanding_bytes() const { return m_outstanding_bytes; }
|
||||
|
||||
int send_buffer_size() const
|
||||
{ return m_send_buffer.size(); }
|
||||
|
||||
|
|
|
@ -151,8 +151,10 @@ namespace libtorrent
|
|||
void set_share_mode(bool s);
|
||||
bool share_mode() const { return m_share_mode; }
|
||||
|
||||
bool graceful_pause() const { return m_graceful_pause_mode; }
|
||||
|
||||
void set_upload_mode(bool b);
|
||||
bool upload_mode() const { return m_upload_mode; }
|
||||
bool upload_mode() const { return m_upload_mode || m_graceful_pause_mode; }
|
||||
bool is_upload_only() const
|
||||
{ return (is_finished() || upload_mode()) && !super_seeding(); }
|
||||
|
||||
|
@ -222,9 +224,9 @@ namespace libtorrent
|
|||
bool has_error() const { return m_error; }
|
||||
|
||||
void flush_cache();
|
||||
void pause();
|
||||
void pause(bool graceful = false);
|
||||
void resume();
|
||||
void set_allow_peers(bool b);
|
||||
void set_allow_peers(bool b, bool graceful_pause = false);
|
||||
void set_announce_to_dht(bool b) { m_announce_to_dht = b; }
|
||||
void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; }
|
||||
void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; }
|
||||
|
@ -235,7 +237,7 @@ namespace libtorrent
|
|||
|
||||
bool is_paused() const;
|
||||
bool allows_peers() const { return m_allow_peers; }
|
||||
bool is_torrent_paused() const { return !m_allow_peers; }
|
||||
bool is_torrent_paused() const { return !m_allow_peers || m_graceful_pause_mode; }
|
||||
void force_recheck();
|
||||
void save_resume_data(int flags);
|
||||
|
||||
|
@ -1224,6 +1226,11 @@ namespace libtorrent
|
|||
|
||||
// round-robin index into m_interfaces
|
||||
mutable boost::uint8_t m_interface_index;
|
||||
|
||||
// set to true when this torrent has been paused but
|
||||
// is waiting to finish all current download requests
|
||||
// before actually closing all connections
|
||||
bool m_graceful_pause_mode:1;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -469,7 +469,8 @@ namespace libtorrent
|
|||
bool is_seed() const;
|
||||
bool is_finished() const;
|
||||
bool is_paused() const;
|
||||
void pause() const;
|
||||
enum pause_flags_t { graceful_pause = 1 };
|
||||
void pause(int flags = 0) const;
|
||||
void resume() const;
|
||||
void set_upload_mode(bool b) const;
|
||||
void set_share_mode(bool b) const;
|
||||
|
|
|
@ -1235,9 +1235,6 @@ namespace libtorrent
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
boost::shared_ptr<torrent> t = m_torrent.lock();
|
||||
TORRENT_ASSERT(t);
|
||||
|
||||
#ifndef TORRENT_DISABLE_EXTENSIONS
|
||||
for (extension_list_t::iterator i = m_extensions.begin()
|
||||
, end(m_extensions.end()); i != end; ++i)
|
||||
|
@ -1252,6 +1249,14 @@ namespace libtorrent
|
|||
#endif
|
||||
m_peer_choked = true;
|
||||
|
||||
clear_request_queue();
|
||||
}
|
||||
|
||||
void peer_connection::clear_request_queue()
|
||||
{
|
||||
boost::shared_ptr<torrent> t = m_torrent.lock();
|
||||
TORRENT_ASSERT(t);
|
||||
|
||||
// clear the requests that haven't been sent yet
|
||||
if (peer_info_struct() == 0 || !peer_info_struct()->on_parole)
|
||||
{
|
||||
|
@ -1269,7 +1274,6 @@ namespace libtorrent
|
|||
m_request_queue.clear();
|
||||
m_queued_time_critical = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool match_request(peer_request const& r, piece_block const& b, int block_size)
|
||||
|
@ -3108,6 +3112,15 @@ namespace libtorrent
|
|||
|
||||
if (m_disconnecting) return;
|
||||
|
||||
if (t->graceful_pause() && m_outstanding_bytes == 0)
|
||||
{
|
||||
#ifdef TORRENT_VERBOSE_LOGGING
|
||||
(*m_logger) << time_now_string() << " *** GRACEFUL PAUSE [ NO MORE DOWNLOAD ]\n";
|
||||
#endif
|
||||
disconnect(errors::torrent_paused);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((int)m_download_queue.size() >= m_desired_queue_size
|
||||
|| t->upload_mode()) return;
|
||||
|
||||
|
|
|
@ -2647,7 +2647,8 @@ namespace aux {
|
|||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING
|
||||
t->log_to_all_peers(("AUTO MANAGER PAUSING TORRENT: " + t->torrent_file().name()).c_str());
|
||||
#endif
|
||||
t->set_allow_peers(false);
|
||||
// use graceful pause for auto-managed torrents
|
||||
t->set_allow_peers(false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2754,6 +2755,7 @@ namespace aux {
|
|||
if (!pi) continue;
|
||||
torrent* t = p->associated_torrent().lock().get();
|
||||
if (!t) continue;
|
||||
if (t->is_paused()) continue;
|
||||
|
||||
if (pi->optimistically_unchoked)
|
||||
{
|
||||
|
@ -2849,7 +2851,7 @@ namespace aux {
|
|||
torrent* t = p->associated_torrent().lock().get();
|
||||
policy::peer* pi = p->peer_info_struct();
|
||||
|
||||
if (p->ignore_unchoke_slots() || t == 0 || pi == 0) continue;
|
||||
if (p->ignore_unchoke_slots() || t == 0 || pi == 0 || t->is_paused()) continue;
|
||||
|
||||
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
|
||||
{
|
||||
|
|
|
@ -389,6 +389,7 @@ namespace libtorrent
|
|||
, m_last_upload(0)
|
||||
, m_downloaders(0xffffff)
|
||||
, m_interface_index(0)
|
||||
, m_graceful_pause_mode(false)
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*m_ses.m_logger) << time_now_string() << " creating torrent: "
|
||||
|
@ -3233,6 +3234,7 @@ namespace libtorrent
|
|||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
TORRENT_ASSERT(!m_graceful_pause_mode);
|
||||
TORRENT_ASSERT(c.is_choked());
|
||||
TORRENT_ASSERT(!c.ignore_unchoke_slots());
|
||||
// when we're unchoking the optimistic slots, we might
|
||||
|
@ -5008,7 +5010,7 @@ namespace libtorrent
|
|||
void torrent::check_invariant() const
|
||||
{
|
||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||
if (is_paused()) TORRENT_ASSERT(num_peers() == 0);
|
||||
if (is_paused()) TORRENT_ASSERT(num_peers() == 0 || m_graceful_pause_mode);
|
||||
|
||||
if (!should_check_files())
|
||||
TORRENT_ASSERT(m_state != torrent_status::checking_files);
|
||||
|
@ -5526,7 +5528,8 @@ namespace libtorrent
|
|||
|| m_state == torrent_status::queued_for_checking)
|
||||
&& (m_allow_peers || m_auto_managed)
|
||||
&& !has_error()
|
||||
&& !m_abort;
|
||||
&& !m_abort
|
||||
&& !m_graceful_pause_mode;
|
||||
}
|
||||
|
||||
void torrent::flush_cache()
|
||||
|
@ -5546,20 +5549,24 @@ namespace libtorrent
|
|||
bool torrent::is_paused() const
|
||||
{
|
||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||
return !m_allow_peers || m_ses.is_paused();
|
||||
return !m_allow_peers || m_ses.is_paused() || m_graceful_pause_mode;
|
||||
}
|
||||
|
||||
void torrent::pause()
|
||||
void torrent::pause(bool graceful)
|
||||
{
|
||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||
INVARIANT_CHECK;
|
||||
|
||||
if (!m_allow_peers) return;
|
||||
bool checking_files = should_check_files();
|
||||
m_allow_peers = false;
|
||||
if (!graceful) m_allow_peers = false;
|
||||
m_announce_to_dht = false;
|
||||
m_announce_to_trackers = false;
|
||||
m_announce_to_lsd = false;
|
||||
|
||||
// mark torrent as upload only to make peers stop request more pieces
|
||||
m_graceful_pause_mode = graceful;
|
||||
|
||||
if (!m_ses.is_paused())
|
||||
do_pause();
|
||||
if (checking_files && !should_check_files())
|
||||
|
@ -5609,7 +5616,44 @@ namespace libtorrent
|
|||
alerts().post_alert(torrent_paused_alert(get_handle()));
|
||||
}
|
||||
|
||||
disconnect_all(errors::torrent_paused);
|
||||
if (!m_graceful_pause_mode)
|
||||
{
|
||||
disconnect_all(errors::torrent_paused);
|
||||
}
|
||||
else
|
||||
{
|
||||
// disconnect all peers with no outstanding data to receive
|
||||
// and choke all remaining peers to prevent responding to new
|
||||
// requests
|
||||
for (std::set<peer_connection*>::iterator i = m_connections.begin()
|
||||
, end(m_connections.end()); i != end;)
|
||||
{
|
||||
std::set<peer_connection*>::iterator j = i++;
|
||||
peer_connection* p = *j;
|
||||
TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
|
||||
|
||||
if (p->is_disconnecting())
|
||||
m_connections.erase(j);
|
||||
|
||||
if (p->outstanding_bytes() > 0)
|
||||
{
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*p->m_logger) << "*** CHOKING PEER: torrent graceful paused\n";
|
||||
#endif
|
||||
// remove any un-sent requests from the queue
|
||||
p->clear_request_queue();
|
||||
// don't accept new requests from the peer
|
||||
if (!p->is_choked()) m_ses.choke_peer(*p);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
||||
(*p->m_logger) << "*** CLOSING CONNECTION: torrent_paused\n";
|
||||
#endif
|
||||
p->disconnect(errors::torrent_paused);
|
||||
}
|
||||
}
|
||||
|
||||
stop_announcing();
|
||||
}
|
||||
|
||||
|
@ -5628,14 +5672,17 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
void torrent::set_allow_peers(bool b)
|
||||
void torrent::set_allow_peers(bool b, bool graceful)
|
||||
{
|
||||
TORRENT_ASSERT(m_ses.is_network_thread());
|
||||
if (m_allow_peers == b) return;
|
||||
|
||||
if (m_allow_peers == b
|
||||
&& m_graceful_pause_mode == graceful) return;
|
||||
|
||||
bool checking_files = should_check_files();
|
||||
|
||||
m_allow_peers = b;
|
||||
m_graceful_pause_mode = graceful;
|
||||
|
||||
if (!b)
|
||||
{
|
||||
|
@ -5667,6 +5714,7 @@ namespace libtorrent
|
|||
m_announce_to_dht = true;
|
||||
m_announce_to_trackers = true;
|
||||
m_announce_to_lsd = true;
|
||||
m_graceful_pause_mode = false;
|
||||
do_resume();
|
||||
if (!checking_files && should_check_files())
|
||||
queue_torrent_check();
|
||||
|
@ -6706,7 +6754,7 @@ namespace libtorrent
|
|||
|
||||
st.num_complete = (m_complete == 0xffffff) ? -1 : m_complete;
|
||||
st.num_incomplete = (m_incomplete == 0xffffff) ? -1 : m_incomplete;
|
||||
st.paused = !m_allow_peers;
|
||||
st.paused = !m_allow_peers || m_graceful_pause_mode;
|
||||
bytes_done(st, flags & torrent_handle::query_accurate_download_counters);
|
||||
TORRENT_ASSERT(st.total_wanted_done >= 0);
|
||||
TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
|
||||
|
|
|
@ -371,10 +371,10 @@ namespace libtorrent
|
|||
return r;
|
||||
}
|
||||
|
||||
void torrent_handle::pause() const
|
||||
void torrent_handle::pause(int flags) const
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
TORRENT_ASYNC_CALL(pause);
|
||||
TORRENT_ASYNC_CALL1(pause, bool(flags & graceful_pause));
|
||||
}
|
||||
|
||||
void torrent_handle::set_share_mode(bool b) const
|
||||
|
|
Loading…
Reference in New Issue