changed the optimistic disconnect logic to be more efficient and configurable
This commit is contained in:
parent
eabe9cad2d
commit
f2ac4db1af
|
@ -242,6 +242,9 @@ namespace libtorrent
|
||||||
std::vector<int> const& allowed_fast();
|
std::vector<int> const& allowed_fast();
|
||||||
std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; }
|
std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; }
|
||||||
|
|
||||||
|
ptime connected_time() const { return m_connect; }
|
||||||
|
ptime last_received() const { return m_last_receive; }
|
||||||
|
|
||||||
void timed_out();
|
void timed_out();
|
||||||
// this will cause this peer_connection to be disconnected.
|
// this will cause this peer_connection to be disconnected.
|
||||||
void disconnect(char const* message);
|
void disconnect(char const* message);
|
||||||
|
|
|
@ -248,7 +248,6 @@ namespace libtorrent
|
||||||
const_iterator end_peer() const { return m_peers.end(); }
|
const_iterator end_peer() const { return m_peers.end(); }
|
||||||
|
|
||||||
bool connect_one_peer();
|
bool connect_one_peer();
|
||||||
bool disconnect_one_peer();
|
|
||||||
|
|
||||||
bool has_peer(policy::peer const* p) const;
|
bool has_peer(policy::peer const* p) const;
|
||||||
|
|
||||||
|
@ -267,7 +266,6 @@ namespace libtorrent
|
||||||
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||||
, address const& external_ip) const;
|
, address const& external_ip) const;
|
||||||
|
|
||||||
iterator find_disconnect_candidate();
|
|
||||||
iterator find_connect_candidate();
|
iterator find_connect_candidate();
|
||||||
|
|
||||||
bool is_connect_candidate(peer const& p, bool finished);
|
bool is_connect_candidate(peer const& p, bool finished);
|
||||||
|
|
|
@ -102,11 +102,7 @@ namespace libtorrent
|
||||||
, min_reconnect_time(60)
|
, min_reconnect_time(60)
|
||||||
, peer_connect_timeout(7)
|
, peer_connect_timeout(7)
|
||||||
, ignore_limits_on_local_network(true)
|
, ignore_limits_on_local_network(true)
|
||||||
#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
|
|
||||||
, connection_speed(2)
|
|
||||||
#else
|
|
||||||
, connection_speed(20)
|
, connection_speed(20)
|
||||||
#endif
|
|
||||||
, send_redundant_have(false)
|
, send_redundant_have(false)
|
||||||
, lazy_bitfields(true)
|
, lazy_bitfields(true)
|
||||||
, inactivity_timeout(600)
|
, inactivity_timeout(600)
|
||||||
|
@ -134,6 +130,9 @@ namespace libtorrent
|
||||||
, share_ratio_limit(2.f)
|
, share_ratio_limit(2.f)
|
||||||
, seed_time_ratio_limit(7.f)
|
, seed_time_ratio_limit(7.f)
|
||||||
, seed_time_limit(24 * 60 * 60) // 24 hours
|
, seed_time_limit(24 * 60 * 60) // 24 hours
|
||||||
|
, peer_turnover(1 / 50.f)
|
||||||
|
, peer_turnover_cutoff(1.f)
|
||||||
|
, close_redundant_connections(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// this is the user agent that will be sent to the tracker
|
// this is the user agent that will be sent to the tracker
|
||||||
|
@ -376,6 +375,23 @@ namespace libtorrent
|
||||||
float share_ratio_limit;
|
float share_ratio_limit;
|
||||||
float seed_time_ratio_limit;
|
float seed_time_ratio_limit;
|
||||||
int seed_time_limit;
|
int seed_time_limit;
|
||||||
|
|
||||||
|
// the percentage of peers to disconnect every
|
||||||
|
// 90 seconds (if we're at the peer limit)
|
||||||
|
// defaults to 1/50:th
|
||||||
|
float peer_turnover;
|
||||||
|
|
||||||
|
// when we are connected to more than
|
||||||
|
// limit * peer_turnover_enable peers
|
||||||
|
// disconnect peer_turnover fraction
|
||||||
|
// of the peers
|
||||||
|
float peer_turnover_cutoff;
|
||||||
|
|
||||||
|
// if this is true (default) connections where both
|
||||||
|
// ends have no utility in keeping the connection open
|
||||||
|
// are closed. for instance if both ends have completed
|
||||||
|
// their downloads
|
||||||
|
bool close_redundant_connections;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
|
|
|
@ -452,6 +452,7 @@ namespace libtorrent
|
||||||
void announce_piece(int index);
|
void announce_piece(int index);
|
||||||
|
|
||||||
void disconnect_all();
|
void disconnect_all();
|
||||||
|
int disconnect_peers(int num);
|
||||||
|
|
||||||
// this is called wheh the torrent has completed
|
// this is called wheh the torrent has completed
|
||||||
// the download. It will post an event, disconnect
|
// the download. It will post an event, disconnect
|
||||||
|
|
|
@ -421,49 +421,6 @@ namespace libtorrent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
policy::iterator policy::find_disconnect_candidate()
|
|
||||||
{
|
|
||||||
INVARIANT_CHECK;
|
|
||||||
|
|
||||||
iterator disconnect_peer = m_peers.end();
|
|
||||||
double slowest_transfer_rate = (std::numeric_limits<double>::max)();
|
|
||||||
|
|
||||||
ptime now = time_now();
|
|
||||||
|
|
||||||
for (iterator i = m_peers.begin();
|
|
||||||
i != m_peers.end(); ++i)
|
|
||||||
{
|
|
||||||
peer_connection* c = i->second.connection;
|
|
||||||
if (c == 0) continue;
|
|
||||||
if (c->is_disconnecting()) continue;
|
|
||||||
|
|
||||||
// never disconnect an interesting peer if we have a candidate that
|
|
||||||
// isn't interesting
|
|
||||||
if (disconnect_peer != m_peers.end()
|
|
||||||
&& c->is_interesting()
|
|
||||||
&& !disconnect_peer->second.connection->is_interesting())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
double transferred_amount
|
|
||||||
= (double)c->statistics().total_payload_download();
|
|
||||||
|
|
||||||
time_duration connected_time = now - i->second.connected;
|
|
||||||
|
|
||||||
double connected_time_in_seconds = total_seconds(connected_time);
|
|
||||||
|
|
||||||
double transfer_rate
|
|
||||||
= transferred_amount / (connected_time_in_seconds + 1);
|
|
||||||
|
|
||||||
// prefer to disconnect uninteresting peers, and secondly slow peers
|
|
||||||
if (transfer_rate <= slowest_transfer_rate)
|
|
||||||
{
|
|
||||||
slowest_transfer_rate = transfer_rate;
|
|
||||||
disconnect_peer = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return disconnect_peer;
|
|
||||||
}
|
|
||||||
|
|
||||||
policy::iterator policy::find_connect_candidate()
|
policy::iterator policy::find_connect_candidate()
|
||||||
{
|
{
|
||||||
// too expensive
|
// too expensive
|
||||||
|
@ -1074,19 +1031,6 @@ namespace libtorrent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool policy::disconnect_one_peer()
|
|
||||||
{
|
|
||||||
iterator p = find_disconnect_candidate();
|
|
||||||
if (p == m_peers.end())
|
|
||||||
return false;
|
|
||||||
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
|
|
||||||
(*p->second.connection->m_logger) << "*** CLOSING CONNECTION 'too many connections'\n";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
p->second.connection->disconnect("too many connections, closing");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is called whenever a peer connection is closed
|
// this is called whenever a peer connection is closed
|
||||||
void policy::connection_closed(const peer_connection& c)
|
void policy::connection_closed(const peer_connection& c)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1214,17 +1214,37 @@ namespace aux {
|
||||||
{
|
{
|
||||||
m_disconnect_time_scaler = 90;
|
m_disconnect_time_scaler = 90;
|
||||||
|
|
||||||
// every 90 seconds, disconnect the worst peer
|
// every 90 seconds, disconnect the worst peers
|
||||||
// if we have reached the connection limit
|
// if we have reached the connection limit
|
||||||
if (num_connections() >= max_connections() && !m_torrents.empty())
|
if (num_connections() >= max_connections() * m_settings.peer_turnover_cutoff
|
||||||
|
&& !m_torrents.empty())
|
||||||
{
|
{
|
||||||
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
|
torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end()
|
||||||
, bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1))
|
, bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1))
|
||||||
< bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2)));
|
< bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2)));
|
||||||
|
|
||||||
TORRENT_ASSERT(i != m_torrents.end());
|
TORRENT_ASSERT(i != m_torrents.end());
|
||||||
// TODO: make the number of peers a percentage of the number of connected peers
|
int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers()
|
||||||
i->second->get_policy().disconnect_one_peer();
|
* m_settings.peer_turnover), 1)
|
||||||
|
, i->second->get_policy().num_connect_candidates());
|
||||||
|
i->second->disconnect_peers(peers_to_disconnect);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if we haven't reached the global max. see if any torrent
|
||||||
|
// has reached its local limit
|
||||||
|
for (torrent_map::iterator i = m_torrents.begin()
|
||||||
|
, end(m_torrents.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
boost::shared_ptr<torrent> t = i->second;
|
||||||
|
if (t->num_peers() < t->max_connections() * m_settings.peer_turnover_cutoff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers()
|
||||||
|
* m_settings.peer_turnover), 1)
|
||||||
|
, i->second->get_policy().num_connect_candidates());
|
||||||
|
t->disconnect_peers(peers_to_disconnect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2732,6 +2732,71 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// this returns true if lhs is a better disconnect candidate than rhs
|
||||||
|
bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs)
|
||||||
|
{
|
||||||
|
// prefer to disconnect peers we're not interested in
|
||||||
|
if (lhs->is_interesting() != rhs->is_interesting())
|
||||||
|
return rhs->is_interesting();
|
||||||
|
|
||||||
|
// prefer to disconnect peers that are not seeds
|
||||||
|
if (lhs->is_seed() != rhs->is_seed())
|
||||||
|
return rhs->is_seed();
|
||||||
|
|
||||||
|
// prefer to disconnect peers that are on parole
|
||||||
|
if (lhs->on_parole() != rhs->on_parole())
|
||||||
|
return lhs->on_parole();
|
||||||
|
|
||||||
|
// prefer to disconnect peers that send data at a lower rate
|
||||||
|
size_type lhs_transferred = lhs->statistics().total_payload_download();
|
||||||
|
size_type rhs_transferred = rhs->statistics().total_payload_download();
|
||||||
|
|
||||||
|
if (lhs_transferred != rhs_transferred
|
||||||
|
&& lhs_transferred > 0
|
||||||
|
&& rhs_transferred > 0)
|
||||||
|
{
|
||||||
|
ptime now = time_now();
|
||||||
|
size_type lhs_time_connected = total_seconds(now - lhs->connected_time());
|
||||||
|
size_type rhs_time_connected = total_seconds(now - rhs->connected_time());
|
||||||
|
|
||||||
|
double lhs_rate = double(lhs_transferred) / (lhs_time_connected + 1);
|
||||||
|
double rhs_rate = double(rhs_transferred) / (rhs_time_connected + 1);
|
||||||
|
|
||||||
|
return lhs_rate < rhs_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// prefer to disconnect peers that chokes us
|
||||||
|
if (lhs->is_choked() != rhs->is_choked())
|
||||||
|
return lhs->is_choked();
|
||||||
|
|
||||||
|
return lhs->last_received() < rhs->last_received();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int torrent::disconnect_peers(int num)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
// buils a list of all connected peers and sort it by 'disconnectability'.
|
||||||
|
std::vector<peer_connection*> peers(m_connections.size());
|
||||||
|
std::copy(m_connections.begin(), m_connections.end(), peers.begin());
|
||||||
|
std::sort(peers.begin(), peers.end(), boost::bind(&compare_disconnect_peer, _1, _2));
|
||||||
|
|
||||||
|
// never disconnect peers that connected less than 90 seconds ago
|
||||||
|
ptime cut_off = time_now() - seconds(90);
|
||||||
|
|
||||||
|
for (std::vector<peer_connection*>::iterator i = peers.begin()
|
||||||
|
, end(peers.end()); i != end && ret < num; ++i)
|
||||||
|
{
|
||||||
|
peer_connection* p = *i;
|
||||||
|
if (p->connected_time() > cut_off) continue;
|
||||||
|
++ret;
|
||||||
|
p->disconnect("optimistic disconnect");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int torrent::bandwidth_throttle(int channel) const
|
int torrent::bandwidth_throttle(int channel) const
|
||||||
{
|
{
|
||||||
return m_bandwidth_limit[channel].throttle();
|
return m_bandwidth_limit[channel].throttle();
|
||||||
|
|
Loading…
Reference in New Issue