experimental support for the BitTyrant choking algorithm

This commit is contained in:
Arvid Norberg
2010-02-09 03:04:41 +00:00
parent 1a97405189
commit fb47469834
16 changed files with 396 additions and 72 deletions

View File

@@ -228,8 +228,11 @@ namespace aux {
TORRENT_SETTING(boolean, free_torrent_hashes)
TORRENT_SETTING(boolean, upnp_ignore_nonrouters)
TORRENT_SETTING(integer, send_buffer_watermark)
#ifndef TORRENT_NO_DEPRECATE
TORRENT_SETTING(boolean, auto_upload_slots)
TORRENT_SETTING(boolean, auto_upload_slots_rate_based)
#endif
TORRENT_SETTING(integer, choking_algorithm)
TORRENT_SETTING(boolean, use_parole_mode)
TORRENT_SETTING(integer, cache_size)
TORRENT_SETTING(integer, cache_buffer_chunk_size)
@@ -438,6 +441,8 @@ namespace aux {
, m_auto_scrape_time_scaler(180)
, m_next_explicit_cache_torrent(0)
, m_cache_rotation_timer(0)
, m_peak_up_rate(0)
, m_peak_down_rate(0)
, m_incoming_connection(false)
, m_created(time_now_hires())
, m_last_tick(m_created)
@@ -1052,6 +1057,17 @@ namespace aux {
|| m_settings.low_prio_disk != s.low_prio_disk)
update_disk_io_thread = true;
#ifndef TORRENT_NO_DEPRECATE
// support deprecated choker settings
if (s.choking_algorithm == session_settings::rate_based_choker)
{
if (s.auto_upload_slots && !s.auto_upload_slots_rate_based)
m_settings.choking_algorithm = session_settings::auto_expand_choker;
else if (!s.auto_upload_slots)
m_settings.choking_algorithm = session_settings::fixed_slots_choker;
}
#endif
// safety check
if (m_settings.volatile_read_cache
&& (m_settings.suggest_mode == session_settings::suggest_read_cache
@@ -1064,6 +1080,12 @@ namespace aux {
m_settings.volatile_read_cache = false;
}
if (m_settings.choking_algorithm != s.choking_algorithm)
{
// trigger recalculation of the unchoked peers
m_unchoke_time_scaler = 0;
}
// if queuing settings were changed, recalculate
// queued torrents sooner
if ((m_settings.active_downloads != s.active_downloads
@@ -1089,7 +1111,12 @@ namespace aux {
, performance_alert::too_many_optimistic_unchoke_slots));
}
if (!s.auto_upload_slots) m_allowed_upload_slots = m_max_uploads;
if (s.choking_algorithm == session_settings::fixed_slots_choker)
m_allowed_upload_slots = m_max_uploads;
else if (s.choking_algorithm == session_settings::auto_expand_choker
&& m_allowed_upload_slots < m_max_uploads)
m_allowed_upload_slots = m_max_uploads;
// replace all occurances of '\n' with ' '.
std::string::iterator i = m_settings.user_agent.begin();
while ((i = std::find(i, m_settings.user_agent.end(), '\n'))
@@ -1915,6 +1942,9 @@ namespace aux {
}
}
m_peak_up_rate = (std::max)(m_stat.upload_rate(), m_peak_up_rate);
m_peak_down_rate = (std::max)(m_stat.download_rate(), m_peak_down_rate);
m_stat.second_tick(tick_interval_ms);
TORRENT_ASSERT(least_recently_scraped == m_torrents.end()
@@ -2394,8 +2424,29 @@ namespace aux {
++i;
torrent* t = p->associated_torrent().lock().get();
policy::peer* pi = p->peer_info_struct();
if (p->ignore_unchoke_slots() || t == 0 || pi == 0) continue;
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
{
if (!p->is_choked())
{
policy::peer* pi = p->peer_info_struct();
if (!p->has_peer_choked())
{
// we're unchoked, we may want to lower our estimated
// reciprocation rate
p->decrease_est_reciprocation_rate();
}
else
{
// we've unchoked this peer, and it hasn't reciprocated
// we may want to increase our estimated reciprocation rate
p->increase_est_reciprocation_rate();
}
}
}
if (!p->is_peer_interested()
|| p->is_disconnecting()
|| p->is_connecting()
@@ -2417,8 +2468,7 @@ namespace aux {
peers.push_back(p.get());
}
if (m_settings.auto_upload_slots_rate_based
&& m_settings.auto_upload_slots)
if (m_settings.choking_algorithm == session_settings::rate_based_choker)
{
m_allowed_upload_slots = 0;
std::sort(peers.begin(), peers.end()
@@ -2460,17 +2510,26 @@ namespace aux {
++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
// be unchoked
std::sort(peers.begin(), peers.end()
, bind(&peer_connection::unchoke_compare, _1, _2));
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
{
// if we're using the bittyrant choker, sort peers by their return
// on investment. i.e. download rate / upload rate
std::sort(peers.begin(), peers.end()
, bind(&peer_connection::bittyrant_unchoke_compare, _1, _2));
}
else
{
// 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
// be unchoked
std::sort(peers.begin(), peers.end()
, bind(&peer_connection::unchoke_compare, _1, _2));
}
// auto unchoke
int upload_limit = m_bandwidth_channel[peer_connection::upload_channel]->throttle();
if (!m_settings.auto_upload_slots_rate_based
&& m_settings.auto_upload_slots
if (m_settings.choking_algorithm == session_settings::auto_expand_choker
&& upload_limit > 0)
{
// if our current upload rate is less than 90% of our
@@ -2494,9 +2553,25 @@ 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 some upload slots for optimistic unchokes
int unchoke_set_size = m_allowed_upload_slots - num_opt_unchoke;
int upload_capacity_left = 0;
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
{
upload_capacity_left = m_upload_channel.throttle();
if (upload_capacity_left == 0)
{
// we don't know at what rate we can upload. If we have a
// measurement of the peak, use that + 10kB/s, otherwise
// assume 20 kB/s
upload_capacity_left = (std::max)(20000, m_peak_up_rate + 10000);
if (m_alerts.should_post<performance_alert>())
m_alerts.post_alert(performance_alert(torrent_handle()
, performance_alert::bittyrant_with_no_uplimit));
}
}
m_num_unchoked = 0;
// go through all the peers and unchoke the first ones and choke
// all the other ones.
@@ -2508,12 +2583,28 @@ namespace aux {
TORRENT_ASSERT(!p->ignore_unchoke_slots());
// this will update the m_uploaded_at_last_unchoke
// #error this should be called for all peers!
p->reset_choke_counters();
torrent* t = p->associated_torrent().lock().get();
TORRENT_ASSERT(t);
if (unchoke_set_size > 0)
// if this peer should be unchoked depends on different things
// in different unchoked schemes
bool unchoke = false;
if (m_settings.choking_algorithm == session_settings::bittyrant_choker)
{
unchoke = p->est_reciprocation_rate() <= upload_capacity_left;
}
else
{
unchoke = unchoke_set_size > 0;
}
if (unchoke)
{
upload_capacity_left -= p->est_reciprocation_rate();
// yes, this peer should be unchoked
if (p->is_choked())
{
@@ -3565,7 +3656,7 @@ namespace aux {
std::set<peer_connection*> unique_peers;
TORRENT_ASSERT(m_max_connections > 0);
TORRENT_ASSERT(m_max_uploads >= 0);
if (!m_settings.auto_upload_slots_rate_based || !m_settings.auto_upload_slots)
if (m_settings.choking_algorithm == session_settings::auto_expand_choker)
TORRENT_ASSERT(m_allowed_upload_slots >= m_max_uploads);
int unchokes = 0;
int num_optimistic = 0;