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
* optimized DHT routing table memory usage
* 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

View File

@ -655,7 +655,7 @@ namespace libtorrent
void recalculate_auto_managed_torrents();
void recalculate_unchoke_slots(int congested_torrents
, int uncongested_torrents);
void recalculate_optimistic_unchoke_slot();
void recalculate_optimistic_unchoke_slots();
ptime 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)
, guided_read_cache(true)
, default_cache_min_age(1)
, num_optimistic_unchoke_slots(0)
{}
// 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
// is kept in the cache.
int default_cache_min_age;
// the global number of optimistic unchokes
// 0 means automatic
int num_optimistic_unchoke_slots;
};
#ifndef TORRENT_DISABLE_DHT

View File

@ -2062,7 +2062,7 @@ namespace aux {
{
m_optimistic_unchoke_time_scaler
= 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;
// 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();
boost::uint32_t last_unchoke = UINT_MAX;
std::vector<policy::peer*> opt_unchoke;
for (connection_map::iterator i = m_connections.begin()
, end(m_connections.end()); i != end; ++i)
@ -2259,12 +2255,10 @@ namespace aux {
if (pi->optimistically_unchoked)
{
TORRENT_ASSERT(!p->is_choked());
TORRENT_ASSERT(current_optimistic_unchoke == m_connections.end());
current_optimistic_unchoke = i;
opt_unchoke.push_back(pi);
}
if (pi->last_optimistically_unchoked < last_unchoke
&& !p->is_connecting()
if (!p->is_connecting()
&& !p->is_disconnecting()
&& p->is_peer_interested()
&& t->free_upload_slots()
@ -2272,47 +2266,54 @@ namespace aux {
&& !p->ignore_unchoke_slots()
&& t->valid_metadata())
{
last_unchoke = pi->last_optimistically_unchoked;
optimistic_unchoke_candidate = i;
opt_unchoke.push_back(pi);
}
}
if (optimistic_unchoke_candidate != m_connections.end()
&& optimistic_unchoke_candidate != current_optimistic_unchoke)
// find the peers that has been waiting the longest to be optimistically
// 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();
TORRENT_ASSERT(t);
(*current_optimistic_unchoke)->peer_info_struct()->optimistically_unchoked = false;
t->choke_peer(*current_optimistic_unchoke->get());
--num_opt_unchoke;
if (!pi->optimistically_unchoked)
{
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
{
++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
int unchoke_set_size = m_allowed_upload_slots - 1;
int unchoke_set_size = m_allowed_upload_slots - num_opt_unchoke;
m_num_unchoked = 0;
// 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(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)
{
TORRENT_ASSERT(false);