fix issue when peer list is full, previously we would sometimes reject new connections

This commit is contained in:
Arvid Norberg 2011-11-24 17:50:57 +00:00
parent 9250b551d9
commit cab1f3d207
7 changed files with 91 additions and 26 deletions

View File

@ -944,6 +944,9 @@ namespace libtorrent
int m_connect_timeouts; int m_connect_timeouts;
int m_uninteresting_peers; int m_uninteresting_peers;
int m_timeout_peers; int m_timeout_peers;
int m_no_memory_peers;
int m_too_many_peers;
int m_transport_timeout_peers;
cache_status m_last_cache_status; cache_status m_last_cache_status;
size_type m_last_failed; size_type m_last_failed;
size_type m_last_redundant; size_type m_last_redundant;

View File

@ -108,10 +108,6 @@ namespace libtorrent
policy(torrent* t); policy(torrent* t);
// this is called every 10 seconds to allow
// for peer choking management
void pulse();
struct peer; struct peer;
#if TORRENT_USE_I2P #if TORRENT_USE_I2P
@ -433,9 +429,11 @@ namespace libtorrent
bool is_connect_candidate(peer const& p, bool finished) const; bool is_connect_candidate(peer const& p, bool finished) const;
bool is_erase_candidate(peer const& p, bool finished) const; bool is_erase_candidate(peer const& p, bool finished) const;
bool is_force_erase_candidate(peer const& pe) const;
bool should_erase_immediately(peer const& p) const; bool should_erase_immediately(peer const& p) const;
void erase_peers(); enum flags_t { force_erase = 1 };
void erase_peers(int flags = 0);
peers_t m_peers; peers_t m_peers;

View File

@ -132,7 +132,7 @@ reports = [
('disk_write_queue', 'Bytes', 'B', 'bytes queued up by peers, to be written to disk', ['disk write queued bytes', 'disk queue limit', 'disk queue low watermark']), ('disk_write_queue', 'Bytes', 'B', 'bytes queued up by peers, to be written to disk', ['disk write queued bytes', 'disk queue limit', 'disk queue low watermark']),
('peers_upload', 'num', '', 'number of peers by state wrt. uploading', ['peers up interested', 'peers up unchoked', 'peers up requests', 'peers disk-up', 'peers bw-up', 'max unchoked']), ('peers_upload', 'num', '', 'number of peers by state wrt. uploading', ['peers up interested', 'peers up unchoked', 'peers up requests', 'peers disk-up', 'peers bw-up', 'max unchoked']),
('peers_download', 'num', '', 'number of peers by state wrt. downloading', ['peers down interesting', 'peers down unchoked', 'peers down requests', 'peers disk-down', 'peers bw-down','num end-game peers']), ('peers_download', 'num', '', 'number of peers by state wrt. downloading', ['peers down interesting', 'peers down unchoked', 'peers down requests', 'peers disk-down', 'peers bw-down','num end-game peers']),
('peer_errors', 'num', '', 'number of peers by error that disconnected them', ['error peers', 'peer disconnects', 'peers eof', 'peers connection reset', 'connect timeouts', 'uninteresting peers disconnect', 'banned for hash failure']), ('peer_errors', 'num', '', 'number of peers by error that disconnected them', ['error peers', 'peer disconnects', 'peers eof', 'peers connection reset', 'connect timeouts', 'uninteresting peers disconnect', 'banned for hash failure', 'no memory peer errors', 'too many peers', 'transport timeout peers']),
('waste', '% of all downloaded bytes', '%%', 'proportion of all downloaded bytes that were wasted', ['% failed payload bytes', '% wasted payload bytes', '% protocol bytes']), ('waste', '% of all downloaded bytes', '%%', 'proportion of all downloaded bytes that were wasted', ['% failed payload bytes', '% wasted payload bytes', '% protocol bytes']),
('waste by source', '% of all wasted bytes', '%%', 'what\' causing the waste', [ 'redundant timed-out', 'redundant cancelled', 'redundant unknown', 'redundant seed', 'redundant end-game', 'redundant closing']), ('waste by source', '% of all wasted bytes', '%%', 'what\' causing the waste', [ 'redundant timed-out', 'redundant cancelled', 'redundant unknown', 'redundant seed', 'redundant end-game', 'redundant closing']),
('average_disk_time_absolute', 'job time', 's', 'running averages of timings of disk operations', ['disk read time', 'disk write time', 'disk hash time', 'disk job time', 'disk sort time']), ('average_disk_time_absolute', 'job time', 's', 'running averages of timings of disk operations', ['disk read time', 'disk write time', 'disk hash time', 'disk job time', 'disk sort time']),

View File

@ -3455,11 +3455,20 @@ namespace libtorrent
|| ec == error_code(errors::torrent_paused)) || ec == error_code(errors::torrent_paused))
++m_ses.m_uninteresting_peers; ++m_ses.m_uninteresting_peers;
if (ec == error_code(errors::timed_out))
++m_ses.m_transport_timeout_peers;
if (ec == error_code(errors::timed_out_inactivity) if (ec == error_code(errors::timed_out_inactivity)
|| ec == error_code(errors::timed_out_no_request) || ec == error_code(errors::timed_out_no_request)
|| ec == error_code(errors::timed_out_no_interest)) || ec == error_code(errors::timed_out_no_interest))
++m_ses.m_timeout_peers; ++m_ses.m_timeout_peers;
if (ec == error_code(errors::no_memory))
++m_ses.m_no_memory_peers;
if (ec == error_code(errors::too_many_connections))
++m_ses.m_too_many_peers;
if (ec == error_code(errors::timed_out_no_handshake)) if (ec == error_code(errors::timed_out_no_handshake))
++m_ses.m_connect_timeouts; ++m_ses.m_connect_timeouts;
#endif #endif

View File

@ -459,20 +459,24 @@ namespace libtorrent
bool policy::should_erase_immediately(peer const& p) const bool policy::should_erase_immediately(peer const& p) const
{ {
return p.source == peer_info::resume_data return p.source == peer_info::resume_data;
&& p.failcount > 0
&& !p.banned;
} }
bool policy::is_erase_candidate(peer const& pe, bool finished) const bool policy::is_erase_candidate(peer const& pe, bool finished) const
{ {
return pe.connection == 0 if (pe.connection) return false;
&& pe.last_connected != 0 if (is_connect_candidate(pe, finished)) return false;
&& !pe.banned
&& !is_connect_candidate(pe, m_finished); return (pe.failcount > 0)
|| (pe.source == peer_info::resume_data);
} }
void policy::erase_peers() bool policy::is_force_erase_candidate(peer const& pe) const
{
return pe.connection == 0;
}
void policy::erase_peers(int flags)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -483,15 +487,19 @@ namespace libtorrent
if (max_peerlist_size == 0 || m_peers.empty()) return; if (max_peerlist_size == 0 || m_peers.empty()) return;
int erase_candidate = -1; int erase_candidate = -1;
int force_erase_candidate = -1;
TORRENT_ASSERT(m_finished == m_torrent->is_finished()); TORRENT_ASSERT(m_finished == m_torrent->is_finished());
int round_robin = random() % m_peers.size(); int round_robin = random() % m_peers.size();
int low_watermark = max_peerlist_size * 95 / 100;
if (low_watermark == max_peerlist_size) --low_watermark;
for (int iterations = (std::min)(int(m_peers.size()), 300); for (int iterations = (std::min)(int(m_peers.size()), 300);
iterations > 0; --iterations) iterations > 0; --iterations)
{ {
if (int(m_peers.size()) < max_peerlist_size * 0.95) if (int(m_peers.size()) < low_watermark)
break; break;
if (round_robin == int(m_peers.size())) round_robin = 0; if (round_robin == int(m_peers.size())) round_robin = 0;
@ -507,6 +515,7 @@ namespace libtorrent
if (should_erase_immediately(pe)) if (should_erase_immediately(pe))
{ {
if (erase_candidate > current) --erase_candidate; if (erase_candidate > current) --erase_candidate;
if (force_erase_candidate > current) --force_erase_candidate;
TORRENT_ASSERT(current >= 0 && current < int(m_peers.size())); TORRENT_ASSERT(current >= 0 && current < int(m_peers.size()));
--round_robin; --round_robin;
erase_peer(m_peers.begin() + current); erase_peer(m_peers.begin() + current);
@ -516,6 +525,12 @@ namespace libtorrent
erase_candidate = current; erase_candidate = current;
} }
} }
if (is_force_erase_candidate(pe)
&& (force_erase_candidate == -1
|| !compare_peer_erase(*m_peers[force_erase_candidate], pe)))
{
force_erase_candidate = current;
}
} }
++round_robin; ++round_robin;
@ -526,6 +541,11 @@ namespace libtorrent
TORRENT_ASSERT(erase_candidate >= 0 && erase_candidate < int(m_peers.size())); TORRENT_ASSERT(erase_candidate >= 0 && erase_candidate < int(m_peers.size()));
erase_peer(m_peers.begin() + erase_candidate); erase_peer(m_peers.begin() + erase_candidate);
} }
else if ((flags & force_erase) && force_erase_candidate > -1)
{
TORRENT_ASSERT(force_erase_candidate >= 0 && force_erase_candidate < int(m_peers.size()));
erase_peer(m_peers.begin() + force_erase_candidate);
}
} }
void policy::ban_peer(policy::peer* p) void policy::ban_peer(policy::peer* p)
@ -710,13 +730,6 @@ namespace libtorrent
return m_peers.begin() + candidate; return m_peers.begin() + candidate;
} }
void policy::pulse()
{
INVARIANT_CHECK;
erase_peers();
}
bool policy::new_connection(peer_connection& c, int session_time) bool policy::new_connection(peer_connection& c, int session_time)
{ {
TORRENT_ASSERT(!c.is_local()); TORRENT_ASSERT(!c.is_local());
@ -739,6 +752,18 @@ namespace libtorrent
&& ses.num_connections() >= ses.settings().connections_limit && ses.num_connections() >= ses.settings().connections_limit
&& c.remote().address() != m_torrent->current_tracker().address()) && c.remote().address() != m_torrent->current_tracker().address())
{ {
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
(*m_torrent->session().m_logger) << time_now_string()
<< " *** TOO MANY CONNECTIONS ["
" torrent: " << m_torrent->name() <<
" torrent peers: " << m_torrent->num_peers() <<
" torrent limit: " << m_torrent->max_connections() <<
" global peers: " << ses.num_connections() <<
" global limit: " << ses.settings().connections_limit <<
" global list peers " << int(m_peers.size()) <<
" global list limit: " << m_torrent->settings().max_peerlist_size <<
" ]\n";
#endif
c.disconnect(errors::too_many_connections); c.disconnect(errors::too_many_connections);
return false; return false;
} }
@ -859,9 +884,21 @@ namespace libtorrent
if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size) if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size)
{ {
// this may invalidate our iterator! // this may invalidate our iterator!
erase_peers(); erase_peers(force_erase);
if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size) if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size)
{ {
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
(*m_torrent->session().m_logger) << time_now_string()
<< " *** TOO MANY CONNECTIONS ["
" torrent: " << m_torrent->name() <<
" torrent peers: " << m_torrent->num_peers() <<
" torrent limit: " << m_torrent->max_connections() <<
" global peers: " << ses.num_connections() <<
" global limit: " << ses.settings().connections_limit <<
" global list peers " << int(m_peers.size()) <<
" global list limit: " << m_torrent->settings().max_peerlist_size <<
" ]\n";
#endif
c.disconnect(errors::too_many_connections); c.disconnect(errors::too_many_connections);
return false; return false;
} }
@ -1678,6 +1715,13 @@ namespace libtorrent
// this returns true if lhs is a better erase candidate than rhs // this returns true if lhs is a better erase candidate than rhs
bool policy::compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const bool policy::compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const
{ {
TORRENT_ASSERT(lhs.connection == 0);
TORRENT_ASSERT(rhs.connection == 0);
// primarily, prefer getting rid of peers we've already tried and failed
if (lhs.failcount != rhs.failcount)
return lhs.failcount > rhs.failcount;
bool lhs_resume_data_source = lhs.source == peer_info::resume_data; bool lhs_resume_data_source = lhs.source == peer_info::resume_data;
bool rhs_resume_data_source = rhs.source == peer_info::resume_data; bool rhs_resume_data_source = rhs.source == peer_info::resume_data;
@ -1689,7 +1733,10 @@ namespace libtorrent
return lhs.connectable < rhs.connectable; return lhs.connectable < rhs.connectable;
// prefer peers with higher failcount // prefer peers with higher failcount
if (lhs.failcount != rhs.failcount)
return lhs.failcount > rhs.failcount; return lhs.failcount > rhs.failcount;
return lhs.trust_points < rhs.trust_points;
} }
// this returns true if lhs is a better connect candidate than rhs // this returns true if lhs is a better connect candidate than rhs

View File

@ -1145,6 +1145,9 @@ namespace aux {
":redundant seed" ":redundant seed"
":redundant end-game" ":redundant end-game"
":redundant closing" ":redundant closing"
":no memory peer errors"
":too many peers"
":transport timeout peers"
"\n\n", m_stats_logger); "\n\n", m_stats_logger);
} }
#endif #endif
@ -3290,7 +3293,10 @@ namespace aux {
m_snubbed_piece_picks = 0; m_snubbed_piece_picks = 0;
m_connect_timeouts = 0; m_connect_timeouts = 0;
m_uninteresting_peers = 0; m_uninteresting_peers = 0;
m_transport_timeout_peers = 0;
m_timeout_peers = 0; m_timeout_peers = 0;
m_no_memory_peers = 0;
m_too_many_peers = 0;
m_connection_attempts = 0; m_connection_attempts = 0;
m_num_banned_peers = 0; m_num_banned_peers = 0;
m_banned_for_hash_failure = 0; m_banned_for_hash_failure = 0;
@ -3624,6 +3630,10 @@ namespace aux {
for (int i = 0; i < torrent::waste_reason_max; ++i) for (int i = 0; i < torrent::waste_reason_max; ++i)
STAT_LOG(f, (m_redundant_bytes[i] * 100.) / double(m_total_redundant_bytes)); STAT_LOG(f, (m_redundant_bytes[i] * 100.) / double(m_total_redundant_bytes));
STAT_LOG(d, m_no_memory_peers);
STAT_LOG(d, m_too_many_peers);
STAT_LOG(d, m_transport_timeout_peers);
fprintf(m_stats_logger, "\n"); fprintf(m_stats_logger, "\n");
#undef STAT_LOG #undef STAT_LOG

View File

@ -7187,8 +7187,6 @@ ctx->set_verify_callback(verify_function, ec);
m_available_free_upload = distribute_free_upload( m_available_free_upload = distribute_free_upload(
this->begin(), this->end(), m_available_free_upload); this->begin(), this->end(), m_available_free_upload);
} }
m_policy.pulse();
} }
// if we're in upload only mode and we're auto-managed // if we're in upload only mode and we're auto-managed