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& 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();
|
||||
// this will cause this peer_connection to be disconnected.
|
||||
void disconnect(char const* message);
|
||||
|
|
|
@ -248,7 +248,6 @@ namespace libtorrent
|
|||
const_iterator end_peer() const { return m_peers.end(); }
|
||||
|
||||
bool connect_one_peer();
|
||||
bool disconnect_one_peer();
|
||||
|
||||
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
|
||||
, address const& external_ip) const;
|
||||
|
||||
iterator find_disconnect_candidate();
|
||||
iterator find_connect_candidate();
|
||||
|
||||
bool is_connect_candidate(peer const& p, bool finished);
|
||||
|
|
|
@ -102,11 +102,7 @@ namespace libtorrent
|
|||
, min_reconnect_time(60)
|
||||
, peer_connect_timeout(7)
|
||||
, ignore_limits_on_local_network(true)
|
||||
#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
|
||||
, connection_speed(2)
|
||||
#else
|
||||
, connection_speed(20)
|
||||
#endif
|
||||
, send_redundant_have(false)
|
||||
, lazy_bitfields(true)
|
||||
, inactivity_timeout(600)
|
||||
|
@ -134,6 +130,9 @@ namespace libtorrent
|
|||
, share_ratio_limit(2.f)
|
||||
, seed_time_ratio_limit(7.f)
|
||||
, 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
|
||||
|
@ -376,6 +375,23 @@ namespace libtorrent
|
|||
float share_ratio_limit;
|
||||
float seed_time_ratio_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
|
||||
|
|
|
@ -452,6 +452,7 @@ namespace libtorrent
|
|||
void announce_piece(int index);
|
||||
|
||||
void disconnect_all();
|
||||
int disconnect_peers(int num);
|
||||
|
||||
// this is called wheh the torrent has completed
|
||||
// the download. It will post an event, disconnect
|
||||
|
|
|
@ -421,49 +421,6 @@ namespace libtorrent
|
|||
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()
|
||||
{
|
||||
// too expensive
|
||||
|
@ -1074,19 +1031,6 @@ namespace libtorrent
|
|||
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
|
||||
void policy::connection_closed(const peer_connection& c)
|
||||
{
|
||||
|
|
|
@ -1214,17 +1214,37 @@ namespace aux {
|
|||
{
|
||||
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 (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()
|
||||
, bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1))
|
||||
< bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2)));
|
||||
|
||||
TORRENT_ASSERT(i != m_torrents.end());
|
||||
// TODO: make the number of peers a percentage of the number of connected peers
|
||||
i->second->get_policy().disconnect_one_peer();
|
||||
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());
|
||||
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
|
||||
{
|
||||
return m_bandwidth_limit[channel].throttle();
|
||||
|
|
Loading…
Reference in New Issue