From ffecb32b81342b471022e72ee1653188531040d9 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 29 Mar 2008 19:39:24 +0000 Subject: [PATCH] made a bias to give connection attempts to downloading torrents with few peers. Should accelerate downloads on windows (where there's a half-open connection limit) --- ChangeLog | 2 + include/libtorrent/torrent.hpp | 14 ++++ src/session_impl.cpp | 126 ++++++++++++++++++++++----------- src/torrent.cpp | 16 ++++- 4 files changed, 116 insertions(+), 42 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8f3918459..30c44cecb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ + * Better bias to give connections to downloading torrents + with fewer peers. * Optimized resource usage (removed the checking thread) * Support to bind outgoing connections to specific ports * Disk cache support. diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index bca4a9202..281f26032 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -280,6 +280,7 @@ namespace libtorrent bool want_more_peers() const; bool try_connect_peer(); + void give_connect_points(int points); // the number of peers that belong to this torrent int num_peers() const { return (int)m_connections.size(); } @@ -816,6 +817,19 @@ namespace libtorrent // total_done - m_initial_done <= total_payload_download size_type m_initial_done; #endif + // this is the deficit counter in the Deficit Round Robin + // used to determine which torrent gets the next + // connection attempt. See: + // http://www.ecs.umass.edu/ece/wolf/courses/ECE697J/papers/DRR.pdf + // The quanta assigned to each torrent depends on the torrents + // priority, whether it's seed and the number of connected + // peers it has. This has the effect that some torrents + // will have more connection attempts than other. Each + // connection attempt costs 100 points from the deficit + // counter. points are deducted in try_connect_peer and + // increased in give_connect_points. Outside of the + // torrent object, these points are called connect_points. + int m_deficit_counter; policy m_policy; }; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 0c10808b1..71d9bc8a7 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -847,7 +847,72 @@ namespace aux { << std::endl; #endif + // -------------------------------------------------------------- + // second_tick every torrent + // -------------------------------------------------------------- + + int congested_torrents = 0; + int uncongested_torrents = 0; + + // count the number of seeding torrents vs. downloading + // torrents we are running + int num_seeds = 0; + int num_downloads = 0; + + // count the number of peers of downloading torrents + int num_downloads_peers = 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(); + i != m_torrents.end();) + { + torrent& t = *i->second; + TORRENT_ASSERT(!t.is_aborted()); + if (t.bandwidth_queue_size(peer_connection::upload_channel)) + ++congested_torrents; + else + ++uncongested_torrents; + + if (t.is_finished()) + { + ++num_seeds; + } + else + { + ++num_downloads; + num_downloads_peers += t.num_peers(); + } + + if (t.should_request()) + { + tracker_request req = t.generate_tracker_request(); + req.listen_port = 0; + if (!m_listen_sockets.empty()) + req.listen_port = m_listen_sockets.front().external_port; + req.key = m_key; + m_tracker_manager.queue_request(m_io_service, m_half_open, req + , t.tracker_login(), m_listen_interface.address(), i->second); + + if (m_alerts.should_post(alert::info)) + { + m_alerts.post_alert( + tracker_announce_alert( + t.get_handle(), "tracker announce")); + } + } + + t.second_tick(m_stat, tick_interval); + ++i; + } + + m_stat.second_tick(tick_interval); + + // -------------------------------------------------------------- + // connect new peers + // -------------------------------------------------------------- + // let torrents connect to peers if they want to // if there are any torrents and any free slots @@ -864,6 +929,9 @@ namespace aux { // this is the maximum number of connections we will // attempt this tick int max_connections = m_settings.connection_speed; + int average_peers = 0; + 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())) @@ -877,6 +945,21 @@ namespace aux { torrent& t = *i->second; if (t.want_more_peers()) { + int connect_points = 100; + // have a bias against torrents with more peers + // than average + if (!t.is_seed() && t.num_peers() > average_peers) + connect_points /= 2; + // if this is a seed and there is a torrent that + // is downloading, lower the rate at which this + // torrent gets connections. + // dividing by num_seeds will have the effect + // that all seed will get as many connections + // together, as a single downloading torrent. + if (t.is_seed() && num_downloads > 0) + connect_points /= num_seeds + 1; + if (connect_points <= 0) connect_points = 1; + t.give_connect_points(connect_points); try { if (t.try_connect_peer()) @@ -904,9 +987,9 @@ namespace aux { i = m_torrents.begin(); m_next_connect_torrent = 0; } - // if we have gone one whole loop without + // if we have gone two whole loops without // handing out a single connection, break - if (steps_since_last_connect > num_torrents) break; + if (steps_since_last_connect > num_torrents * 2) break; // if there are no more free connection slots, abort if (free_slots <= -m_half_open.limit()) break; // if we should not make any more connections @@ -953,45 +1036,6 @@ namespace aux { c.keep_alive(); } - int congested_torrents = 0; - int uncongested_torrents = 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(); - i != m_torrents.end();) - { - torrent& t = *i->second; - TORRENT_ASSERT(!t.is_aborted()); - if (t.bandwidth_queue_size(peer_connection::upload_channel)) - ++congested_torrents; - else - ++uncongested_torrents; - - if (t.should_request()) - { - tracker_request req = t.generate_tracker_request(); - req.listen_port = 0; - if (!m_listen_sockets.empty()) - req.listen_port = m_listen_sockets.front().external_port; - req.key = m_key; - m_tracker_manager.queue_request(m_io_service, m_half_open, req - , t.tracker_login(), m_listen_interface.address(), i->second); - - if (m_alerts.should_post(alert::info)) - { - m_alerts.post_alert( - tracker_announce_alert( - t.get_handle(), "tracker announce")); - } - } - - // second_tick() will set the used upload quota - t.second_tick(m_stat, tick_interval); - ++i; - } - - m_stat.second_tick(tick_interval); - // -------------------------------------------------------------- // unchoke set and optimistic unchoke calculations // -------------------------------------------------------------- diff --git a/src/torrent.cpp b/src/torrent.cpp index c47762c64..14c99a7f8 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -204,6 +204,7 @@ namespace libtorrent , m_max_uploads((std::numeric_limits::max)()) , m_num_uploads(0) , m_max_connections((std::numeric_limits::max)()) + , m_deficit_counter(0) , m_policy(this) { #ifndef NDEBUG @@ -268,6 +269,7 @@ namespace libtorrent , m_max_uploads((std::numeric_limits::max)()) , m_num_uploads(0) , m_max_connections((std::numeric_limits::max)()) + , m_deficit_counter(0) , m_policy(this) { #ifndef NDEBUG @@ -2312,6 +2314,7 @@ namespace libtorrent TORRENT_ASSERT(peerinfo); TORRENT_ASSERT(peerinfo->connection == 0); + peerinfo->connected = time_now(); #ifndef NDEBUG // this asserts that we don't have duplicates in the policy's peer list @@ -3269,7 +3272,18 @@ namespace libtorrent bool torrent::try_connect_peer() { TORRENT_ASSERT(want_more_peers()); - return m_policy.connect_one_peer(); + if (m_deficit_counter < 100) return false; + m_deficit_counter -= 100; + bool ret = m_policy.connect_one_peer(); + return ret; + } + + void torrent::give_connect_points(int points) + { + TORRENT_ASSERT(points <= 100); + TORRENT_ASSERT(points > 0); + TORRENT_ASSERT(want_more_peers()); + m_deficit_counter += points; } void torrent::async_verify_piece(int piece_index, boost::function const& f)