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)
This commit is contained in:
parent
2014e312b1
commit
ffecb32b81
|
@ -1,3 +1,5 @@
|
||||||
|
* Better bias to give connections to downloading torrents
|
||||||
|
with fewer peers.
|
||||||
* Optimized resource usage (removed the checking thread)
|
* Optimized resource usage (removed the checking thread)
|
||||||
* Support to bind outgoing connections to specific ports
|
* Support to bind outgoing connections to specific ports
|
||||||
* Disk cache support.
|
* Disk cache support.
|
||||||
|
|
|
@ -280,6 +280,7 @@ namespace libtorrent
|
||||||
|
|
||||||
bool want_more_peers() const;
|
bool want_more_peers() const;
|
||||||
bool try_connect_peer();
|
bool try_connect_peer();
|
||||||
|
void give_connect_points(int points);
|
||||||
|
|
||||||
// the number of peers that belong to this torrent
|
// the number of peers that belong to this torrent
|
||||||
int num_peers() const { return (int)m_connections.size(); }
|
int num_peers() const { return (int)m_connections.size(); }
|
||||||
|
@ -816,6 +817,19 @@ namespace libtorrent
|
||||||
// total_done - m_initial_done <= total_payload_download
|
// total_done - m_initial_done <= total_payload_download
|
||||||
size_type m_initial_done;
|
size_type m_initial_done;
|
||||||
#endif
|
#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;
|
policy m_policy;
|
||||||
};
|
};
|
||||||
|
|
|
@ -847,7 +847,72 @@ namespace aux {
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
#endif
|
#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
|
// let torrents connect to peers if they want to
|
||||||
// if there are any torrents and any free slots
|
// if there are any torrents and any free slots
|
||||||
|
|
||||||
|
@ -864,6 +929,9 @@ namespace aux {
|
||||||
// this is the maximum number of connections we will
|
// this is the maximum number of connections we will
|
||||||
// attempt this tick
|
// attempt this tick
|
||||||
int max_connections = m_settings.connection_speed;
|
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();
|
torrent_map::iterator i = m_torrents.begin();
|
||||||
if (m_next_connect_torrent < int(m_torrents.size()))
|
if (m_next_connect_torrent < int(m_torrents.size()))
|
||||||
|
@ -877,6 +945,21 @@ namespace aux {
|
||||||
torrent& t = *i->second;
|
torrent& t = *i->second;
|
||||||
if (t.want_more_peers())
|
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
|
try
|
||||||
{
|
{
|
||||||
if (t.try_connect_peer())
|
if (t.try_connect_peer())
|
||||||
|
@ -904,9 +987,9 @@ namespace aux {
|
||||||
i = m_torrents.begin();
|
i = m_torrents.begin();
|
||||||
m_next_connect_torrent = 0;
|
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
|
// 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 there are no more free connection slots, abort
|
||||||
if (free_slots <= -m_half_open.limit()) break;
|
if (free_slots <= -m_half_open.limit()) break;
|
||||||
// if we should not make any more connections
|
// if we should not make any more connections
|
||||||
|
@ -953,45 +1036,6 @@ namespace aux {
|
||||||
c.keep_alive();
|
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
|
// unchoke set and optimistic unchoke calculations
|
||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
|
@ -204,6 +204,7 @@ namespace libtorrent
|
||||||
, m_max_uploads((std::numeric_limits<int>::max)())
|
, m_max_uploads((std::numeric_limits<int>::max)())
|
||||||
, m_num_uploads(0)
|
, m_num_uploads(0)
|
||||||
, m_max_connections((std::numeric_limits<int>::max)())
|
, m_max_connections((std::numeric_limits<int>::max)())
|
||||||
|
, m_deficit_counter(0)
|
||||||
, m_policy(this)
|
, m_policy(this)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -268,6 +269,7 @@ namespace libtorrent
|
||||||
, m_max_uploads((std::numeric_limits<int>::max)())
|
, m_max_uploads((std::numeric_limits<int>::max)())
|
||||||
, m_num_uploads(0)
|
, m_num_uploads(0)
|
||||||
, m_max_connections((std::numeric_limits<int>::max)())
|
, m_max_connections((std::numeric_limits<int>::max)())
|
||||||
|
, m_deficit_counter(0)
|
||||||
, m_policy(this)
|
, m_policy(this)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
@ -2312,6 +2314,7 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(peerinfo);
|
TORRENT_ASSERT(peerinfo);
|
||||||
TORRENT_ASSERT(peerinfo->connection == 0);
|
TORRENT_ASSERT(peerinfo->connection == 0);
|
||||||
|
|
||||||
peerinfo->connected = time_now();
|
peerinfo->connected = time_now();
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// this asserts that we don't have duplicates in the policy's peer list
|
// 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()
|
bool torrent::try_connect_peer()
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(want_more_peers());
|
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<void(bool)> const& f)
|
void torrent::async_verify_piece(int piece_index, boost::function<void(bool)> const& f)
|
||||||
|
|
Loading…
Reference in New Issue