From a1e7d3229dffabf410a71919f57ca564bb47e7be Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 18 May 2014 22:17:51 +0000 Subject: [PATCH] improve queuing logic of inactive torrents (dont_count_slow_torrents) --- ChangeLog | 1 + include/libtorrent/session_settings.hpp | 9 +++++ include/libtorrent/torrent.hpp | 15 +++++++- src/session.cpp | 4 ++- src/session_impl.cpp | 47 ++++++++----------------- src/torrent.cpp | 46 ++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5535102b9..f60da8873 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 1.0 release + * improve queuing logic of inactive torrents (dont_count_slow_torrents) * expose optimistic unchoke logic to plugins * fix issue with large UDP packets on windows * remove set_ratio() feature diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 1a86ab137..93342a568 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -1383,6 +1383,15 @@ namespace libtorrent // side effect that the disk cache is less likely and slower at returning // memory to the kernel when cache pressure is low. bool use_disk_cache_pool; + + // the download and upload rate limits for a torrent to be considered + // active by the queuing mechanism. A torrent whose download rate is less + // than ``inactive_down_rate`` and whose upload rate is less than + // ``inactive_up_rate`` for ``auto_manage_startup`` seconds, is + // considered inactive, and another queued torrent may be startert. + // This logic is disabled if ``dont_count_slow_torrents`` is false. + int inactive_down_rate; + int inactive_up_rate; }; // structure used to hold configuration options for the DHT diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index e586fe10c..b1eb54d9a 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -736,6 +736,9 @@ namespace libtorrent - m_picker->num_have() - m_picker->num_filtered() == 0; } + bool is_inactive() const + { return m_inactive; } + std::string save_path() const; alert_manager& alerts() const; piece_picker& picker() @@ -1333,7 +1336,10 @@ namespace libtorrent // set to true while moving the storage bool m_moving_storage:1; - // TODO: there's space for another bit here + // this is true if this torrent is considered inactive from the + // queuing mechanism's point of view. If a torrent doesn't transfer + // at high enough rates, it's inactive. + bool m_inactive:1; // ---- @@ -1402,6 +1408,13 @@ namespace libtorrent // millionths of completeness) unsigned int m_progress_ppm:20; + // the number of seconds this torrent has been under the inactive + // threshold in terms of sending and receiving data. When this counter + // reaches the settings.inactive_torrent_timeout it will be considered + // inactive and possibly open up another queue slot, to start another, + // queued, torrent. Every second it's above the threshold + boost::int16_t m_inactive_counter; + #if TORRENT_USE_ASSERTS public: // set to false until we've loaded resume data diff --git a/src/session.cpp b/src/session.cpp index 628342aba..7c7936f50 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -1316,7 +1316,7 @@ namespace libtorrent , max_paused_peerlist_size(4000) , min_announce_interval(5 * 60) , prioritize_partial_pieces(false) - , auto_manage_startup(120) + , auto_manage_startup(60) , rate_limit_ip_overhead(true) , announce_to_all_trackers(false) , announce_to_all_tiers(false) @@ -1415,6 +1415,8 @@ namespace libtorrent , support_merkle_torrents(false) , report_redundant_bytes(true) , use_disk_cache_pool(false) + , inactive_down_rate(2048) + , inactive_up_rate(2048) {} session_settings::~session_settings() {} diff --git a/src/session_impl.cpp b/src/session_impl.cpp index fc68042c8..6a41697d4 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -4181,24 +4181,6 @@ retry: m_next_lsd_torrent = m_torrents.begin(); } - namespace - { - bool is_active(torrent* t, session_settings const& s) - { - // if we count slow torrents, every torrent - // is considered active - if (!s.dont_count_slow_torrents) return true; - - // if the torrent started less than 2 minutes - // ago (default), let it count as active since - // the rates are probably not accurate yet - if (time_now() - t->started() < seconds(s.auto_manage_startup)) return true; - - return t->statistics().upload_payload_rate() != 0.f - || t->statistics().download_payload_rate() != 0.f; - } - } - void session_impl::auto_manage_torrents(std::vector& list , int& dht_limit, int& tracker_limit, int& lsd_limit , int& hard_limit, int type_limit) @@ -4212,20 +4194,6 @@ retry: || t->state() == torrent_status::queued_for_checking)) continue; - --dht_limit; - --lsd_limit; - --tracker_limit; - t->set_announce_to_dht(dht_limit >= 0); - t->set_announce_to_trackers(tracker_limit >= 0); - t->set_announce_to_lsd(lsd_limit >= 0); - - if (!t->is_paused() && !is_active(t, settings()) - && hard_limit > 0) - { - --hard_limit; - continue; - } - if (type_limit > 0 && hard_limit > 0) { --hard_limit; @@ -4234,6 +4202,21 @@ retry: t->log_to_all_peers("AUTO MANAGER STARTING TORRENT"); #endif t->set_allow_peers(true); + + --dht_limit; + --lsd_limit; + --tracker_limit; + t->set_announce_to_dht(dht_limit >= 0); + t->set_announce_to_trackers(tracker_limit >= 0); + t->set_announce_to_lsd(lsd_limit >= 0); + + if (!t->is_paused() && t->is_inactive() + && hard_limit > 0) + { + // the hard limit takes inactive torrents into account, but the + // download and seed limits don't. + continue; + } } else { diff --git a/src/torrent.cpp b/src/torrent.cpp index 5903c5cc9..72d36ad1e 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -232,6 +232,7 @@ namespace libtorrent , m_ssl_torrent(false) , m_deleted(false) , m_moving_storage(false) + , m_inactive(false) , m_incomplete(0xffffff) , m_abort(false) , m_announce_to_dht((p.flags & add_torrent_params::flag_paused) == 0) @@ -247,6 +248,7 @@ namespace libtorrent , m_downloaded(0xffffff) , m_interface_index(0) , m_progress_ppm(0) + , m_inactive_counter(0) { // if there is resume data already, we don't need to trigger the initial save // resume data @@ -7351,6 +7353,8 @@ namespace libtorrent } #endif + m_inactive = false; + state_updated(); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING @@ -7846,6 +7850,48 @@ namespace libtorrent // if the rate is 0, there's no update because of network transfers if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0) state_updated(); + + // this section determines whether the torrent is active or not. When it + // changes state, it may also trigger the auto-manage logic to reconsider + // which torrents should be queued and started. There is a low pass + // filter in order to avoid flapping (auto_manage_startup). + if (m_stat.download_payload_rate() < m_ses.m_settings.inactive_down_rate + && m_stat.upload_payload_rate() < m_ses.m_settings.inactive_up_rate) + { + if (m_inactive_counter < 0) m_inactive_counter = 0; + if (m_inactive_counter < INT16_MAX) + { + ++m_inactive_counter; + + // if this torrent was just considered inactive, we may want + // to dequeue some other torrent + if (m_inactive == false + && m_inactive_counter >= m_ses.m_settings.auto_manage_startup) + { + m_inactive = true; + if (m_ses.m_settings.dont_count_slow_torrents) + m_ses.trigger_auto_manage(); + } + } + } + else + { + if (m_inactive_counter > 0) m_inactive_counter = 0; + if (m_inactive_counter > INT16_MIN) + { + --m_inactive_counter; + + // if this torrent was just considered active, we may want + // to queue some other torrent + if (m_inactive == true + && m_inactive_counter <= -m_ses.m_settings.auto_manage_startup) + { + m_inactive = false; + if (m_ses.m_settings.dont_count_slow_torrents) + m_ses.trigger_auto_manage(); + } + } + } } void torrent::maybe_connect_web_seeds()