changed the optimistic disconnect logic to be more efficient and configurable

This commit is contained in:
Arvid Norberg 2008-05-12 05:17:11 +00:00
parent eabe9cad2d
commit f2ac4db1af
7 changed files with 113 additions and 66 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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)
{

View File

@ -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);
}
}
}
}

View File

@ -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();