From 088f4bf7000a4c5ad3f1b9fd12b99dcad14348c0 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 5 Feb 2010 08:23:17 +0000 Subject: [PATCH] improved LSD performance and made the interval configurable --- ChangeLog | 1 + bindings/python/src/session_settings.cpp | 1 + docs/manual.rst | 6 ++ include/libtorrent/aux_/session_impl.hpp | 14 ++- include/libtorrent/session_settings.hpp | 5 ++ include/libtorrent/torrent.hpp | 16 ++-- src/session_impl.cpp | 66 ++++++++++++--- src/torrent.cpp | 103 +++++++++++------------ 8 files changed, 135 insertions(+), 77 deletions(-) diff --git a/ChangeLog b/ChangeLog index a4a50cf20..b5be9102b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -100,6 +100,7 @@ * fixed magnet link issue when using resume data * support disk I/O priority settings * added info_hash to torrent_deleted_alert + * improved LSD performance and made the interval configurable release 0.14.9 diff --git a/bindings/python/src/session_settings.cpp b/bindings/python/src/session_settings.cpp index e98c7e59c..b559425b2 100644 --- a/bindings/python/src/session_settings.cpp +++ b/bindings/python/src/session_settings.cpp @@ -106,6 +106,7 @@ void bind_session_settings() .def_readwrite("max_suggest_pieces", &session_settings::max_suggest_pieces) .def_readwrite("drop_skipped_requests", &session_settings::drop_skipped_requests) .def_readwrite("low_prio_disk", &session_settings::low_prio_disk) + .def_readwrite("local_service_announce_interval", &session_settings::local_service_announce_interval) .def_readwrite("volatile_read_cache", &session_settings::volatile_read_cache) .def_readwrite("guided_read_cache", &guided_read_cache) ; diff --git a/docs/manual.rst b/docs/manual.rst index d07ddd736..bc6043f65 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3721,6 +3721,7 @@ session_settings bool drop_skipped_requests; bool low_prio_disk; + int local_service_announce_interval; bool volatile_read_cache; bool guided_read_cache; bool default_min_cache_age; @@ -4194,6 +4195,11 @@ overall responsiveness of the system while downloading in the background. For high-performance server setups, this might not be desirable. +``local_service_announce_interval`` is the time between local +network announces for a torrent. By default, when local service +discovery is enabled a torrent announces itself every 5 minutes. +This interval is specified in seconds. + ``volatile_read_cache``, if this is set to true, read cache blocks that are hit by peer read requests are removed from the disk cache to free up more space. This is useful if you don't expect the disk diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 9fd5a0fff..9a44bbde2 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -205,6 +205,8 @@ namespace libtorrent void on_port_map_log(char const* msg, int map_transport); + void on_lsd_announce(error_code const& e); + // called when a port mapping is successful, or a router returns // a failure to map a port void on_port_mapping(int mapping, int port, error_code const& ec @@ -709,10 +711,20 @@ namespace libtorrent // the timer used to fire the tick deadline_timer m_timer; + // torrents are announced on the local network in a + // round-robin fashion. All torrents are cycled through + // within the LSD announce interval (which defaults to + // 5 minutes) + torrent_map::iterator m_next_lsd_torrent; + + // this announce timer is used + // by Local service discovery + deadline_timer m_lsd_announce_timer; + // the index of the torrent that will be offered to // connect to a peer next time on_tick is called. // This implements a round robin. - int m_next_connect_torrent; + torrent_map::iterator m_next_connect_torrent; #ifdef TORRENT_DEBUG void check_invariant() const; #endif diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index a23cebe07..e061617fa 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -186,6 +186,7 @@ namespace libtorrent , max_suggest_pieces(10) , drop_skipped_requests(false) , low_prio_disk(true) + , local_service_announce_interval(5 * 60) , volatile_read_cache(false) , guided_read_cache(true) , default_cache_min_age(1) @@ -689,6 +690,10 @@ namespace libtorrent // in the background bool low_prio_disk; + // number of seconds between local service announces for + // torrents. Defaults to 5 minutes + int local_service_announce_interval; + // if this is set to true, any block read from the // disk cache will be dropped from the cache immediately // following. This may be useful if the block is not diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 48f608214..5e2748aae 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -723,6 +723,10 @@ namespace libtorrent bool add_merkle_nodes(std::map const& n, int piece); + // this is called once periodically for torrents + // that are not private + void lsd_announce(); + private: void on_files_deleted(int ret, disk_io_job const& j); @@ -838,10 +842,12 @@ namespace libtorrent // used to resolve the names of web seeds mutable tcp::resolver m_host_resolver; +#ifndef TORRENT_DISABLE_DHT // this announce timer is used both // by Local service discovery and // by the DHT. - deadline_timer m_lsd_announce_timer; + deadline_timer m_dht_announce_timer; +#endif // used for tracker announces deadline_timer m_tracker_timer; @@ -853,18 +859,14 @@ namespace libtorrent void on_tracker_announce(); - static void on_lsd_announce_disp(boost::weak_ptr p - , error_code const& e); - - // this is called once every 5 minutes for torrents - // that are not private - void on_lsd_announce(); + void dht_announce(); #ifndef TORRENT_DISABLE_DHT static void on_dht_announce_response_disp(boost::weak_ptr t , std::vector const& peers); void on_dht_announce_response(std::vector const& peers); bool should_announce_dht() const; + void on_dht_announce(error_code const& e); // the time when the DHT was last announced of our // presence on this torrent diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 724388ca1..bb9f36f37 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -285,6 +285,7 @@ namespace aux { TORRENT_SETTING(integer, max_suggest_pieces) TORRENT_SETTING(boolean, drop_skipped_requests) TORRENT_SETTING(boolean, low_prio_disk) + TORRENT_SETTING(boolean, local_service_announce_interval) }; #undef TORRENT_SETTING @@ -443,7 +444,7 @@ namespace aux { , m_half_open) #endif , m_timer(m_io_service) - , m_next_connect_torrent(0) + , m_lsd_announce_timer(m_io_service) #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING , m_logpath(logpath) #endif @@ -454,6 +455,9 @@ namespace aux { , m_total_failed_bytes(0) , m_total_redundant_bytes(0) { + m_next_lsd_torrent = m_torrents.begin(); + m_next_connect_torrent = m_torrents.begin(); + TORRENT_ASSERT(listen_interface); error_code ec; m_listen_interface = tcp::endpoint(address::from_string(listen_interface, ec), listen_port_range.first); @@ -590,6 +594,12 @@ namespace aux { m_timer.expires_from_now(milliseconds(100), ec); m_timer.async_wait(bind(&session_impl::on_tick, this, _1)); + int delay = (std::max)(m_settings.local_service_announce_interval + / (std::max)(int(m_torrents.size()), 1), 1); + m_lsd_announce_timer.expires_from_now(seconds(delay), ec); + m_lsd_announce_timer.async_wait( + bind(&session_impl::on_lsd_announce, this, _1)); + m_thread.reset(new thread(boost::bind(&session_impl::main_thread, this))); } @@ -900,6 +910,7 @@ namespace aux { m_dht_socket.close(); #endif m_timer.cancel(ec); + m_lsd_announce_timer.cancel(ec); // close the listen sockets for (std::list::iterator i = m_listen_sockets.begin() @@ -1963,16 +1974,14 @@ namespace aux { if (num_downloads > 0) average_peers = num_downloads_peers / num_downloads; - torrent_map::iterator i = m_torrents.begin(); - if (m_next_connect_torrent < int(m_torrents.size())) - std::advance(i, m_next_connect_torrent); - else - m_next_connect_torrent = 0; + if (m_next_connect_torrent == m_torrents.end()) + m_next_connect_torrent = m_torrents.begin(); + int steps_since_last_connect = 0; int num_torrents = int(m_torrents.size()); for (;;) { - torrent& t = *i->second; + torrent& t = *m_next_connect_torrent->second; if (t.want_more_peers()) { int connect_points = 100; @@ -2012,15 +2021,12 @@ namespace aux { } #endif } + ++m_next_connect_torrent; ++steps_since_last_connect; - ++i; - if (i == m_torrents.end()) - { - TORRENT_ASSERT(m_next_connect_torrent == num_torrents); - i = m_torrents.begin(); - m_next_connect_torrent = 0; - } + if (m_next_connect_torrent == m_torrents.end()) + m_next_connect_torrent = m_torrents.begin(); + // if we have gone two whole loops without // handing out a single connection, break if (steps_since_last_connect > num_torrents * 2) break; @@ -2111,6 +2117,27 @@ namespace aux { // m_peer_pool.release_memory(); } + void session_impl::on_lsd_announce(error_code const& e) + { + if (e) return; + + mutex::scoped_lock l(m_mutex); + + // announce on local network every 5 minutes + int delay = (std::max)(m_settings.local_service_announce_interval + / (std::max)(int(m_torrents.size()), 1), 1); + error_code ec; + m_lsd_announce_timer.expires_from_now(seconds(delay), ec); + m_lsd_announce_timer.async_wait( + bind(&session_impl::on_lsd_announce, this, _1)); + + if (m_next_lsd_torrent == m_torrents.end()) return; + m_next_lsd_torrent->second->lsd_announce(); + ++m_next_lsd_torrent; + if (m_next_lsd_torrent == m_torrents.end()) + m_next_lsd_torrent = m_torrents.begin(); + } + namespace { bool is_active(torrent* t, session_settings const& s) @@ -2729,8 +2756,19 @@ namespace aux { #ifdef TORRENT_DEBUG sha1_hash i_hash = t.torrent_file().info_hash(); #endif + if (i == m_next_lsd_torrent) + ++m_next_lsd_torrent; + if (i == m_next_connect_torrent) + ++m_next_connect_torrent; + t.set_queue_position(-1); m_torrents.erase(i); + + if (m_next_lsd_torrent == m_torrents.end()) + m_next_lsd_torrent = m_torrents.begin(); + if (m_next_connect_torrent == m_torrents.end()) + m_next_connect_torrent = m_torrents.begin(); + std::list >::iterator k = std::find(m_queued_for_checking.begin(), m_queued_for_checking.end(), tptr); if (k != m_queued_for_checking.end()) m_queued_for_checking.erase(k); diff --git a/src/torrent.cpp b/src/torrent.cpp index b1e764fde..f4e87350c 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -214,7 +214,9 @@ namespace libtorrent , m_torrent_file(p.ti ? p.ti : new torrent_info(p.info_hash)) , m_storage(0) , m_host_resolver(ses.m_io_service) - , m_lsd_announce_timer(ses.m_io_service) +#ifndef TORRENT_DISABLE_DHT + , m_dht_announce_timer(ses.m_io_service) +#endif , m_tracker_timer(ses.m_io_service) #ifndef TORRENT_DISABLE_DHT , m_last_dht_announce(time_now() - minutes(15)) @@ -368,10 +370,9 @@ namespace libtorrent // DHT announces are done on the local service // discovery timer. Trigger it. error_code ec; - boost::weak_ptr self(shared_from_this()); - m_lsd_announce_timer.expires_from_now(seconds(1), ec); - m_lsd_announce_timer.async_wait( - bind(&torrent::on_lsd_announce_disp, self, _1)); + m_dht_announce_timer.expires_from_now(seconds(1), ec); + m_dht_announce_timer.async_wait( + bind(&torrent::on_dht_announce, shared_from_this(), _1)); } #endif @@ -1175,30 +1176,14 @@ namespace libtorrent announce_with_tracker(); } - void torrent::on_lsd_announce_disp(boost::weak_ptr p - , error_code const& e) + void torrent::lsd_announce() { -#if defined TORRENT_LOGGING - if (e) - { - boost::shared_ptr t = p.lock(); - if (!t) return; - (*t->session().m_logger) << time_now_string() << " on_lsd_announce_disp: " << e.message() << "\n"; - } -#else - if (e) return; -#endif - boost::shared_ptr t = p.lock(); - if (!t) return; - t->on_lsd_announce(); - } - - void torrent::on_lsd_announce() - { - mutex::scoped_lock l(m_ses.m_mutex); - if (m_abort) return; + // if the files haven't been checked yet, we're + // not ready for peers + if (!m_files_checked) return; + TORRENT_ASSERT(!m_torrent_file->priv()); if (m_torrent_file->is_valid() && (m_torrent_file->priv() @@ -1206,36 +1191,39 @@ namespace libtorrent && !m_settings.allow_i2p_mixed))) return; - if (is_paused()) return; - boost::weak_ptr self(shared_from_this()); - - error_code ec; - - // announce on local network every 5 minutes - m_lsd_announce_timer.expires_from_now(minutes(5), ec); - m_lsd_announce_timer.async_wait( - bind(&torrent::on_lsd_announce_disp, self, _1)); - // announce with the local discovery service m_ses.announce_lsd(m_torrent_file->info_hash()); - -#ifndef TORRENT_DISABLE_DHT - if (!m_ses.m_dht) return; - ptime now = time_now(); - if (should_announce_dht() && now - m_last_dht_announce > minutes(14)) - { - m_last_dht_announce = now; - m_ses.m_dht->announce(m_torrent_file->info_hash() - , m_ses.listen_port() - , bind(&torrent::on_dht_announce_response_disp, self, _1)); - } -#endif } #ifndef TORRENT_DISABLE_DHT + void torrent::on_dht_announce(error_code const& e) + { + if (e) return; + + mutex::scoped_lock l(m_ses.m_mutex); + if (m_abort) return; + + error_code ec; + m_dht_announce_timer.expires_from_now(minutes(15), ec); + m_dht_announce_timer.async_wait( + bind(&torrent::on_dht_announce, shared_from_this(), _1)); + + if (m_torrent_file->is_valid() && m_torrent_file->priv()) + return; + + if (is_paused()) return; + if (!m_ses.m_dht) return; + if (!should_announce_dht()) return; + + m_last_dht_announce = time_now(); + boost::weak_ptr self(shared_from_this()); + m_ses.m_dht->announce(m_torrent_file->info_hash() + , m_ses.listen_port() + , bind(&torrent::on_dht_announce_response_disp, self, _1)); + } void torrent::on_dht_announce_response_disp(boost::weak_ptr t , std::vector const& peers) { @@ -1617,7 +1605,7 @@ namespace libtorrent #if defined TORRENT_LOGGING if (ec) - *m_ses.m_logger << time_now_string() << " on_i2p_resolve: " << e.message() << "\n"; + *m_ses.m_logger << time_now_string() << " on_i2p_resolve: " << ec.message() << "\n"; #endif if (ec || m_ses.is_aborted()) return; @@ -1633,7 +1621,7 @@ namespace libtorrent INVARIANT_CHECK; #if defined TORRENT_LOGGING - if (ec) + if (e) *m_ses.m_logger << time_now_string() << " on_peer_name_lookup: " << e.message() << "\n"; #endif if (e || host == tcp::resolver::iterator() || @@ -5270,11 +5258,14 @@ namespace libtorrent && (!m_torrent_file->is_i2p() || m_settings.allow_i2p_mixed))) { + if (m_ses.m_lsd) lsd_announce(); + +#ifndef TORRENT_DISABLE_DHT error_code ec; - boost::weak_ptr self(shared_from_this()); - m_lsd_announce_timer.expires_from_now(seconds(1), ec); - m_lsd_announce_timer.async_wait( - bind(&torrent::on_lsd_announce_disp, self, _1)); + m_dht_announce_timer.expires_from_now(seconds(1), ec); + m_dht_announce_timer.async_wait( + bind(&torrent::on_dht_announce, shared_from_this(), _1)); +#endif } } @@ -5283,7 +5274,9 @@ namespace libtorrent if (!m_announcing) return; error_code ec; - m_lsd_announce_timer.cancel(ec); +#ifndef TORRENT_DISABLE_DHT + m_dht_announce_timer.cancel(ec); +#endif m_tracker_timer.cancel(ec); m_announcing = false;