made unchoke interval depend on piece size

This commit is contained in:
Arvid Norberg 2008-10-18 22:35:10 +00:00
parent d0fc5fee2b
commit f04e9e9875
6 changed files with 127 additions and 82 deletions

View File

@ -556,6 +556,9 @@ struct has the following members::
int num_unchoked; int num_unchoked;
int allowed_upload_slots; int allowed_upload_slots;
int optimistic_unchoke_counter;
int unchoke_counter;
int dht_nodes; int dht_nodes;
int dht_cache_nodes; int dht_cache_nodes;
int dht_torrents; int dht_torrents;
@ -604,6 +607,11 @@ be assigned a torrent yet.
``num_unchoked`` is the current number of unchoked peers. ``num_unchoked`` is the current number of unchoked peers.
``allowed_upload_slots`` is the current allowed number of unchoked peers. ``allowed_upload_slots`` is the current allowed number of unchoked peers.
``optimistic_unchoke_counter`` and ``unchoke_counter`` tells the number of
seconds until the next optimistic unchoke change and the start of the next
unchoke interval. These numbers may be reset prematurely if a peer that is
unchoked disconnects or becomes notinterested.
``dht_nodes``, ``dht_cache_nodes`` and ``dht_torrents`` are only available when ``dht_nodes``, ``dht_cache_nodes`` and ``dht_torrents`` are only available when
built with DHT support. They are all set to 0 if the DHT isn't running. When built with DHT support. They are all set to 0 if the DHT isn't running. When
the DHT is running, ``dht_nodes`` is set to the number of nodes in the routing the DHT is running, ``dht_nodes`` is set to the number of nodes in the routing
@ -2963,7 +2971,7 @@ that will be sent to the tracker. The user-agent is a good way to identify your
bool lazy_bitfields; bool lazy_bitfields;
int inactivity_timeout; int inactivity_timeout;
int unchoke_interval; int unchoke_interval;
int optimistic_unchoke_multiplier; int optimistic_unchoke_interval;
address announce_ip; address announce_ip;
int num_want; int num_want;
int initial_picker_threshold; int initial_picker_threshold;
@ -3125,8 +3133,8 @@ On this interval, peers are re-evaluated for being choked/unchoked. This
is defined as 30 seconds in the protocol, and it should be significantly is defined as 30 seconds in the protocol, and it should be significantly
longer than what it takes for TCP to ramp up to it's max rate. longer than what it takes for TCP to ramp up to it's max rate.
``optimistic_unchoke_multiplier`` is the number of unchoke intervals between ``optimistic_unchoke_interval`` is the number of seconds between
each *optimistic* unchoke interval. On this timer, the currently optimistically each *optimistic* unchoke. On this timer, the currently optimistically
unchoked peer will change. unchoked peer will change.
``announce_ip`` is the ip address passed along to trackers as the ``&ip=`` parameter. ``announce_ip`` is the ip address passed along to trackers as the ``&ip=`` parameter.

View File

@ -1401,7 +1401,10 @@ int main(int ac, char* av[])
" read cache hits: " << (cs.blocks_read_hit * 100 / cs.blocks_read) << "% " " read cache hits: " << (cs.blocks_read_hit * 100 / cs.blocks_read) << "% "
" cache size: " << add_suffix(cs.cache_size * 16 * 1024) " cache size: " << add_suffix(cs.cache_size * 16 * 1024)
<< " (" << add_suffix(cs.read_cache_size * 16 * 1024) << ")" << " (" << add_suffix(cs.read_cache_size * 16 * 1024) << ")"
" ====" << std::endl; " ====\n"
"==== optimistic unchoke: " << sess_stat.optimistic_unchoke_counter
<< " unchoke counter: " << sess_stat.unchoke_counter
<< " ====" << std::endl;
if (show_dht_status) if (show_dht_status)
{ {

View File

@ -528,6 +528,7 @@ namespace libtorrent
void recalculate_auto_managed_torrents(); void recalculate_auto_managed_torrents();
void recalculate_unchoke_slots(int congested_torrents void recalculate_unchoke_slots(int congested_torrents
, int uncongested_torrents); , int uncongested_torrents);
void recalculate_optimistic_unchoke_slot();
ptime m_last_tick; ptime m_last_tick;

View File

@ -108,7 +108,7 @@ namespace libtorrent
, lazy_bitfields(true) , lazy_bitfields(true)
, inactivity_timeout(600) , inactivity_timeout(600)
, unchoke_interval(15) , unchoke_interval(15)
, optimistic_unchoke_multiplier(4) , optimistic_unchoke_interval(30)
, num_want(200) , num_want(200)
, initial_picker_threshold(4) , initial_picker_threshold(4)
, allowed_fast_set_size(10) , allowed_fast_set_size(10)
@ -280,9 +280,9 @@ namespace libtorrent
// the number of seconds between chokes/unchokes // the number of seconds between chokes/unchokes
int unchoke_interval; int unchoke_interval;
// the number of unchoke intervals between // the number of seconds between
// optimistic unchokes // optimistic unchokes
int optimistic_unchoke_multiplier; int optimistic_unchoke_interval;
// if this is set, this IP will be reported do the // if this is set, this IP will be reported do the
// tracker in the ip= parameter. // tracker in the ip= parameter.

View File

@ -89,6 +89,9 @@ namespace libtorrent
int up_bandwidth_queue; int up_bandwidth_queue;
int down_bandwidth_queue; int down_bandwidth_queue;
int optimistic_unchoke_counter;
int unchoke_counter;
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
int dht_nodes; int dht_nodes;
int dht_node_cache; int dht_node_cache;

View File

@ -1231,7 +1231,7 @@ namespace aux {
} }
// -------------------------------------------------------------- // --------------------------------------------------------------
// unchoke set and optimistic unchoke calculations // unchoke set calculations
// -------------------------------------------------------------- // --------------------------------------------------------------
m_unchoke_time_scaler--; m_unchoke_time_scaler--;
if (m_unchoke_time_scaler <= 0 && !m_connections.empty()) if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
@ -1241,6 +1241,17 @@ namespace aux {
, uncongested_torrents); , uncongested_torrents);
} }
// --------------------------------------------------------------
// optimistic unchoke calculation
// --------------------------------------------------------------
m_optimistic_unchoke_time_scaler--;
if (m_optimistic_unchoke_time_scaler <= 0)
{
m_optimistic_unchoke_time_scaler
= settings().optimistic_unchoke_interval;
recalculate_optimistic_unchoke_slot();
}
// -------------------------------------------------------------- // --------------------------------------------------------------
// disconnect peers when we have too many // disconnect peers when we have too many
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -1416,15 +1427,96 @@ namespace aux {
} }
} }
void session_impl::recalculate_unchoke_slots(int congested_torrents void session_impl::recalculate_optimistic_unchoke_slot()
, int uncongested_torrents)
{ {
std::vector<peer_connection*> peers; if (m_allowed_upload_slots == 0) return;
// find the peer that has been waiting the longest to be optimistically
// unchoked
connection_map::iterator current_optimistic_unchoke = m_connections.end();
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
ptime last_unchoke = max_time();
for (connection_map::iterator i = m_connections.begin() for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i) , end(m_connections.end()); i != end; ++i)
{ {
peer_connection* p = i->get(); peer_connection* p = i->get();
TORRENT_ASSERT(p); TORRENT_ASSERT(p);
policy::peer* pi = p->peer_info_struct();
if (!pi) continue;
torrent* t = p->associated_torrent().lock().get();
if (!t) continue;
if (pi->optimistically_unchoked)
{
TORRENT_ASSERT(!p->is_choked());
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
current_optimistic_unchoke = i;
}
if (pi->last_optimistically_unchoked < last_unchoke
&& !p->is_connecting()
&& !p->is_disconnecting()
&& p->is_peer_interested()
&& t->free_upload_slots()
&& p->is_choked()
&& t->valid_metadata())
{
last_unchoke = pi->last_optimistically_unchoked;
optimistic_unchoke_candidate = i;
}
}
if (optimistic_unchoke_candidate != m_connections.end()
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
{
if (current_optimistic_unchoke != m_connections.end())
{
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
t->choke_peer(*current_optimistic_unchoke->get());
}
else
{
++m_num_unchoked;
}
torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
TORRENT_ASSERT(ret);
(*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
// adjust the optimistic unchoke interval depending on the piece-size
// the peer should be able to download one whole piece within the optimistic
// unchoke interval, at a reasonable rate
int piece_size = t->torrent_file().piece_length();
int rate = 3000;
// assume a reasonable rate is 3 kB/s, unless there's an upload limit and
// a max number of slots, in which case we assume each upload slot gets
// roughly the same amount of bandwidth
if (m_upload_channel.throttle() != bandwidth_limit::inf && m_max_uploads > 0)
rate = (std::max)(m_upload_channel.throttle() / m_max_uploads, 1);
// the time it takes to download one piece at this rate (in seconds)
int piece_dl_time = piece_size / rate;
m_optimistic_unchoke_time_scaler = piece_dl_time;
}
}
void session_impl::recalculate_unchoke_slots(int congested_torrents
, int uncongested_torrents)
{
INVARIANT_CHECK;
std::vector<peer_connection*> peers;
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();)
{
boost::intrusive_ptr<peer_connection> p = *i;
TORRENT_ASSERT(p);
++i;
torrent* t = p->associated_torrent().lock().get(); torrent* t = p->associated_torrent().lock().get();
if (!p->peer_info_struct() if (!p->peer_info_struct()
|| t == 0 || t == 0
@ -1434,7 +1526,7 @@ namespace aux {
|| (p->share_diff() < -free_upload_amount || (p->share_diff() < -free_upload_amount
&& !t->is_seed())) && !t->is_seed()))
{ {
if (!(*i)->is_choked() && t) if (!p->is_choked() && t)
{ {
policy::peer* pi = p->peer_info_struct(); policy::peer* pi = p->peer_info_struct();
if (pi && pi->optimistically_unchoked) if (pi && pi->optimistically_unchoked)
@ -1443,11 +1535,11 @@ namespace aux {
// force a new optimistic unchoke // force a new optimistic unchoke
m_optimistic_unchoke_time_scaler = 0; m_optimistic_unchoke_time_scaler = 0;
} }
t->choke_peer(*(*i)); t->choke_peer(*p);
} }
continue; continue;
} }
peers.push_back(i->get()); peers.push_back(p.get());
} }
// sorts the peers that are eligible for unchoke by download rate and secondary // sorts the peers that are eligible for unchoke by download rate and secondary
@ -1525,74 +1617,6 @@ namespace aux {
++m_num_unchoked; ++m_num_unchoked;
} }
} }
if (m_allowed_upload_slots > 0)
{
m_optimistic_unchoke_time_scaler--;
if (m_optimistic_unchoke_time_scaler <= 0)
{
m_optimistic_unchoke_time_scaler
= settings().optimistic_unchoke_multiplier;
// find the peer that has been waiting the longest to be optimistically
// unchoked
connection_map::iterator current_optimistic_unchoke = m_connections.end();
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
ptime last_unchoke = max_time();
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
{
peer_connection* p = i->get();
TORRENT_ASSERT(p);
policy::peer* pi = p->peer_info_struct();
if (!pi) continue;
torrent* t = p->associated_torrent().lock().get();
if (!t) continue;
if (pi->optimistically_unchoked)
{
TORRENT_ASSERT(!p->is_choked());
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
current_optimistic_unchoke = i;
}
if (pi->last_optimistically_unchoked < last_unchoke
&& !p->is_connecting()
&& !p->is_disconnecting()
&& p->is_peer_interested()
&& t->free_upload_slots()
&& p->is_choked()
&& t->valid_metadata())
{
last_unchoke = pi->last_optimistically_unchoked;
optimistic_unchoke_candidate = i;
}
}
if (optimistic_unchoke_candidate != m_connections.end()
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
{
if (current_optimistic_unchoke != m_connections.end())
{
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
t->choke_peer(*current_optimistic_unchoke->get());
}
else
{
++m_num_unchoked;
}
torrent* t = (*optimistic_unchoke_candidate)->associated_torrent().lock().get();
TORRENT_ASSERT(t);
bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->get());
TORRENT_ASSERT(ret);
(*optimistic_unchoke_candidate)->peer_info_struct()->optimistically_unchoked = true;
}
}
}
} }
void session_impl::operator()() void session_impl::operator()()
@ -2003,6 +2027,9 @@ namespace aux {
session_status s; session_status s;
s.optimistic_unchoke_counter = m_optimistic_unchoke_time_scaler;
s.unchoke_counter = m_unchoke_time_scaler;
s.num_peers = (int)m_connections.size(); s.num_peers = (int)m_connections.size();
s.num_unchoked = m_num_unchoked; s.num_unchoked = m_num_unchoked;
s.allowed_upload_slots = m_allowed_upload_slots; s.allowed_upload_slots = m_allowed_upload_slots;
@ -2529,6 +2556,7 @@ namespace aux {
} }
TORRENT_ASSERT(int(unique.size()) == total_downloaders); TORRENT_ASSERT(int(unique.size()) == total_downloaders);
std::set<peer_connection*> unique_peers;
TORRENT_ASSERT(m_max_connections > 0); TORRENT_ASSERT(m_max_connections > 0);
TORRENT_ASSERT(m_max_uploads > 0); TORRENT_ASSERT(m_max_uploads > 0);
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads); TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
@ -2539,6 +2567,8 @@ namespace aux {
{ {
TORRENT_ASSERT(*i); TORRENT_ASSERT(*i);
boost::shared_ptr<torrent> t = (*i)->associated_torrent().lock(); boost::shared_ptr<torrent> t = (*i)->associated_torrent().lock();
TORRENT_ASSERT(unique_peers.find(i->get()) == unique_peers.end());
unique_peers.insert(i->get());
peer_connection* p = i->get(); peer_connection* p = i->get();
TORRENT_ASSERT(!p->is_disconnecting()); TORRENT_ASSERT(!p->is_disconnecting());