diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index c679b480d..3934f8457 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -515,6 +515,19 @@ namespace libtorrent --m_disk_queues[channel]; } + void inc_active_downloading() { ++m_num_active_downloading; } + void dec_active_downloading() + { + TORRENT_ASSERT(m_num_active_downloading > 0); + --m_num_active_downloading; + } + void inc_active_finished() { ++m_num_active_finished; } + void dec_active_finished() + { + TORRENT_ASSERT(m_num_active_finished > 0); + --m_num_active_finished; + } + #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS bool in_state_updates(boost::shared_ptr t) { @@ -681,6 +694,13 @@ namespace libtorrent torrent_map m_torrents; std::map > m_uuids; + // counters of how many of the active (non-paused) torrents + // are finished and downloading. This is used to weigh the + // priority of downloading and finished torrents when connecting + // more peers. + int m_num_active_downloading; + int m_num_active_finished; + typedef std::list > check_queue_t; // this has all torrents that wants to be checked in it diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 6dcdc67d4..0bfc6e265 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -260,6 +260,20 @@ namespace libtorrent void force_recheck(); void save_resume_data(int flags); + bool is_active_download() const + { + return (m_state == torrent_status::downloading + || m_state == torrent_status::downloading_metadata) + && m_allow_peers; + } + + bool is_active_finished() const + { + return (m_state == torrent_status::finished + || m_state == torrent_status::seeding) + && m_allow_peers; + } + bool need_save_resume_data() const { // save resume data every 15 minutes regardless, just to diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 59d38d4e5..d5cbbac06 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -610,6 +610,8 @@ namespace aux { , m_upload_rate(peer_connection::upload_channel) #endif , m_tracker_manager(*this, m_proxy) + , m_num_active_downloading(0) + , m_num_active_finished(0) , m_listen_port_retries(listen_port_range.second - listen_port_range.first) #if TORRENT_USE_I2P , m_i2p_conn(m_io_service) @@ -3430,16 +3432,17 @@ namespace aux { torrent& t = *m_next_connect_torrent->second; if (t.want_more_peers()) { + TORRENT_ASSERT(t.allows_peers()); // have a bias to give more connection attempts // to downloading torrents than seed, and even // more to downloading torrents with less than // average number of connections int num_attempts = 1; - if (!t.is_seed()) + if (!t.is_finished()) { - ++num_attempts; - if (t.num_peers() < average_peers) - ++num_attempts; + // TODO: make this bias configurable + TORRENT_ASSERT(m_num_active_downloading > 0); + num_attempts += m_num_active_finished / m_num_active_downloading; } for (int i = 0; i < num_attempts; ++i) { @@ -4209,6 +4212,8 @@ namespace aux { void session_impl::recalculate_auto_managed_torrents() { + INVARIANT_CHECK; + // these vectors are filled with auto managed torrents std::vector downloaders; downloaders.reserve(m_torrents.size()); @@ -4301,7 +4306,6 @@ namespace aux { auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit , hard_limit, num_seeds); } - } void session_impl::recalculate_optimistic_unchoke_slots() @@ -4996,6 +5000,8 @@ namespace aux { void session_impl::remove_torrent(const torrent_handle& h, int options) { + INVARIANT_CHECK; + boost::shared_ptr tptr = h.m_torrent.lock(); if (!tptr) return; @@ -5037,6 +5043,13 @@ namespace aux { if (options & session::delete_files) t.delete_files(); + bool is_active_download = tptr->is_active_download(); + bool is_active_finished = tptr->is_active_finished(); + + // update finished and downloading counters + if (is_active_download) dec_active_downloading(); + if (is_active_finished) dec_active_finished(); + #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS sha1_hash i_hash = t.torrent_file().info_hash(); #endif @@ -6064,20 +6077,29 @@ namespace aux { // TORRENT_ASSERT(m_queued_for_checking.size() == num_queued_for_checking); std::set unique; + int num_active_downloading = 0; + int num_active_finished = 0; int total_downloaders = 0; for (torrent_map::const_iterator i = m_torrents.begin() , end(m_torrents.end()); i != end; ++i) { - int pos = i->second->queue_position(); + boost::shared_ptr t = i->second; + if (t->is_active_download()) ++num_active_downloading; + else if (t->is_active_finished()) ++num_active_finished; + + int pos = t->queue_position(); if (pos < 0) { TORRENT_ASSERT(pos == -1); continue; } ++total_downloaders; - unique.insert(i->second->queue_position()); + + unique.insert(t->queue_position()); } TORRENT_ASSERT(int(unique.size()) == total_downloaders); + TORRENT_ASSERT(num_active_downloading == m_num_active_downloading); + TORRENT_ASSERT(num_active_finished == m_num_active_finished); std::set unique_peers; TORRENT_ASSERT(m_settings.connections_limit > 0); diff --git a/src/torrent.cpp b/src/torrent.cpp index b06233e93..39d58319c 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -441,6 +441,10 @@ namespace libtorrent if (!m_apply_ip_filter) ++m_ses.m_non_filtered_torrents; + // update finished and downloading counters + if (is_active_download()) m_ses.inc_active_downloading(); + if (is_active_finished()) m_ses.inc_active_finished(); + if (!p.ti || !p.ti->is_valid()) { // we don't have metadata for this torrent. We'll download @@ -5059,7 +5063,7 @@ namespace libtorrent int paused_ = rd.dict_find_int_value("paused", -1); if (paused_ != -1) { - m_allow_peers = !paused_; + set_allow_peers(!paused_); m_announce_to_dht = !paused_; m_announce_to_trackers = !paused_; m_announce_to_lsd = !paused_; @@ -7002,7 +7006,7 @@ namespace libtorrent INVARIANT_CHECK; if (!m_allow_peers) return; - if (!graceful) m_allow_peers = false; + if (!graceful) set_allow_peers(false); m_announce_to_dht = false; m_announce_to_trackers = false; m_announce_to_lsd = false; @@ -7134,10 +7138,19 @@ namespace libtorrent if (m_allow_peers == b && m_graceful_pause_mode == graceful) return; + bool was_active_download = is_active_download(); + bool was_active_finished = is_active_finished(); + m_allow_peers = b; if (!m_ses.is_paused()) m_graceful_pause_mode = graceful; + // update finished and downloading counters + if (was_active_download && !is_active_download()) m_ses.dec_active_downloading(); + else if (!was_active_download && is_active_download()) m_ses.inc_active_downloading(); + if (was_active_finished && !is_active_finished()) m_ses.dec_active_finished(); + else if (!was_active_finished && is_active_finished()) m_ses.inc_active_finished(); + if (!b) { m_announce_to_dht = false; @@ -7160,7 +7173,7 @@ namespace libtorrent && m_announce_to_dht && m_announce_to_trackers && m_announce_to_lsd) return; - m_allow_peers = true; + set_allow_peers(true); m_announce_to_dht = true; m_announce_to_trackers = true; m_announce_to_lsd = true; @@ -8244,8 +8257,18 @@ namespace libtorrent if (int(m_state) == s) return; if (m_ses.m_alerts.should_post()) m_ses.m_alerts.post_alert(state_changed_alert(get_handle(), s, (torrent_status::state_t)m_state)); + + bool was_active_download = is_active_download(); + bool was_active_finished = is_active_finished(); + m_state = s; + // update finished and downloading counters + if (was_active_download && !is_active_download()) m_ses.dec_active_downloading(); + else if (!was_active_download && is_active_download()) m_ses.inc_active_downloading(); + if (was_active_finished && !is_active_finished()) m_ses.dec_active_finished(); + else if (!was_active_finished && is_active_finished()) m_ses.inc_active_finished(); + state_updated(); #ifndef TORRENT_DISABLE_EXTENSIONS