diff --git a/docs/manual.html b/docs/manual.html index 227f04366..dcd3303fa 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -2265,6 +2265,8 @@ struct torrent_status int seeding_time; int seed_rank; + + int last_scrape; };

progress is a value in the range [0, 1], that represents the progress of the @@ -2421,6 +2423,8 @@ across sessions.

seed_rank is a rank of how important it is to seed the torrent, it is used to determine which torrents to seed and which to queue. It is based on the peer to seed ratio from the tracker scrape. For more information, see queuing.

+

last_scrape is the number of seconds since this torrent acquired scrape data. +If it has never done that, this value is -1.

peer_info

@@ -2801,6 +2805,9 @@ struct session_settings float seed_time_ratio_limit; int seed_time_limit; bool close_redundant_connections; + + int auto_scrape_interval; + int auto_scrape_min_interval; };

user_agent this is the client identification to the tracker. @@ -2978,6 +2985,15 @@ See queuing.

connections where both ends have no utility in keeping the connection open. For instance if both ends have completed their downloads, there's no point in keeping it open. This defaults to true.

+

auto_scrape_interval is the number of seconds between scrapes of +queued torrents (auto managed and paused torrents). Auto managed +torrents that are paused, are scraped regularly in order to keep +track of their downloader/seed ratio. This ratio is used to determine +which torrents to seed and which to pause.

+

auto_scrape_min_interval is the minimum number of seconds between any +automatic scrape (regardless of torrent). In case there are a large number +of paused auto managed torrents, this puts a limit on how often a scrape +request is sent.

pe_settings

diff --git a/docs/manual.rst b/docs/manual.rst index 508407c98..098f9daf2 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -2229,6 +2229,8 @@ It contains the following fields:: int seeding_time; int seed_rank; + + int last_scrape; }; ``progress`` is a value in the range [0, 1], that represents the progress of the @@ -2404,6 +2406,9 @@ across sessions. to determine which torrents to seed and which to queue. It is based on the peer to seed ratio from the tracker scrape. For more information, see queuing_. +``last_scrape`` is the number of seconds since this torrent acquired scrape data. +If it has never done that, this value is -1. + peer_info ========= @@ -2784,6 +2789,9 @@ that will be sent to the tracker. The user-agent is a good way to identify your float seed_time_ratio_limit; int seed_time_limit; bool close_redundant_connections; + + int auto_scrape_interval; + int auto_scrape_min_interval; }; ``user_agent`` this is the client identification to the tracker. @@ -3009,6 +3017,17 @@ connections where both ends have no utility in keeping the connection open. For instance if both ends have completed their downloads, there's no point in keeping it open. This defaults to ``true``. +``auto_scrape_interval`` is the number of seconds between scrapes of +queued torrents (auto managed and paused torrents). Auto managed +torrents that are paused, are scraped regularly in order to keep +track of their downloader/seed ratio. This ratio is used to determine +which torrents to seed and which to pause. + +``auto_scrape_min_interval`` is the minimum number of seconds between any +automatic scrape (regardless of torrent). In case there are a large number +of paused auto managed torrents, this puts a limit on how often a scrape +request is sent. + pe_settings =========== diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 92d72d96c..4875500ec 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1278,8 +1278,9 @@ int main(int ac, char* av[]) << "swarm: " << to_string(downloaders, 4) << ":" << to_string(seeds, 4) << " bw queue: (" << s.up_bandwidth_queue << " | " << s.down_bandwidth_queue << ") " "all-time (Rx: " << esc("32") << add_suffix(s.all_time_download) << term - << " Tx: " << esc("31") << add_suffix(s.all_time_upload) << term << ") " << std::hex << s.seed_rank << std::dec << "\n" - << esc("0"); + << " Tx: " << esc("31") << add_suffix(s.all_time_upload) << term << ") " + << std::hex << s.seed_rank << std::dec << " " + << s.last_scrape << "\n" << esc("0"); if (s.state != torrent_status::seeding) { diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 4602e9d6d..20e2a9860 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -489,6 +489,11 @@ namespace libtorrent // from the torrent with the most peers int m_disconnect_time_scaler; + // when this scaler reaches zero, it will + // scrape one of the auto managed, paused, + // torrents. + int m_auto_scrape_time_scaler; + // statistics gathered from all torrents. stat m_stat; diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 744b299d7..30e76b825 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -133,6 +133,8 @@ namespace libtorrent , peer_turnover(1 / 50.f) , peer_turnover_cutoff(1.f) , close_redundant_connections(true) + , auto_scrape_interval(1800) + , auto_scrape_min_interval(300) {} // this is the user agent that will be sent to the tracker @@ -392,6 +394,14 @@ namespace libtorrent // are closed. for instance if both ends have completed // their downloads bool close_redundant_connections; + + // the number of seconds between scrapes of + // queued torrents (auto managed and paused) + int auto_scrape_interval; + + // the minimum number of seconds between any + // automatic scrape (regardless of torrent) + int auto_scrape_min_interval; }; #ifndef TORRENT_DISABLE_DHT diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index cb8f606ae..4ad5b617a 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -355,6 +355,7 @@ namespace libtorrent void force_tracker_request(); void force_tracker_request(ptime); void scrape_tracker(); + ptime const& last_scrape() const { return m_last_scrape; } // sets the username and password that will be sent to // the tracker @@ -614,6 +615,10 @@ namespace libtorrent // recently was started, to avoid oscillation ptime m_started; + // the last time we initiated a scrape request to + // one of the trackers in this torrent + ptime m_last_scrape; + boost::intrusive_ptr m_torrent_file; tracker_request::event_t m_event; diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index db9952735..e6e7e55f4 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -119,6 +119,7 @@ namespace libtorrent , active_time(0) , seeding_time(0) , seed_rank(0) + , last_scrape(0) {} enum state_t @@ -259,6 +260,10 @@ namespace libtorrent // higher value means more important to seed int seed_rank; + + // number of seconds since last scrape, or -1 if + // there hasn't been a scrape + int last_scrape; }; struct TORRENT_EXPORT block_info diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 83ff762b2..5e70cb6e7 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -166,6 +166,7 @@ namespace aux { , m_auto_manage_time_scaler(0) , m_optimistic_unchoke_time_scaler(0) , m_disconnect_time_scaler(90) + , m_auto_scrape_time_scaler(180) , m_incoming_connection(false) , m_last_tick(time_now()) , m_torrent_sequence(0) @@ -1012,7 +1013,6 @@ namespace aux { << m_disk_thread.disk_allocations() << "\t" << std::endl; #endif - // -------------------------------------------------------------- // second_tick every torrent // -------------------------------------------------------------- @@ -1028,6 +1028,9 @@ namespace aux { // count the number of peers of downloading torrents int num_downloads_peers = 0; + torrent_map::iterator least_recently_scraped = m_torrents.begin(); + int num_paused_auto_managed = 0; + // check each torrent for tracker updates // TODO: do this in a timer-event in each torrent instead for (torrent_map::iterator i = m_torrents.begin(); @@ -1040,6 +1043,17 @@ namespace aux { else ++uncongested_torrents; + if (t.is_auto_managed() && t.is_paused()) + { + ++num_paused_auto_managed; + if (!least_recently_scraped->second->is_auto_managed() + || !least_recently_scraped->second->is_paused() + || least_recently_scraped->second->last_scrape() > t.last_scrape()) + { + least_recently_scraped = i; + } + } + if (t.is_finished()) { ++num_seeds; @@ -1078,7 +1092,23 @@ namespace aux { m_stat.second_tick(tick_interval); - + // -------------------------------------------------------------- + // scrape paused torrents that are auto managed + // -------------------------------------------------------------- + --m_auto_scrape_time_scaler; + if (m_auto_scrape_time_scaler <= 0) + { + m_auto_scrape_time_scaler = m_settings.auto_scrape_interval + / (std::max)(1, num_paused_auto_managed); + if (m_auto_scrape_time_scaler < m_settings.auto_scrape_min_interval) + m_auto_scrape_time_scaler = m_settings.auto_scrape_min_interval; + + if (least_recently_scraped != m_torrents.end()) + { + least_recently_scraped->second->scrape_tracker(); + } + } + // -------------------------------------------------------------- // connect new peers // -------------------------------------------------------------- @@ -1189,7 +1219,7 @@ namespace aux { #if defined(TORRENT_VERBOSE_LOGGING) (*c.m_logger) << "*** CONNECTION TIMED OUT\n"; #endif - c.disconnect("timed out: inactive", true); + c.disconnect("timed out: inactive", 1); continue; } diff --git a/src/torrent.cpp b/src/torrent.cpp index 476ca25cc..686e984a4 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -153,6 +153,7 @@ namespace libtorrent , m_total_uploaded(0) , m_total_downloaded(0) , m_started(time_now()) + , m_last_scrape(min_time()) , m_torrent_file(tf) , m_event(tracker_request::started) , m_storage(0) @@ -227,6 +228,7 @@ namespace libtorrent , m_total_uploaded(0) , m_total_downloaded(0) , m_started(time_now()) + , m_last_scrape(min_time()) , m_torrent_file(new torrent_info(info_hash)) , m_event(tracker_request::started) , m_storage(0) @@ -754,6 +756,8 @@ namespace libtorrent req.url = m_trackers[m_currently_trying_tracker].url; m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this()); + + m_last_scrape = time_now(); } // returns true if it is time for this torrent to make another @@ -832,6 +836,8 @@ namespace libtorrent if (complete >= 0) m_complete = complete; if (incomplete >= 0) m_incomplete = incomplete; + if (complete >= 0 && incomplete >= 0) + m_last_scrape = time_now(); // connect to random peers from the list std::random_shuffle(peer_list.begin(), peer_list.end()); @@ -3788,8 +3794,18 @@ namespace libtorrent , m_have_pieces.end() , 0) == m_num_pieces); + ptime now = time_now(); + torrent_status st; + if (m_last_scrape == min_time()) + { + st.last_scrape = -1; + } + else + { + st.last_scrape = total_seconds(now - m_last_scrape); + } st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size(); st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size(); @@ -3837,7 +3853,7 @@ namespace libtorrent st.upload_payload_rate = m_stat.upload_payload_rate(); st.next_announce = boost::posix_time::seconds( - total_seconds(next_announce() - time_now())); + total_seconds(next_announce() - now)); if (st.next_announce.is_negative()) st.next_announce = boost::posix_time::seconds(0);