From f3ec86169eff86b4716865255d1743e22e27fab3 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 3 Nov 2012 03:50:12 +0000 Subject: [PATCH] merged swarm startup optimization from libtorrent_aio --- include/libtorrent/aux_/session_impl.hpp | 30 ++++++++++ include/libtorrent/torrent.hpp | 4 ++ src/session_impl.cpp | 70 ++++++++++++++++++++---- src/torrent.cpp | 65 +++++++++++++--------- 4 files changed, 132 insertions(+), 37 deletions(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 974aad5dd..88b93f1eb 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -245,6 +245,12 @@ namespace libtorrent void open_listen_port(int flags, error_code& ec); + // prioritize this torrent to be allocated some connection + // attempts, because this torrent needs more peers. + // this is typically done when a torrent starts out and + // need the initial push to connect peers + void prioritize_connections(boost::weak_ptr t); + // if we are listening on an IPv6 interface // this will return one of the IPv6 addresses on this // machine, otherwise just an empty endpoint @@ -294,6 +300,11 @@ namespace libtorrent void stop_dht(); void start_dht(entry const& startup_state); + // this is called for torrents when they are started + // it will prioritize them for announcing to + // the DHT, to get the initial peers quickly + void prioritize_dht(boost::weak_ptr t); + #ifndef TORRENT_NO_DEPRECATE entry dht_state() const; #endif @@ -556,6 +567,8 @@ namespace libtorrent void update_connections_limit(); void update_unchoke_limit(); + void trigger_auto_manage(); + void on_trigger_auto_manage(); void update_rate_settings(); void update_disk_thread_settings(); @@ -960,6 +973,9 @@ namespace libtorrent std::deque > m_dht_torrents; #endif + // torrents prioritized to get connection attempts + std::deque, int> > m_prio_torrents; + // this announce timer is used // by Local service discovery deadline_timer m_lsd_announce_timer; @@ -1189,6 +1205,20 @@ namespace libtorrent size_type m_total_failed_bytes; size_type m_total_redundant_bytes; + // this is set to true when a torrent auto-manage + // event is triggered, and reset whenever the message + // is delivered and the auto-manage is executed. + // there should never be more than a single pending auto-manage + // message in-flight at any given time. + bool m_pending_auto_manage; + + // this is also set to true when triggering an auto-manage + // of the torrents. However, if the normal auto-manage + // timer comes along and executes the auto-management, + // this is set to false, which means the triggered event + // no longer needs to execute the auto-management. + bool m_need_auto_manage; + // redundant bytes per category size_type m_redundant_bytes[7]; diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 8133a0991..8f5ff0ade 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -462,6 +462,10 @@ namespace libtorrent // base64 encoding). std::string tracker_login() const; + // if we need a connect boost, connect some peers + // immediately + void do_connect_boost(); + // returns the absolute time when the next tracker // announce will take place. ptime next_announce() const; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 9615940c1..7e16034da 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -670,6 +670,8 @@ namespace aux { #endif , m_total_failed_bytes(0) , m_total_redundant_bytes(0) + , m_pending_auto_manage(false) + , m_need_auto_manage(false) #if (defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS) && defined BOOST_HAS_PTHREADS , m_network_thread(0) #endif @@ -1307,6 +1309,23 @@ namespace aux { m_thread.reset(new thread(boost::bind(&session_impl::main_thread, this))); } + void session_impl::trigger_auto_manage() + { + if (m_pending_auto_manage) return; + + m_pending_auto_manage = true; + m_need_auto_manage = true; + m_io_service.post(boost::bind(&session_impl::on_trigger_auto_manage, this)); + } + + void session_impl::on_trigger_auto_manage() + { + assert(m_pending_auto_manage); + m_pending_auto_manage = false; + if (!m_need_auto_manage) return; + recalculate_auto_managed_torrents(); + } + void session_impl::update_dht_announce_interval() { #ifndef TORRENT_DISABLE_DHT @@ -1665,15 +1684,6 @@ namespace aux { } #endif -#ifndef TORRENT_DISABLE_DHT - void session_impl::add_dht_node(udp::endpoint n) - { - TORRENT_ASSERT(is_network_thread()); - - if (m_dht) m_dht->add_node(n); - } -#endif - feed_handle session_impl::add_feed(feed_settings const& sett) { TORRENT_ASSERT(is_network_thread()); @@ -3972,8 +3982,37 @@ retry: m_next_rss_update = min_update; } + void session_impl::prioritize_connections(boost::weak_ptr t) + { + m_prio_torrents.push_back(std::make_pair(t, 10)); + } + #ifndef TORRENT_DISABLE_DHT + void session_impl::add_dht_node(udp::endpoint n) + { + TORRENT_ASSERT(is_network_thread()); + + if (m_dht) m_dht->add_node(n); + } + + void session_impl::prioritize_dht(boost::weak_ptr t) + { + m_dht_torrents.push_back(t); + // trigger a DHT announce right away if we just + // added a new torrent and there's no back-log + if (m_dht_torrents.size() == 1) + { +#if defined TORRENT_ASIO_DEBUGGING + add_outstanding_async("session_impl::on_dht_announce"); +#endif + error_code ec; + m_dht_announce_timer.expires_from_now(seconds(0), ec); + m_dht_announce_timer.async_wait( + bind(&session_impl::on_dht_announce, this, _1)); + } + } + void session_impl::on_dht_announce(error_code const& e) { #if defined TORRENT_ASIO_DEBUGGING @@ -3990,6 +4029,15 @@ retry: // announce to DHT every 15 minutes int delay = (std::max)(m_settings.dht_announce_interval / (std::max)(int(m_torrents.size()), 1), 1); + + if (!m_dht_torrents.empty()) + { + // we have prioritized torrents that need + // an initial DHT announce. Don't wait too long + // until we announce those. + delay = (std::min)(4, delay); + } + error_code ec; m_dht_announce_timer.expires_from_now(seconds(delay), ec); m_dht_announce_timer.async_wait( @@ -4125,6 +4173,8 @@ retry: { INVARIANT_CHECK; + m_need_auto_manage = false; + // these vectors are filled with auto managed torrents std::vector downloaders; downloaders.reserve(m_torrents.size()); @@ -5003,7 +5053,7 @@ retry: // a boat load of torrents, we postpone the recalculation until // we're done adding them all (since it's kind of an expensive operation) if (params.flags & add_torrent_params::flag_auto_managed) - m_auto_manage_time_scaler = 2; + trigger_auto_manage(); return torrent_handle(torrent_ptr); } diff --git a/src/torrent.cpp b/src/torrent.cpp index d69c01ca3..738347970 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -2104,6 +2104,9 @@ namespace libtorrent #endif pause(); set_error(j.error, j.error_file); + // recalculate auto-managed torrents sooner + // in order to start checking the next torrent + m_ses.trigger_auto_manage(); return; } @@ -2250,6 +2253,8 @@ namespace libtorrent std::for_each(peers.begin(), peers.end(), boost::bind( &policy::add_peer, boost::ref(m_policy), _1, peer_id(0) , peer_info::dht, 0)); + + do_connect_boost(); } #endif @@ -2689,31 +2694,37 @@ namespace libtorrent } } - if (m_need_connect_boost) - { - m_need_connect_boost = false; - // this is the first tracker response for this torrent - // instead of waiting one second for session_impl::on_tick() - // to be called, connect to a few peers immediately - int conns = (std::min)((std::min)((std::min)(m_ses.m_settings.torrent_connect_boost - , m_ses.m_settings.connections_limit - m_ses.num_connections()) - , m_ses.m_half_open.free_slots()) - , m_ses.m_boost_connections - m_ses.m_settings.connection_speed); - - while (want_more_peers() && conns > 0) - { - if (!m_policy.connect_one_peer(m_ses.session_time())) break; - // increase m_ses.m_boost_connections for each connection - // attempt. This will be deducted from the connect speed - // the next time session_impl::on_tick() is triggered - --conns; - ++m_ses.m_boost_connections; - } - } + do_connect_boost(); state_updated(); } + void torrent::do_connect_boost() + { + if (!m_need_connect_boost) return; + + m_need_connect_boost = false; + // this is the first tracker response for this torrent + // instead of waiting one second for session_impl::on_tick() + // to be called, connect to a few peers immediately + int conns = (std::min)((std::min)((std::min)(m_ses.m_settings.torrent_connect_boost + , m_ses.m_settings.connections_limit - m_ses.num_connections()) + , m_ses.m_half_open.free_slots()) + , m_ses.m_boost_connections - m_ses.m_settings.connection_speed); + + while (want_more_peers() && conns > 0) + { + if (!m_policy.connect_one_peer(m_ses.session_time())) break; + // increase m_ses.m_boost_connections for each connection + // attempt. This will be deducted from the connect speed + // the next time session_impl::on_tick() is triggered + --conns; + ++m_ses.m_boost_connections; + } + + if (want_more_peers()) m_ses.prioritize_connections(shared_from_this()); + } + ptime torrent::next_announce() const { return m_waiting_tracker?m_tracker_timer.expires_at():min_time(); @@ -6184,7 +6195,7 @@ namespace libtorrent // under a different limit with the auto-manager. Make sure we // update auto-manage torrents in that case if (m_auto_managed) - m_ses.m_auto_manage_time_scaler = 2; + m_ses.trigger_auto_manage(); } // this is called when we were finished, but some files were @@ -6303,7 +6314,7 @@ namespace libtorrent { // if this is an auto managed torrent, force a recalculation // of which torrents to have active - m_ses.m_auto_manage_time_scaler = 2; + m_ses.trigger_auto_manage(); } if (!is_seed()) @@ -6313,7 +6324,7 @@ namespace libtorrent // if we just finished checking and we're not a seed, we are // likely to be unpaused - m_ses.m_auto_manage_time_scaler = 2; + m_ses.trigger_auto_manage(); if (is_finished() && m_state != torrent_status::finished) finished(); @@ -6858,7 +6869,7 @@ namespace libtorrent TORRENT_ASSERT(m_ses.is_network_thread()); if (!m_error) return; bool checking_files = should_check_files(); - m_ses.m_auto_manage_time_scaler = 2; + m_ses.trigger_auto_manage(); m_error = error_code(); m_error_file.clear(); @@ -6923,7 +6934,7 @@ namespace libtorrent // recalculate which torrents should be // paused - m_ses.m_auto_manage_time_scaler = 2; + m_ses.trigger_auto_manage(); if (!checking_files && should_check_files()) { @@ -7199,7 +7210,7 @@ namespace libtorrent // if this torrent was just paused // we might have to resume some other auto-managed torrent - m_ses.m_auto_manage_time_scaler = 2; + m_ses.trigger_auto_manage(); } #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING || defined TORRENT_LOGGING