auto unchoke improvement

This commit is contained in:
Arvid Norberg 2009-04-04 07:55:34 +00:00
parent 9140358a3f
commit db8487be46
7 changed files with 93 additions and 17 deletions

View File

@ -476,6 +476,9 @@ number of uploads is at least one per torrent.
``max_connections()`` returns the current setting.
The number of unchoke slots may be ignored. In order to make this setting
take effect, disable ``session_settings::auto_upload_slots_rate_based``.
num_uploads() num_connections()
-------------------------------
@ -3306,6 +3309,7 @@ that will be sent to the tracker. The user-agent is a good way to identify your
bool upnp_ignore_nonrouters;
int send_buffer_watermark;
bool auto_upload_slots;
bool auto_upload_slots_rate_based;
bool use_parole_mode;
int cache_size;
int cache_expiry;
@ -3530,6 +3534,11 @@ of time, on upload slot is closed. The number of upload slots will never be
less than what has been set by ``session::set_max_uploads()``. To query the
current number of upload slots, see ``session_status::allowed_upload_slots``.
When ``auto_upload_slots_rate_based`` is set, and ``auto_upload_slots`` is set,
the max upload slots setting is ignored and decided completely automatically.
This algorithm is designed to prevent the peer from spreading its upload
capacity too thin.
``use_parole_mode`` specifies if parole mode should be used. Parole mode means
that peers that participate in pieces that fail the hash check are put in a mode
where they are only allowed to download whole pieces. If the whole piece a peer

View File

@ -713,6 +713,7 @@ int main(int argc, char* argv[])
proxy_settings ps;
settings.user_agent = "client_test/" LIBTORRENT_VERSION;
settings.auto_upload_slots_rate_based = true;
settings.announce_to_all_trackers = true;
std::deque<std::string> events;

View File

@ -90,6 +90,7 @@ namespace libtorrent
class natpmp;
class lsd;
class fingerprint;
class torrent;
namespace dht
{
@ -520,6 +521,10 @@ namespace libtorrent
ptime m_last_tick;
// the last time we went through the peers
// to decide which ones to choke/unchoke
ptime m_last_choke;
// when outgoing_ports is configured, this is the
// port we'll bind the next outgoing socket to
int m_next_port;

View File

@ -361,6 +361,7 @@ namespace libtorrent
// for which one is more eligible for an unchoke.
// returns true if this is more eligible
bool unchoke_compare(boost::intrusive_ptr<peer_connection const> const& p) const;
bool upload_rate_compare(peer_connection const* p) const;
// resets the byte counters that are used to measure
// the number of bytes transferred within unchoke cycles
@ -505,6 +506,12 @@ namespace libtorrent
// enum from peer_info::bw_state
char m_channel_state[2];
size_type uploaded_since_unchoke() const
{ return m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke; }
size_type downloaded_since_unchoke() const
{ return m_statistics.total_payload_download() - m_downloaded_at_last_unchoke; }
protected:
virtual void get_specific_peer_info(peer_info& p) const = 0;

View File

@ -121,6 +121,7 @@ namespace libtorrent
, upnp_ignore_nonrouters(false)
, send_buffer_watermark(80 * 1024)
, auto_upload_slots(true)
, auto_upload_slots_rate_based(false)
, use_parole_mode(true)
, cache_size(512)
, cache_expiry(60)
@ -363,6 +364,11 @@ namespace libtorrent
// the manual settings, through max_uploads.
bool auto_upload_slots;
// this only affects the auto upload slots mechanism.
// if auto_upload_slots is false, this field is not
// considered.
bool auto_upload_slots_rate_based;
// if set to true, peers that participate in a failing
// piece is put in parole mode. i.e. They will only
// download whole pieces until they either fail or pass.

View File

@ -336,6 +336,17 @@ namespace libtorrent
return m_last_unchoke < rhs.m_last_unchoke;
}
bool peer_connection::upload_rate_compare(peer_connection const* p) const
{
size_type c1;
size_type c2;
c1 = m_statistics.total_payload_upload() - m_uploaded_at_last_unchoke;
c2 = p->m_statistics.total_payload_upload() - p->m_uploaded_at_last_unchoke;
return c1 > c2;
}
void peer_connection::reset_choke_counters()
{
m_downloaded_at_last_unchoke = m_statistics.total_payload_download();

View File

@ -180,6 +180,7 @@ namespace aux {
, m_auto_scrape_time_scaler(180)
, m_incoming_connection(false)
, m_last_tick(time_now())
, m_last_choke(m_last_tick)
#ifndef TORRENT_DISABLE_DHT
, m_dht_same_port(true)
, m_external_udp_port(0)
@ -1644,6 +1645,12 @@ namespace aux {
{
INVARIANT_CHECK;
ptime now = time_now();
time_duration unchoke_interval = now - m_last_choke;
m_last_choke = now;
// build list of all peers that are
// unchoke:able.
std::vector<peer_connection*> peers;
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();)
@ -1652,31 +1659,56 @@ namespace aux {
TORRENT_ASSERT(p);
++i;
torrent* t = p->associated_torrent().lock().get();
if (!p->peer_info_struct()
|| t == 0
|| !p->is_peer_interested()
policy::peer* pi = p->peer_info_struct();
if (p->ignore_unchoke_slots() || t == 0 || pi == 0) continue;
if (!p->is_peer_interested()
|| p->is_disconnecting()
|| p->is_connecting()
|| p->ignore_unchoke_slots()
|| (p->share_diff() < -free_upload_amount
&& !t->is_seed()))
{
if (!p->is_choked() && t && !p->ignore_unchoke_slots())
// this peer is not unchokable. So, if it's unchoked
// already, make sure to choke it.
if (p->is_choked()) continue;
if (pi && pi->optimistically_unchoked)
{
policy::peer* pi = p->peer_info_struct();
if (pi && pi->optimistically_unchoked)
{
pi->optimistically_unchoked = false;
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
}
t->choke_peer(*p);
pi->optimistically_unchoked = false;
// force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0;
}
continue;
t->choke_peer(*p);
}
peers.push_back(p.get());
}
// if the client is configured to use fully automatic
// unchoke slots, ignore m_max_uploads
if (m_settings.auto_upload_slots_rate_based
&& m_settings.auto_upload_slots)
{
m_allowed_upload_slots = 0;
std::sort(peers.begin(), peers.end()
, bind(&peer_connection::upload_rate_compare, _1, _2));
// TODO: make configurable
int rate_threshold = 1024;
for (std::vector<peer_connection*>::const_iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
peer_connection const& p = **i;
int rate = p.uploaded_since_unchoke()
* 1000 / total_milliseconds(unchoke_interval);
if (rate > rate_threshold) ++m_allowed_upload_slots;
// TODO: make configurable
rate_threshold += 1024;
}
// allow one optimistic unchoke
++m_allowed_upload_slots;
}
// sorts the peers that are eligible for unchoke by download rate and secondary
// by total upload. The reason for this is, if all torrents are being seeded,
// the download rate will be 0, and the peers we have sent the least to should
@ -1689,7 +1721,9 @@ namespace aux {
// auto unchoke
int upload_limit = m_bandwidth_manager[peer_connection::upload_channel]->throttle();
if (m_settings.auto_upload_slots && upload_limit != bandwidth_limit::inf)
if (!m_settings.auto_upload_slots_rate_based
&& m_settings.auto_upload_slots
&& upload_limit != bandwidth_limit::inf)
{
// if our current upload rate is less than 90% of our
// limit AND most torrents are not "congested", i.e.
@ -1720,11 +1754,12 @@ namespace aux {
{
peer_connection* p = *i;
TORRENT_ASSERT(p);
if (p->ignore_unchoke_slots()) continue;
TORRENT_ASSERT(!p->ignore_unchoke_slots());
torrent* t = p->associated_torrent().lock().get();
TORRENT_ASSERT(t);
if (unchoke_set_size > 0)
{
// yes, this peer should be unchoked
if (p->is_choked())
{
if (!t->unchoke_peer(*p))
@ -1746,6 +1781,7 @@ namespace aux {
}
else
{
// no, this peer should be shoked
TORRENT_ASSERT(p->peer_info_struct());
if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
t->choke_peer(*p);
@ -2749,7 +2785,8 @@ namespace aux {
std::set<peer_connection*> unique_peers;
TORRENT_ASSERT(m_max_connections > 0);
TORRENT_ASSERT(m_max_uploads > 0);
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
if (!m_settings.auto_upload_slots_rate_based || !m_settings.auto_upload_slots)
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
int unchokes = 0;
int num_optimistic = 0;
for (connection_map::const_iterator i = m_connections.begin();