optimized rate limiter by allowing peers to request more bandwidth while waiting on the socket
This commit is contained in:
parent
a220b8df0c
commit
be6afa74f3
|
@ -1,3 +1,4 @@
|
||||||
|
* optimized rate limiter
|
||||||
* make disk cache pool allocator configurable
|
* make disk cache pool allocator configurable
|
||||||
* fix library ABI to not depend on logging being enabled
|
* fix library ABI to not depend on logging being enabled
|
||||||
* use hex encoding instead of base32 in create_magnet_uri
|
* use hex encoding instead of base32 in create_magnet_uri
|
||||||
|
|
|
@ -85,10 +85,10 @@ namespace libtorrent
|
||||||
// bw_idle: the channel is not used
|
// bw_idle: the channel is not used
|
||||||
// bw_limit: the channel is waiting for quota
|
// bw_limit: the channel is waiting for quota
|
||||||
// bw_network: the channel is waiting for an async write
|
// bw_network: the channel is waiting for an async write
|
||||||
// for read operation to complete
|
// or read operation to complete
|
||||||
// bw_disk: the peer is waiting for the disk io thread
|
// bw_disk: the peer is waiting for the disk io thread
|
||||||
// this is a bitmask, a peer can wait for network and
|
// this is a bitmask, a peer can wait for network, rate-limiter
|
||||||
// disk at the same time!
|
// and disk at the same time!
|
||||||
enum bw_state { bw_idle = 0, bw_limit = 1, bw_network = 2, bw_disk = 4 };
|
enum bw_state { bw_idle = 0, bw_limit = 1, bw_network = 2, bw_disk = 4 };
|
||||||
#ifndef TORRENT_NO_DEPRECATE
|
#ifndef TORRENT_NO_DEPRECATE
|
||||||
enum bw_state_deprecated { bw_torrent = bw_limit, bw_global = bw_limit };
|
enum bw_state_deprecated { bw_torrent = bw_limit, bw_global = bw_limit };
|
||||||
|
|
|
@ -4574,6 +4574,18 @@ namespace libtorrent
|
||||||
, bandwidth_channel* bwc3
|
, bandwidth_channel* bwc3
|
||||||
, bandwidth_channel* bwc4)
|
, bandwidth_channel* bwc4)
|
||||||
{
|
{
|
||||||
|
// we can only have one outstanding bandwidth request at a time
|
||||||
|
if (m_channel_state[upload_channel] & peer_info::bw_limit) return 0;
|
||||||
|
|
||||||
|
int bytes = (std::max)(m_send_buffer.size(), m_statistics.upload_rate() * 2
|
||||||
|
* m_ses.m_settings.tick_interval / 1000);
|
||||||
|
|
||||||
|
// we already have quota for the bytes we want to send
|
||||||
|
if (m_quota[upload_channel] >= bytes) return 0;
|
||||||
|
|
||||||
|
// deduct the bytes we already have quota for
|
||||||
|
bytes -= m_quota[upload_channel];
|
||||||
|
|
||||||
shared_ptr<torrent> t = m_torrent.lock();
|
shared_ptr<torrent> t = m_torrent.lock();
|
||||||
int priority;
|
int priority;
|
||||||
if (t && m_ses.m_settings.choking_algorithm == session_settings::bittyrant_choker
|
if (t && m_ses.m_settings.choking_algorithm == session_settings::bittyrant_choker
|
||||||
|
@ -4608,7 +4620,6 @@ namespace libtorrent
|
||||||
TORRENT_ASSERT(priority <= 0xffff);
|
TORRENT_ASSERT(priority <= 0xffff);
|
||||||
|
|
||||||
// peers that we are not interested in are non-prioritized
|
// peers that we are not interested in are non-prioritized
|
||||||
TORRENT_ASSERT((m_channel_state[upload_channel] & peer_info::bw_limit) == 0);
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
peer_log(">>> REQUEST_BANDWIDTH [ upload: %d prio: %d "
|
peer_log(">>> REQUEST_BANDWIDTH [ upload: %d prio: %d "
|
||||||
"channels: %p %p %p %p limits: %d %d %d %d ignore: %d ]"
|
"channels: %p %p %p %p limits: %d %d %d %d ignore: %d ]"
|
||||||
|
@ -4620,11 +4631,24 @@ namespace libtorrent
|
||||||
, (bwc4?bwc4->throttle():0)
|
, (bwc4?bwc4->throttle():0)
|
||||||
, m_ignore_bandwidth_limits);
|
, m_ignore_bandwidth_limits);
|
||||||
#endif
|
#endif
|
||||||
return m_ses.m_upload_rate.request_bandwidth(self()
|
|
||||||
, (std::max)(m_send_buffer.size(), m_statistics.upload_rate() * 2
|
int ret = m_ses.m_upload_rate.request_bandwidth(self()
|
||||||
* m_ses.m_settings.tick_interval / 1000)
|
, bytes
|
||||||
, priority
|
, priority
|
||||||
, bwc1, bwc2, bwc3, bwc4);
|
, bwc1, bwc2, bwc3, bwc4);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
m_channel_state[upload_channel] |= peer_info::bw_limit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_quota[upload_channel] += ret;
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
peer_log(">>> ASSIGN BANDWIDTH [ bytes: %d ]", ret);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int peer_connection::request_download_bandwidth(
|
int peer_connection::request_download_bandwidth(
|
||||||
|
@ -4633,6 +4657,18 @@ namespace libtorrent
|
||||||
, bandwidth_channel* bwc3
|
, bandwidth_channel* bwc3
|
||||||
, bandwidth_channel* bwc4)
|
, bandwidth_channel* bwc4)
|
||||||
{
|
{
|
||||||
|
// we can only have one outstanding bandwidth request at a time
|
||||||
|
if (m_channel_state[download_channel] & peer_info::bw_limit) return 0;
|
||||||
|
|
||||||
|
int bytes = (std::max)((std::max)(m_outstanding_bytes, m_packet_size - m_recv_pos) + 30
|
||||||
|
, m_statistics.download_rate() * 2 * m_ses.m_settings.tick_interval / 1000);
|
||||||
|
|
||||||
|
// we already have enough quota
|
||||||
|
if (m_quota[download_channel] >= bytes) return 0;
|
||||||
|
|
||||||
|
// deduct the bytes we already have quota for
|
||||||
|
bytes -= m_quota[download_channel];
|
||||||
|
|
||||||
shared_ptr<torrent> t = m_torrent.lock();
|
shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
@ -4652,10 +4688,21 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(m_outstanding_bytes >= 0);
|
TORRENT_ASSERT(m_outstanding_bytes >= 0);
|
||||||
TORRENT_ASSERT((m_channel_state[download_channel] & peer_info::bw_limit) == 0);
|
TORRENT_ASSERT((m_channel_state[download_channel] & peer_info::bw_limit) == 0);
|
||||||
return m_ses.m_download_rate.request_bandwidth(self()
|
|
||||||
, (std::max)((std::max)(m_outstanding_bytes, m_packet_size - m_recv_pos) + 30
|
int ret = m_ses.m_download_rate.request_bandwidth(self()
|
||||||
, m_statistics.download_rate() * 2 * m_ses.m_settings.tick_interval / 1000)
|
, bytes, priority, bwc1, bwc2, bwc3, bwc4);
|
||||||
, priority , bwc1, bwc2, bwc3, bwc4);
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
m_channel_state[download_channel] |= peer_info::bw_limit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
peer_log("<<< ASSIGN BANDWIDTH [ bytes: %d ]", ret);
|
||||||
|
#endif
|
||||||
|
m_quota[download_channel] += ret;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void peer_connection::uncork_socket()
|
void peer_connection::uncork_socket()
|
||||||
|
@ -4669,52 +4716,42 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
if (m_disconnecting) return;
|
if (m_disconnecting) return;
|
||||||
|
|
||||||
if (m_channel_state[upload_channel] & (peer_info::bw_network | peer_info::bw_limit)) return;
|
|
||||||
|
|
||||||
shared_ptr<torrent> t = m_torrent.lock();
|
shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
|
||||||
|
// we may want to request more quota at this point
|
||||||
|
int ret = 0;
|
||||||
|
bool utp = m_socket->get<utp_stream>() != 0;
|
||||||
|
bool ignore_limits = m_ignore_bandwidth_limits
|
||||||
|
|| (!m_ses.m_settings.rate_limit_utp && utp);
|
||||||
|
if (!ignore_limits)
|
||||||
|
{
|
||||||
|
// in this case, we have data to send, but no
|
||||||
|
// bandwidth. So, we simply request bandwidth
|
||||||
|
// from the bandwidth manager
|
||||||
|
ret = request_upload_bandwidth(
|
||||||
|
&m_ses.m_upload_channel
|
||||||
|
, t ? &t->m_bandwidth_channel[upload_channel] : 0
|
||||||
|
, &m_bandwidth_channel[upload_channel]
|
||||||
|
, !utp ? &m_ses.m_tcp_upload_channel : 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// in this case, we're a local peer, and the settings
|
||||||
|
// are set to ignore rate limits for local peers. So,
|
||||||
|
// instead we rate limit ourself against the special
|
||||||
|
// global bandwidth channel for local peers, which defaults
|
||||||
|
// to unthrottled
|
||||||
|
ret = request_upload_bandwidth(&m_ses.m_local_upload_channel
|
||||||
|
, &m_bandwidth_channel[upload_channel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_channel_state[upload_channel] & peer_info::bw_network) return;
|
||||||
|
|
||||||
if (m_quota[upload_channel] == 0
|
if (m_quota[upload_channel] == 0
|
||||||
&& !m_send_buffer.empty()
|
&& !m_send_buffer.empty()
|
||||||
&& !m_connecting)
|
&& !m_connecting)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
return;
|
||||||
bool utp = m_socket->get<utp_stream>() != 0;
|
|
||||||
bool ignore_limits = m_ignore_bandwidth_limits
|
|
||||||
|| (!m_ses.m_settings.rate_limit_utp && utp);
|
|
||||||
if (!ignore_limits)
|
|
||||||
{
|
|
||||||
// in this case, we have data to send, but no
|
|
||||||
// bandwidth. So, we simply request bandwidth
|
|
||||||
// from the bandwidth manager
|
|
||||||
ret = request_upload_bandwidth(
|
|
||||||
&m_ses.m_upload_channel
|
|
||||||
, t ? &t->m_bandwidth_channel[upload_channel] : 0
|
|
||||||
, &m_bandwidth_channel[upload_channel]
|
|
||||||
, !utp ? &m_ses.m_tcp_upload_channel : 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// in this case, we're a local peer, and the settings
|
|
||||||
// are set to ignore rate limits for local peers. So,
|
|
||||||
// instead we rate limit ourself against the special
|
|
||||||
// global bandwidth channel for local peers, which defaults
|
|
||||||
// to unthrottled
|
|
||||||
ret = request_upload_bandwidth(&m_ses.m_local_upload_channel
|
|
||||||
, &m_bandwidth_channel[upload_channel]);
|
|
||||||
}
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
m_channel_state[upload_channel] |= peer_info::bw_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we were just assigned 'ret' quota
|
|
||||||
TORRENT_ASSERT(ret > 0);
|
|
||||||
m_quota[upload_channel] += ret;
|
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
|
||||||
peer_log("<<< ASSIGN BANDWIDTH [ bytes: %d ]", ret);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int quota_left = m_quota[upload_channel];
|
int quota_left = m_quota[upload_channel];
|
||||||
|
@ -4823,51 +4860,42 @@ namespace libtorrent
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
if (m_disconnecting) return;
|
if (m_disconnecting) return;
|
||||||
if (m_channel_state[download_channel] & (peer_info::bw_network | peer_info::bw_limit)) return;
|
|
||||||
|
|
||||||
shared_ptr<torrent> t = m_torrent.lock();
|
shared_ptr<torrent> t = m_torrent.lock();
|
||||||
|
|
||||||
|
// we may want to request more quota at this point
|
||||||
|
int ret = 0;
|
||||||
|
bool utp = m_socket->get<utp_stream>() != 0;
|
||||||
|
bool ignore_limits = m_ignore_bandwidth_limits
|
||||||
|
|| (!m_ses.m_settings.rate_limit_utp && utp);
|
||||||
|
if (!ignore_limits)
|
||||||
|
{
|
||||||
|
// in this case, we have outstanding data to
|
||||||
|
// receive, but no bandwidth quota. So, we simply
|
||||||
|
// request bandwidth from the bandwidth manager
|
||||||
|
ret = request_download_bandwidth(
|
||||||
|
&m_ses.m_download_channel
|
||||||
|
, t ? &t->m_bandwidth_channel[download_channel] : 0
|
||||||
|
, &m_bandwidth_channel[download_channel]
|
||||||
|
, !utp ? &m_ses.m_tcp_download_channel : 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// in this case, we're a local peer, and the settings
|
||||||
|
// are set to ignore rate limits for local peers. So,
|
||||||
|
// instead we rate limit ourself against the special
|
||||||
|
// global bandwidth channel for local peers, which defaults
|
||||||
|
// to unthrottled
|
||||||
|
ret = request_download_bandwidth(&m_ses.m_local_download_channel
|
||||||
|
, &m_bandwidth_channel[download_channel]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_channel_state[download_channel] & peer_info::bw_network) return;
|
||||||
|
|
||||||
if (m_quota[download_channel] == 0
|
if (m_quota[download_channel] == 0
|
||||||
&& !m_connecting)
|
&& !m_connecting)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
return;
|
||||||
bool utp = m_socket->get<utp_stream>() != 0;
|
|
||||||
bool ignore_limits = m_ignore_bandwidth_limits
|
|
||||||
|| (!m_ses.m_settings.rate_limit_utp && utp);
|
|
||||||
if (!ignore_limits)
|
|
||||||
{
|
|
||||||
// in this case, we have outstanding data to
|
|
||||||
// receive, but no bandwidth quota. So, we simply
|
|
||||||
// request bandwidth from the bandwidth manager
|
|
||||||
ret = request_download_bandwidth(
|
|
||||||
&m_ses.m_download_channel
|
|
||||||
, t ? &t->m_bandwidth_channel[download_channel] : 0
|
|
||||||
, &m_bandwidth_channel[download_channel]
|
|
||||||
, !utp ? &m_ses.m_tcp_download_channel : 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// in this case, we're a local peer, and the settings
|
|
||||||
// are set to ignore rate limits for local peers. So,
|
|
||||||
// instead we rate limit ourself against the special
|
|
||||||
// global bandwidth channel for local peers, which defaults
|
|
||||||
// to unthrottled
|
|
||||||
ret = request_download_bandwidth(&m_ses.m_local_download_channel
|
|
||||||
, &m_bandwidth_channel[download_channel]);
|
|
||||||
}
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
m_channel_state[download_channel] |= peer_info::bw_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// we were just assigned 'ret' quota
|
|
||||||
TORRENT_ASSERT(ret > 0);
|
|
||||||
m_quota[download_channel] += ret;
|
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
|
||||||
peer_log(">>> ASSIGN BANDWIDTH [ bytes: %d ]", ret);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!can_read(&m_channel_state[download_channel]))
|
if (!can_read(&m_channel_state[download_channel]))
|
||||||
|
@ -5667,12 +5695,7 @@ namespace libtorrent
|
||||||
|
|
||||||
TORRENT_ASSERT(m_outstanding_bytes == outstanding_bytes);
|
TORRENT_ASSERT(m_outstanding_bytes == outstanding_bytes);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (m_channel_state[download_channel] == peer_info::bw_limit)
|
|
||||||
TORRENT_ASSERT(m_quota[download_channel] == 0);
|
|
||||||
if (m_channel_state[upload_channel] == peer_info::bw_limit)
|
|
||||||
TORRENT_ASSERT(m_quota[upload_channel] == 0);
|
|
||||||
*/
|
|
||||||
std::set<piece_block> unique;
|
std::set<piece_block> unique;
|
||||||
std::transform(m_download_queue.begin(), m_download_queue.end()
|
std::transform(m_download_queue.begin(), m_download_queue.end()
|
||||||
, std::inserter(unique, unique.begin()), boost::bind(&pending_block::block, _1));
|
, std::inserter(unique, unique.begin()), boost::bind(&pending_block::block, _1));
|
||||||
|
|
Loading…
Reference in New Issue