diff --git a/ChangeLog b/ChangeLog index c30a10696..3958ee9f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * added feature to set a separate global rate limit for local peers * added preset settings for low memory environments and seed machines min_memory_usage() and high_performance_seeder() * optimized overall memory usage for DHT nodes and requests, peer diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 54ec09f30..7f658630b 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -229,6 +229,11 @@ namespace libtorrent int upload_rate_limit() const; int download_rate_limit() const; + int local_upload_rate_limit() const; + int local_download_rate_limit() const; + + void set_local_download_rate_limit(int bytes_per_second); + void set_local_upload_rate_limit(int bytes_per_second); void set_download_rate_limit(int bytes_per_second); void set_upload_rate_limit(int bytes_per_second); @@ -426,9 +431,18 @@ namespace libtorrent bandwidth_manager m_download_rate; bandwidth_manager m_upload_rate; + // the global rate limiter bandwidth channels bandwidth_channel m_download_channel; bandwidth_channel m_upload_channel; + // bandwidth channels for local peers when + // rate limits are ignored. They are only + // throttled by these global rate limiters + // and they don't have a rate limit set by + // default + bandwidth_channel m_local_download_channel; + bandwidth_channel m_local_upload_channel; + bandwidth_channel* m_bandwidth_channel[2]; tracker_manager m_tracker_manager; diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 6646130c5..d9df58c0f 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -634,6 +634,16 @@ namespace libtorrent void on_disk_read_complete(int ret, disk_io_job const& j, peer_request r); void on_disk_write_complete(int ret, disk_io_job const& j , peer_request r, boost::shared_ptr t); + void request_upload_bandwidth( + bandwidth_channel* bwc1 + , bandwidth_channel* bwc2 = 0 + , bandwidth_channel* bwc3 = 0 + , bandwidth_channel* bwc4 = 0); + void request_download_bandwidth( + bandwidth_channel* bwc1 + , bandwidth_channel* bwc2 = 0 + , bandwidth_channel* bwc3 = 0 + , bandwidth_channel* bwc4 = 0); // keep the io_service running as long as we // have peer connections diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 151dc7aab..328cfcbb1 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -370,8 +370,12 @@ namespace libtorrent int upload_rate_limit() const; int download_rate_limit() const; + int local_upload_rate_limit() const; + int local_download_rate_limit() const; int max_half_open_connections() const; + void set_local_upload_rate_limit(int bytes_per_second); + void set_local_download_rate_limit(int bytes_per_second); void set_upload_rate_limit(int bytes_per_second); void set_download_rate_limit(int bytes_per_second); void set_max_uploads(int limit); diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index f9985c97c..664743567 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -3565,6 +3565,47 @@ namespace libtorrent } } + void peer_connection::request_upload_bandwidth( + bandwidth_channel* bwc1 + , bandwidth_channel* bwc2 + , bandwidth_channel* bwc3 + , bandwidth_channel* bwc4) + { + shared_ptr t = m_torrent.lock(); + int priority = 1 + is_interesting() * 2 + m_requests_in_buffer.size(); + // peers that we are not interested in are non-prioritized + m_channel_state[upload_channel] = peer_info::bw_limit; + m_ses.m_upload_rate.request_bandwidth(self() + , m_send_buffer.size(), priority + , bwc1, bwc2, bwc3, bwc4); +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ " + "upload: " << m_send_buffer.size() + << " prio: " << priority << "]\n"; +#endif + } + + void peer_connection::request_download_bandwidth( + bandwidth_channel* bwc1 + , bandwidth_channel* bwc2 + , bandwidth_channel* bwc3 + , bandwidth_channel* bwc4) + { + shared_ptr t = m_torrent.lock(); + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ " + "download: " << (m_download_queue.size() * 16 * 1024 + 30) + << " prio: " << m_priority << " ]\n"; +#endif + TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle); + TORRENT_ASSERT(m_outstanding_bytes >= 0); + m_channel_state[download_channel] = peer_info::bw_limit; + m_ses.m_download_rate.request_bandwidth(self() + , m_outstanding_bytes + 30, m_priority + , bwc1, bwc2, bwc3, bwc4); + } + void peer_connection::setup_send() { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -3576,26 +3617,27 @@ namespace libtorrent if (m_quota[upload_channel] == 0 && !m_send_buffer.empty() && !m_connecting - && t - && !m_ignore_bandwidth_limits) + && t) { - // in this case, we have data to send, but no - // bandwidth. So, we simply request bandwidth - // from the torrent - TORRENT_ASSERT(t); - int priority = 1 + is_interesting() * 2 + m_requests_in_buffer.size(); - // peers that we are not interested in are non-prioritized - m_channel_state[upload_channel] = peer_info::bw_limit; - m_ses.m_upload_rate.request_bandwidth(self() - , m_send_buffer.size(), priority - , &m_ses.m_upload_channel - , &t->m_bandwidth_channel[upload_channel] - , &m_bandwidth_channel[upload_channel]); -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ " - "upload: " << m_send_buffer.size() - << " prio: " << priority << "]\n"; -#endif + if (!m_ignore_bandwidth_limits) + { + // in this case, we have data to send, but no + // bandwidth. So, we simply request bandwidth + // from the bandwidth manager + request_upload_bandwidth( + &m_ses.m_upload_channel + , &t->m_bandwidth_channel[upload_channel] + , &m_bandwidth_channel[upload_channel]); + } + 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 + request_upload_bandwidth(&m_ses.m_local_upload_channel); + } return; } @@ -3656,22 +3698,27 @@ namespace libtorrent if (m_quota[download_channel] == 0 && !m_connecting - && t - && !m_ignore_bandwidth_limits) + && t) { -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " *** REQUEST_BANDWIDTH [ " - "download: " << (m_download_queue.size() * 16 * 1024 + 30) - << " prio: " << m_priority << " ]\n"; -#endif - TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle); - TORRENT_ASSERT(m_outstanding_bytes >= 0); - m_channel_state[download_channel] = peer_info::bw_limit; - m_ses.m_download_rate.request_bandwidth(self() - , m_outstanding_bytes + 30, m_priority - , &m_ses.m_download_channel - , &t->m_bandwidth_channel[download_channel] - , &m_bandwidth_channel[download_channel]); + if (!m_ignore_bandwidth_limits) + { + // in this case, we have outstanding data to + // receive, but no bandwidth quota. So, we simply + // request bandwidth from the bandwidth manager + request_download_bandwidth( + &m_ses.m_download_channel + , &t->m_bandwidth_channel[download_channel] + , &m_bandwidth_channel[download_channel]); + } + 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 + request_download_bandwidth(&m_ses.m_local_download_channel); + } return; } diff --git a/src/session.cpp b/src/session.cpp index 9f44a41e9..e76abad6b 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -652,6 +652,16 @@ namespace libtorrent m_impl->set_max_half_open_connections(limit); } + int session::local_upload_rate_limit() const + { + return m_impl->local_upload_rate_limit(); + } + + int session::local_download_rate_limit() const + { + return m_impl->local_download_rate_limit(); + } + int session::upload_rate_limit() const { return m_impl->upload_rate_limit(); @@ -662,6 +672,16 @@ namespace libtorrent return m_impl->download_rate_limit(); } + void session::set_local_upload_rate_limit(int bytes_per_second) + { + m_impl->set_local_upload_rate_limit(bytes_per_second); + } + + void session::set_local_download_rate_limit(int bytes_per_second) + { + m_impl->set_local_download_rate_limit(bytes_per_second); + } + void session::set_upload_rate_limit(int bytes_per_second) { m_impl->set_upload_rate_limit(bytes_per_second); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index cda991b21..afee8a582 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1772,7 +1772,8 @@ namespace aux { // 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 - if (m_upload_channel.throttle() != bandwidth_channel::inf && m_max_uploads > 0) + 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) @@ -2665,14 +2666,34 @@ namespace aux { m_half_open.limit(limit); } + void session_impl::set_local_download_rate_limit(int bytes_per_second) + { + mutex_t::scoped_lock l(m_mutex); + + INVARIANT_CHECK; + + if (bytes_per_second <= 0) bytes_per_second = 0; + m_local_download_channel.throttle(bytes_per_second); + } + + void session_impl::set_local_upload_rate_limit(int bytes_per_second) + { + mutex_t::scoped_lock l(m_mutex); + + INVARIANT_CHECK; + + if (bytes_per_second <= 0) bytes_per_second = 0; + m_local_upload_channel.throttle(bytes_per_second); + } + void session_impl::set_download_rate_limit(int bytes_per_second) { mutex_t::scoped_lock l(m_mutex); INVARIANT_CHECK; - if (bytes_per_second <= 0) bytes_per_second = bandwidth_channel::inf; - m_bandwidth_channel[peer_connection::download_channel]->throttle(bytes_per_second); + if (bytes_per_second <= 0) bytes_per_second = 0; + m_download_channel.throttle(bytes_per_second); } void session_impl::set_upload_rate_limit(int bytes_per_second) @@ -2681,8 +2702,8 @@ namespace aux { INVARIANT_CHECK; - if (bytes_per_second <= 0) bytes_per_second = bandwidth_channel::inf; - m_bandwidth_channel[peer_connection::upload_channel]->throttle(bytes_per_second); + if (bytes_per_second <= 0) bytes_per_second = 0; + m_upload_channel.throttle(bytes_per_second); } void session_impl::set_alert_dispatch(boost::function const& fun) @@ -2720,21 +2741,28 @@ namespace aux { return m_alerts.set_alert_queue_size_limit(queue_size_limit_); } + int session_impl::local_upload_rate_limit() const + { + mutex_t::scoped_lock l(m_mutex); + return m_local_upload_channel.throttle(); + } + + int session_impl::local_download_rate_limit() const + { + mutex_t::scoped_lock l(m_mutex); + return m_local_download_channel.throttle(); + } + int session_impl::upload_rate_limit() const { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - - int ret = m_bandwidth_channel[peer_connection::upload_channel]->throttle(); - return ret == (std::numeric_limits::max)() ? -1 : ret; + return m_upload_channel.throttle(); } int session_impl::download_rate_limit() const { mutex_t::scoped_lock l(m_mutex); - int ret = m_bandwidth_channel[peer_connection::download_channel]->throttle(); - return ret == (std::numeric_limits::max)() ? -1 : ret; + return m_download_channel.throttle(); } void session_impl::start_lsd()