support an arbitrary number of optimistic unchoke slots
This commit is contained in:
parent
c1b8124d20
commit
859f412189
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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); }
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue