forked from premiere/premiere-libtorrent
scans at most 300 peers when finding a connect candidate. Supposedly fixes cpu spikes on large swarms
This commit is contained in:
parent
b73112682c
commit
228e225489
|
@ -260,8 +260,17 @@ namespace libtorrent
|
||||||
m_num_connect_candidates = 1;
|
m_num_connect_candidates = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void erase_peer(iterator i);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||||
|
, address const& external_ip) const;
|
||||||
|
|
||||||
|
// since the peer list can grow too large
|
||||||
|
// to scan all of it, start at this iterator
|
||||||
|
iterator m_round_robin;
|
||||||
|
|
||||||
iterator find_disconnect_candidate();
|
iterator find_disconnect_candidate();
|
||||||
iterator find_connect_candidate();
|
iterator find_connect_candidate();
|
||||||
|
|
||||||
|
|
193
src/policy.cpp
193
src/policy.cpp
|
@ -384,12 +384,26 @@ namespace libtorrent
|
||||||
, "blocked peer removed from peer list"));
|
, "blocked peer removed from peer list"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p) p->clear_peer(&i->second);
|
erase_peer(i++);
|
||||||
if (i->second.seed) --m_num_seeds;
|
|
||||||
m_peers.erase(i++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// any peer that is erased from m_peers will be
|
||||||
|
// erased through this function. This way we can make
|
||||||
|
// sure that any references to the peer are removed
|
||||||
|
// as well, such as in the piece picker.
|
||||||
|
void policy::erase_peer(iterator i)
|
||||||
|
{
|
||||||
|
if (m_torrent->has_picker())
|
||||||
|
m_torrent->picker().clear_peer(&i->second);
|
||||||
|
if (i->second.seed) --m_num_seeds;
|
||||||
|
if (is_connect_candidate(i->second, m_torrent->is_finished()))
|
||||||
|
--m_num_connect_candidates;
|
||||||
|
if (m_round_robin == i) ++m_round_robin;
|
||||||
|
|
||||||
|
m_peers.erase(i);
|
||||||
|
}
|
||||||
|
|
||||||
bool policy::is_connect_candidate(peer const& p, bool finished)
|
bool policy::is_connect_candidate(peer const& p, bool finished)
|
||||||
{
|
{
|
||||||
if (p.connection
|
if (p.connection
|
||||||
|
@ -450,16 +464,14 @@ namespace libtorrent
|
||||||
|
|
||||||
policy::iterator policy::find_connect_candidate()
|
policy::iterator policy::find_connect_candidate()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
// too expensive
|
||||||
|
// INVARIANT_CHECK;
|
||||||
|
|
||||||
ptime now = time_now();
|
ptime now = time_now();
|
||||||
ptime min_connect_time(now);
|
|
||||||
iterator candidate = m_peers.end();
|
iterator candidate = m_peers.end();
|
||||||
|
|
||||||
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
|
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
|
||||||
bool finished = m_torrent->is_finished();
|
bool finished = m_torrent->is_finished();
|
||||||
|
|
||||||
int min_cidr_distance = (std::numeric_limits<int>::max)();
|
|
||||||
address external_ip = m_torrent->session().external_address();
|
address external_ip = m_torrent->session().external_address();
|
||||||
|
|
||||||
// don't bias any particular peers when seeding
|
// don't bias any particular peers when seeding
|
||||||
|
@ -472,75 +484,35 @@ namespace libtorrent
|
||||||
external_ip = address_v4(bytes);
|
external_ip = address_v4(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
if (m_round_robin == iterator() || m_round_robin == m_peers.end())
|
||||||
int max_inet_as_rate = -1;
|
m_round_robin = m_peers.begin();
|
||||||
bool has_db = m_torrent->session().has_asnum_db();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int connect_candidates = 0;
|
for (int iterations = (std::min)(int(m_peers.size()), 300);
|
||||||
int seeds = 0;
|
iterations > 0; ++m_round_robin, --iterations)
|
||||||
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
|
|
||||||
{
|
{
|
||||||
if (i->second.seed) ++seeds;
|
if (m_round_robin == m_peers.end()) m_round_robin = m_peers.begin();
|
||||||
if (!is_connect_candidate(i->second, finished)) continue;
|
|
||||||
++connect_candidates;
|
if (!is_connect_candidate(m_round_robin->second, finished)) continue;
|
||||||
|
|
||||||
// prefer peers with lower failcount
|
|
||||||
if (candidate != m_peers.end()
|
if (candidate != m_peers.end()
|
||||||
&& candidate->second.failcount < i->second.failcount)
|
&& !compare_peer(candidate->second, m_round_robin->second, external_ip)) continue;
|
||||||
|
|
||||||
|
if (now - m_round_robin->second.connected <
|
||||||
|
seconds(m_round_robin->second.failcount * min_reconnect_time))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (now - i->second.connected < seconds(i->second.failcount * min_reconnect_time))
|
candidate = m_round_robin;
|
||||||
continue;
|
|
||||||
|
|
||||||
TORRENT_ASSERT(i->second.connected <= now);
|
|
||||||
|
|
||||||
// don't replace a candidate that is on the local
|
|
||||||
// network with one that isn't. Local peers should
|
|
||||||
// always be tried first
|
|
||||||
if (candidate != m_peers.end()
|
|
||||||
&& is_local(candidate->second.ip.address())
|
|
||||||
&& !is_local(i->second.ip.address()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (i->second.connected > min_connect_time) continue;
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_GEO_IP
|
|
||||||
if (!finished && has_db)
|
|
||||||
{
|
|
||||||
// don't bias fast peers when seeding
|
|
||||||
std::pair<const int, int>* inet_as = i->second.inet_as;
|
|
||||||
int peak_rate = inet_as ? inet_as->second : 0;
|
|
||||||
if (peak_rate <= max_inet_as_rate) continue;
|
|
||||||
max_inet_as_rate = peak_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_inet_as_rate <= 0)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
int distance = cidr_distance(external_ip, i->second.ip.address());
|
|
||||||
if (distance > min_cidr_distance) continue;
|
|
||||||
|
|
||||||
min_cidr_distance = distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
min_connect_time = i->second.connected;
|
|
||||||
candidate = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_num_connect_candidates = connect_candidates;
|
|
||||||
m_num_seeds = seeds;
|
|
||||||
TORRENT_ASSERT(min_connect_time <= now);
|
|
||||||
|
|
||||||
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
||||||
if (candidate != m_peers.end())
|
if (candidate != m_peers.end())
|
||||||
{
|
{
|
||||||
(*m_torrent->session().m_logger) << time_now_string()
|
(*m_torrent->session().m_logger) << time_now_string()
|
||||||
<< " *** FOUND CONNECTION CANDIDATE ["
|
<< " *** FOUND CONNECTION CANDIDATE ["
|
||||||
" ip: " << candidate->second.ip <<
|
" ip: " << candidate->second.ip <<
|
||||||
" d: " << min_cidr_distance <<
|
" d: " << cidr_distance(external_ip, candidate->second.ip.address()) <<
|
||||||
" external: " << external_ip <<
|
" external: " << external_ip <<
|
||||||
" t: " << total_seconds(time_now() - min_connect_time) <<
|
" t: " << total_seconds(time_now() - candidate->second.connected) <<
|
||||||
" ]\n";
|
" ]\n";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -554,10 +526,6 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_torrent->is_paused()) return;
|
if (m_torrent->is_paused()) return;
|
||||||
|
|
||||||
piece_picker* p = 0;
|
|
||||||
if (m_torrent->has_picker())
|
|
||||||
p = &m_torrent->picker();
|
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
bool pinged = false;
|
bool pinged = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -589,9 +557,7 @@ namespace libtorrent
|
||||||
&& !pe.banned
|
&& !pe.banned
|
||||||
&& now - pe.connected > minutes(120))
|
&& now - pe.connected > minutes(120))
|
||||||
{
|
{
|
||||||
if (p) p->clear_peer(&pe);
|
erase_peer(i++);
|
||||||
if (pe.seed) --m_num_seeds;
|
|
||||||
m_peers.erase(i++);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -599,52 +565,6 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
|
||||||
// maintain the number of connections
|
|
||||||
// -------------------------------------
|
|
||||||
/*
|
|
||||||
// count the number of connected peers except for peers
|
|
||||||
// that are currently in the process of disconnecting
|
|
||||||
int num_connected_peers = 0;
|
|
||||||
|
|
||||||
for (iterator i = m_peers.begin();
|
|
||||||
i != m_peers.end(); ++i)
|
|
||||||
{
|
|
||||||
if (i->connection && !i->connection->is_disconnecting())
|
|
||||||
++num_connected_peers;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_torrent->max_connections() != (std::numeric_limits<int>::max)())
|
|
||||||
{
|
|
||||||
int max_connections = m_torrent->max_connections();
|
|
||||||
|
|
||||||
if (num_connected_peers >= max_connections)
|
|
||||||
{
|
|
||||||
// every minute, disconnect the worst peer in hope of finding a better peer
|
|
||||||
|
|
||||||
ptime local_time = time_now();
|
|
||||||
if (m_last_optimistic_disconnect + seconds(120) <= local_time
|
|
||||||
&& find_connect_candidate() != m_peers.end())
|
|
||||||
{
|
|
||||||
m_last_optimistic_disconnect = local_time;
|
|
||||||
--max_connections; // this will have the effect of disconnecting the worst peer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// don't do a disconnect earlier than 1 minute after some peer was connected
|
|
||||||
m_last_optimistic_disconnect = time_now();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (num_connected_peers > max_connections)
|
|
||||||
{
|
|
||||||
bool ret = disconnect_one_peer();
|
|
||||||
(void)ret;
|
|
||||||
TORRENT_ASSERT(ret);
|
|
||||||
--num_connected_peers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// ------------------------
|
// ------------------------
|
||||||
// upload shift
|
// upload shift
|
||||||
// ------------------------
|
// ------------------------
|
||||||
|
@ -769,6 +689,9 @@ namespace libtorrent
|
||||||
"with higher priority, closing");
|
"with higher priority, closing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_num_connect_candidates > 0)
|
||||||
|
--m_num_connect_candidates;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -797,8 +720,6 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(i->second.connection);
|
TORRENT_ASSERT(i->second.connection);
|
||||||
if (!c.fast_reconnect())
|
if (!c.fast_reconnect())
|
||||||
i->second.connected = time_now();
|
i->second.connected = time_now();
|
||||||
if (m_num_connect_candidates > 0)
|
|
||||||
--m_num_connect_candidates;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,10 +744,7 @@ namespace libtorrent
|
||||||
p->connection->disconnect("duplicate connection");
|
p->connection->disconnect("duplicate connection");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (m_torrent->has_picker())
|
erase_peer(i);
|
||||||
m_torrent->picker().clear_peer(&i->second);
|
|
||||||
if (i->second.seed) --m_num_seeds;
|
|
||||||
m_peers.erase(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1406,5 +1324,38 @@ namespace libtorrent
|
||||||
return prev_amount_upload;
|
return prev_amount_upload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this returns true if lhs is a better connect candidate than rhs
|
||||||
|
bool policy::compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||||
|
, address const& external_ip) const
|
||||||
|
{
|
||||||
|
// prefer peers with lower failcount
|
||||||
|
if (lhs.failcount < rhs.failcount) return true;
|
||||||
|
if (lhs.failcount > rhs.failcount) return false;
|
||||||
|
|
||||||
|
// Local peers should always be tried first
|
||||||
|
bool lhs_local = is_local(lhs.ip.address());
|
||||||
|
bool rhs_local = is_local(rhs.ip.address());
|
||||||
|
if (lhs_local && !rhs_local) return true;
|
||||||
|
if (!lhs_local && rhs_local) return false;
|
||||||
|
|
||||||
|
if (lhs.connected < rhs.connected) return true;
|
||||||
|
if (lhs.connected > rhs.connected) return false;
|
||||||
|
|
||||||
|
#ifndef TORRENT_DISABLE_GEO_IP
|
||||||
|
// don't bias fast peers when seeding
|
||||||
|
if (!m_torrent->is_finished() && m_torrent->session().has_asnum_db())
|
||||||
|
{
|
||||||
|
std::pair<const int, int>* lhs_as = lhs.inet_as;
|
||||||
|
std::pair<const int, int>* rhs_as = rhs.inet_as;
|
||||||
|
if (lhs_as ? lhs_as->second : 0 > rhs_as ? rhs->second : 0) return true;
|
||||||
|
if (lhs_as ? lhs_as->second : 0 < rhs_as ? rhs->second : 0) return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
int lhs_distance = cidr_distance(external_ip, lhs.ip.address());
|
||||||
|
int rhs_distance = cidr_distance(external_ip, rhs.ip.address());
|
||||||
|
if (lhs_distance < rhs_distance) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue