diff --git a/ChangeLog b/ChangeLog index 4dd679faf..0bd37493a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ * fix uTP edge case where udp socket buffer fills up * fix nagle implementation in uTP + * DHT performance improvement * attempt to handle ERROR_CANT_WAIT disk error on windows * improve peers exchanged over PEX * fixed rare crash in ut_metadata extension diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index e9118df7c..b49e52fa6 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -268,19 +268,13 @@ namespace libtorrent { rate_limited_udp_socket(io_service& ios, connection_queue& cc); void set_rate_limit(int limit) { m_rate_limit = limit; } - bool can_send() const { return int(m_queue.size()) >= m_queue_size_limit; } bool send(udp::endpoint const& ep, char const* p, int len, error_code& ec, int flags = 0); - void close(); private: - void on_tick(error_code const& e); - deadline_timer m_timer; - int m_queue_size_limit; int m_rate_limit; int m_quota; ptime m_last_tick; - std::deque m_queue; }; } diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index a18ef09ae..e97d0d3df 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -1332,77 +1332,35 @@ void udp_socket::hung_up(error_code const& e) rate_limited_udp_socket::rate_limited_udp_socket(io_service& ios , connection_queue& cc) : udp_socket(ios, cc) - , m_timer(ios) - , m_queue_size_limit(200) - , m_rate_limit(4000) - , m_quota(4000) + , m_rate_limit(8000) + , m_quota(8000) , m_last_tick(time_now()) { #if defined TORRENT_ASIO_DEBUGGING add_outstanding_async("rate_limited_udp_socket::on_tick"); #endif - error_code ec; - m_timer.expires_from_now(seconds(1), ec); - m_timer.async_wait(boost::bind(&rate_limited_udp_socket::on_tick, this, _1)); - TORRENT_ASSERT_VAL(!ec, ec); } bool rate_limited_udp_socket::send(udp::endpoint const& ep, char const* p , int len, error_code& ec, int flags) { - if (m_quota < len) - { - if (int(m_queue.size()) >= m_queue_size_limit && (flags & dont_drop) == 0) - return false; - m_queue.push_back(queued_packet()); - queued_packet& qp = m_queue.back(); - qp.ep = ep; - qp.flags = flags; - qp.buf.insert(qp.buf.begin(), p, p + len); - return true; - } + ptime now = time_now_hires(); + time_duration delta = now - m_last_tick; + m_last_tick = now; + + // add any new quota we've accrued since last time + m_quota += boost::uint64_t(m_rate_limit) * total_microseconds(delta) / 1000000; + + // allow 3 seconds worth of burst + if (m_quota > 3 * m_rate_limit) m_quota = 3 * m_rate_limit; + + // if there's no quota, and it's OK to drop, just + // drop the packet + if (m_quota < len && (flags & dont_drop) == 0) return false; m_quota -= len; + if (m_quota < 0) m_quota = 0; udp_socket::send(ep, p, len, ec, flags); return true; } -void rate_limited_udp_socket::on_tick(error_code const& e) -{ -#if defined TORRENT_ASIO_DEBUGGING - complete_async("rate_limited_udp_socket::on_tick"); -#endif - if (e) return; - if (is_closed()) return; - error_code ec; - ptime now = time_now_hires(); -#if defined TORRENT_ASIO_DEBUGGING - add_outstanding_async("rate_limited_udp_socket::on_tick"); -#endif - m_timer.expires_at(now + seconds(1), ec); - m_timer.async_wait(boost::bind(&rate_limited_udp_socket::on_tick, this, _1)); - - time_duration delta = now - m_last_tick; - m_last_tick = now; - if (m_quota < m_rate_limit) m_quota += boost::uint64_t(m_rate_limit) * total_milliseconds(delta) / 1000; - - if (m_queue.empty()) return; - - while (!m_queue.empty() && int(m_queue.front().buf.size()) <= m_quota) - { - queued_packet const& p = m_queue.front(); - TORRENT_ASSERT(m_quota >= int(p.buf.size())); - m_quota -= p.buf.size(); - error_code ec; - udp_socket::send(p.ep, &p.buf[0], p.buf.size(), ec, p.flags); - m_queue.pop_front(); - } -} - -void rate_limited_udp_socket::close() -{ - error_code ec; - m_timer.cancel(ec); - udp_socket::close(); -} -