support an arbitrary number of optimistic unchoke slots

This commit is contained in:
Arvid Norberg 2010-02-02 18:39:32 +00:00
parent c1b8124d20
commit 859f412189
4 changed files with 60 additions and 46 deletions

View File

@ -11,6 +11,8 @@
* added support to build with libgcrypt and a shipped version of libtommath * added support to build with libgcrypt and a shipped version of libtommath
* optimized DHT routing table memory usage * optimized DHT routing table memory usage
* optimized disk cache to work with large caches * optimized disk cache to work with large caches
* support variable number of optimistic unchoke slots and to dynamically
adjust based on the total number of unchoke slots
0.15 release 0.15 release

View File

@ -655,7 +655,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(); void recalculate_optimistic_unchoke_slots();
ptime m_created; ptime m_created;
int session_time() const { return total_seconds(time_now() - m_created); } int session_time() const { return total_seconds(time_now() - m_created); }

View File

@ -189,6 +189,7 @@ namespace libtorrent
, volatile_read_cache(false) , volatile_read_cache(false)
, guided_read_cache(true) , guided_read_cache(true)
, default_cache_min_age(1) , default_cache_min_age(1)
, num_optimistic_unchoke_slots(0)
{} {}
// this is the user agent that will be sent to the tracker // this is the user agent that will be sent to the tracker
@ -704,6 +705,10 @@ namespace libtorrent
// this is the default minimum time any read cache line // this is the default minimum time any read cache line
// is kept in the cache. // is kept in the cache.
int default_cache_min_age; int default_cache_min_age;
// the global number of optimistic unchokes
// 0 means automatic
int num_optimistic_unchoke_slots;
}; };
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT

View File

@ -2062,7 +2062,7 @@ namespace aux {
{ {
m_optimistic_unchoke_time_scaler m_optimistic_unchoke_time_scaler
= settings().optimistic_unchoke_interval; = settings().optimistic_unchoke_interval;
recalculate_optimistic_unchoke_slot(); recalculate_optimistic_unchoke_slots();
} }
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -2236,15 +2236,11 @@ namespace aux {
} }
void session_impl::recalculate_optimistic_unchoke_slot() void session_impl::recalculate_optimistic_unchoke_slots()
{ {
if (m_allowed_upload_slots == 0) return; if (m_allowed_upload_slots == 0) return;
// find the peer that has been waiting the longest to be optimistically std::vector<policy::peer*> opt_unchoke;
// unchoked
connection_map::iterator current_optimistic_unchoke = m_connections.end();
connection_map::iterator optimistic_unchoke_candidate = m_connections.end();
boost::uint32_t last_unchoke = UINT_MAX;
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)
@ -2259,12 +2255,10 @@ namespace aux {
if (pi->optimistically_unchoked) if (pi->optimistically_unchoked)
{ {
TORRENT_ASSERT(!p->is_choked()); TORRENT_ASSERT(!p->is_choked());
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end()); opt_unchoke.push_back(pi);
current_optimistic_unchoke = i;
} }
if (pi->last_optimistically_unchoked < last_unchoke if (!p->is_connecting()
&& !p->is_connecting()
&& !p->is_disconnecting() && !p->is_disconnecting()
&& p->is_peer_interested() && p->is_peer_interested()
&& t->free_upload_slots() && t->free_upload_slots()
@ -2272,47 +2266,54 @@ namespace aux {
&& !p->ignore_unchoke_slots() && !p->ignore_unchoke_slots()
&& t->valid_metadata()) && t->valid_metadata())
{ {
last_unchoke = pi->last_optimistically_unchoked; opt_unchoke.push_back(pi);
optimistic_unchoke_candidate = i;
} }
} }
if (optimistic_unchoke_candidate != m_connections.end() // find the peers that has been waiting the longest to be optimistically
&& optimistic_unchoke_candidate != current_optimistic_unchoke) // unchoked
// avoid having a bias towards peers that happen to be sorted first
std::random_shuffle(opt_unchoke.begin(), opt_unchoke.end());
// sort all candidates based on when they were last optimistically
// unchoked.
std::sort(opt_unchoke.begin(), opt_unchoke.end()
, boost::bind(&policy::peer::last_optimistically_unchoked, _1)
< boost::bind(&policy::peer::last_optimistically_unchoked, _2));
int num_opt_unchoke = m_settings.num_optimistic_unchoke_slots;
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, m_allowed_upload_slots / 5);
// unchoke the first num_opt_unchoke peers in the candidate set
// and make sure that the others are choked
for (std::vector<policy::peer*>::iterator i = opt_unchoke.begin()
, end(opt_unchoke.end()); i != end; ++i)
{ {
if (current_optimistic_unchoke != m_connections.end()) policy::peer* pi = *i;
if (num_opt_unchoke > 0)
{ {
torrent* t = (*current_optimistic_unchoke)->associated_torrent().lock().get(); --num_opt_unchoke;
TORRENT_ASSERT(t); if (!pi->optimistically_unchoked)
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false; {
t->choke_peer(*current_optimistic_unchoke->get()); torrent* t = pi->connection->associated_torrent().lock().get();
bool ret = t->unchoke_peer(*pi->connection);
TORRENT_ASSERT(ret);
pi->optimistically_unchoked = true;
++m_num_unchoked;
pi->last_optimistically_unchoked = session_time();
}
} }
else else
{ {
++m_num_unchoked; if (pi->optimistically_unchoked)
{
torrent* t = pi->connection->associated_torrent().lock().get();
pi->optimistically_unchoked = false;
t->choke_peer(*pi->connection);
--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
TORRENT_ASSERT(m_upload_channel.throttle() != bandwidth_channel::inf);
if (m_upload_channel.throttle() > 0 && 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;
} }
} }
@ -2433,8 +2434,11 @@ namespace aux {
} }
} }
int num_opt_unchoke = m_settings.num_optimistic_unchoke_slots;
if (num_opt_unchoke == 0) num_opt_unchoke = (std::max)(1, m_allowed_upload_slots / 5);
// reserve one upload slot for optimistic unchokes // reserve one upload slot for optimistic unchokes
int unchoke_set_size = m_allowed_upload_slots - 1; int unchoke_set_size = m_allowed_upload_slots - num_opt_unchoke;
m_num_unchoked = 0; m_num_unchoked = 0;
// go through all the peers and unchoke the first ones and choke // go through all the peers and unchoke the first ones and choke
@ -3494,7 +3498,10 @@ namespace aux {
TORRENT_ASSERT(t->get_policy().has_connection(p)); TORRENT_ASSERT(t->get_policy().has_connection(p));
} }
} }
TORRENT_ASSERT(num_optimistic == 0 || num_optimistic == 1);
if (m_settings.num_optimistic_unchoke_slots)
TORRENT_ASSERT(num_optimistic <= m_settings.num_optimistic_unchoke_slots);
if (m_num_unchoked != unchokes) if (m_num_unchoked != unchokes)
{ {
TORRENT_ASSERT(false); TORRENT_ASSERT(false);