From 62240393ed056099a6a2ee60d778ac19928ef451 Mon Sep 17 00:00:00 2001 From: Yat Ho Date: Sat, 24 Aug 2024 10:46:37 +0800 Subject: [PATCH] feat: configurable client `reqq` (#7030) * chore: housekeeping * refactor: raise client reqq value * feat: allow configuring client reqq value * feat: expose reqq config in RPC * test: add new key * code review: distinguish client vs peer * docs: fix new config name --------- Co-authored-by: Charles Kerr --- docs/Editing-Configuration-Files.md | 1 + docs/rpc-spec.md | 1 + libtransmission/peer-mgr.cc | 2 +- libtransmission/peer-msgs.cc | 20 ++++++++++++-------- libtransmission/rpcimpl.cc | 6 ++++++ libtransmission/session.h | 12 ++++++++++++ tests/libtransmission/rpc-test.cc | 11 ++++++----- 7 files changed, 39 insertions(+), 14 deletions(-) diff --git a/docs/Editing-Configuration-Files.md b/docs/Editing-Configuration-Files.md index 41d9015e9..4414ee7be 100644 --- a/docs/Editing-Configuration-Files.md +++ b/docs/Editing-Configuration-Files.md @@ -101,6 +101,7 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri * **peer-limit-global:** Number (default = 200) * **peer-limit-per-torrent:** Number (default = 50) * **peer-socket-tos:** String (default = "le") Set the [DiffServ](https://en.wikipedia.org/wiki/Differentiated_services) parameter for outgoing packets. Allowed values are lowercase DSCP names. See the `tr_tos_t` class from `libtransmission/net.h` for the exact list of possible values. + * **reqq:** Number (default = 2000) The number of outstanding block requests a peer is allowed to queue in the client. The higher this number, the higher the max possible upload speed towards each peer. #### Peer Port * **peer-port:** Number (default = 51413) diff --git a/docs/rpc-spec.md b/docs/rpc-spec.md index 964f3091e..485459f4f 100644 --- a/docs/rpc-spec.md +++ b/docs/rpc-spec.md @@ -554,6 +554,7 @@ Response arguments: `path`, `name`, and `id`, holding the torrent ID integer | `queue-stalled-enabled` | boolean | whether or not to consider idle torrents as stalled | `queue-stalled-minutes` | number | torrents that are idle for N minuets aren't counted toward seed-queue-size or download-queue-size | `rename-partial-files` | boolean | true means append `.part` to incomplete files +| `reqq` | number | the number of outstanding block requests a peer is allowed to queue in the client | `rpc-version-minimum` | number | the minimum RPC API version supported | `rpc-version-semver` | string | the current RPC API version in a [semver](https://semver.org)-compatible string | `rpc-version` | number | the current RPC API version diff --git a/libtransmission/peer-mgr.cc b/libtransmission/peer-mgr.cc index 25d58c705..046dd2ebe 100644 --- a/libtransmission/peer-mgr.cc +++ b/libtransmission/peer-mgr.cc @@ -905,7 +905,7 @@ EXIT: // --- // number of bad pieces a peer is allowed to send before we ban them - static auto constexpr MaxBadPiecesPerPeer = 5; + static auto constexpr MaxBadPiecesPerPeer = 5U; // how long we'll let requests we've made linger before we cancel them static auto constexpr RequestTtlSecs = 90; diff --git a/libtransmission/peer-msgs.cc b/libtransmission/peer-msgs.cc index d85a7e97a..e66d72a35 100644 --- a/libtransmission/peer-msgs.cc +++ b/libtransmission/peer-msgs.cc @@ -178,7 +178,7 @@ auto constexpr KeepaliveIntervalSecs = time_t{ 100 }; auto constexpr MetadataReqQ = size_t{ 64U }; -auto constexpr ReqQ = 512; +auto constexpr PeerReqQDefault = 500U; // when we're making requests from another peer, // batch them together to send enough requests to @@ -571,6 +571,11 @@ private: void update_block_requests(); + [[nodiscard]] constexpr auto client_reqq() const noexcept + { + return session->reqq(); + } + // --- [[nodiscard]] std::optional pop_next_metadata_request() @@ -702,7 +707,7 @@ private: // if the peer supports the Extension Protocol in BEP 10 and // supplied a reqq argument, it's stored here. - std::optional reqq_; + std::optional peer_reqq_; std::unique_ptr pex_timer_; @@ -1131,9 +1136,8 @@ void tr_peerMsgsImpl::send_ltep_handshake() // https://www.bittorrent.org/beps/bep_0010.html // An integer, the number of outstanding request messages this - // client supports without dropping any. The default in in - // libtorrent is 250. - tr_variantDictAddInt(&val, TR_KEY_reqq, ReqQ); + // client supports without dropping any. + tr_variantDictAddInt(&val, TR_KEY_reqq, client_reqq()); // https://www.bittorrent.org/beps/bep_0010.html // A string containing the compact representation of the ip address this peer sees @@ -1289,7 +1293,7 @@ void tr_peerMsgsImpl::parse_ltep_handshake(MessageReader& payload) /* get peer's maximum request queue size */ if (auto reqq_in = int64_t{}; tr_variantDictFindInt(&*var, TR_KEY_reqq, &reqq_in)) { - reqq_ = reqq_in; + peer_reqq_ = reqq_in; } } @@ -1994,7 +1998,7 @@ bool tr_peerMsgsImpl::is_valid_request(peer_request const& req) const return false; } - if (std::size(peer_requested_) >= ReqQ) + if (std::size(peer_requested_) >= client_reqq()) { logtrace(this, "rejecting request ... reqq is full"); return false; @@ -2045,7 +2049,7 @@ size_t tr_peerMsgsImpl::max_available_reqs() const static auto constexpr Floor = size_t{ 32 }; static size_t constexpr Seconds = RequestBufSecs; size_t const estimated_blocks_in_period = (rate.base_quantity() * Seconds) / tr_block_info::BlockSize; - auto const ceil = reqq_.value_or(250); + auto const ceil = peer_reqq_.value_or(PeerReqQDefault); return std::clamp(estimated_blocks_in_period, Floor, ceil); } diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 7b61f2023..720502476 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -1695,6 +1695,11 @@ char const* sessionSet(tr_session* session, tr_variant::Map const& args_in, tr_v tr_sessionSetPeerLimitPerTorrent(session, *val); } + if (auto const val = args_in.value_if(TR_KEY_reqq); val && val > 0) + { + session->set_reqq(*val); + } + if (auto const val = args_in.value_if(TR_KEY_pex_enabled)) { tr_sessionSetPexEnabled(session, *val); @@ -1955,6 +1960,7 @@ char const* sessionStats(tr_session* session, tr_variant::Map const& /*args_in*/ case TR_KEY_queue_stalled_enabled: return session.queueStalledEnabled(); case TR_KEY_queue_stalled_minutes: return session.queueStalledMinutes(); case TR_KEY_rename_partial_files: return session.isIncompleteFileNamingEnabled(); + case TR_KEY_reqq: return session.reqq(); case TR_KEY_rpc_version: return RpcVersion; case TR_KEY_rpc_version_minimum: return RpcVersionMin; case TR_KEY_rpc_version_semver: return RpcVersionSemver; diff --git a/libtransmission/session.h b/libtransmission/session.h index 572e53dc8..662f1b5e8 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -398,6 +398,7 @@ public: size_t peer_limit_global = TR_DEFAULT_PEER_LIMIT_GLOBAL; size_t peer_limit_per_torrent = TR_DEFAULT_PEER_LIMIT_TORRENT; size_t queue_stalled_minutes = 30U; + size_t reqq = 2000U; size_t seed_queue_size = 10U; size_t speed_limit_down = 100U; size_t speed_limit_up = 100U; @@ -465,6 +466,7 @@ public: { TR_KEY_ratio_limit, &ratio_limit }, { TR_KEY_ratio_limit_enabled, &ratio_limit_enabled }, { TR_KEY_rename_partial_files, &is_incomplete_file_naming_enabled }, + { TR_KEY_reqq, &reqq }, { TR_KEY_scrape_paused_torrents_enabled, &should_scrape_paused_torrents }, { TR_KEY_script_torrent_added_enabled, &script_torrent_added_enabled }, { TR_KEY_script_torrent_added_filename, &script_torrent_added_filename }, @@ -693,6 +695,16 @@ public: return settings().peer_limit_per_torrent; } + [[nodiscard]] constexpr auto reqq() const noexcept + { + return settings().reqq; + } + + constexpr void set_reqq(size_t reqq) noexcept + { + settings_.reqq = reqq; + } + // bandwidth [[nodiscard]] tr_bandwidth& getBandwidthGroup(std::string_view name); diff --git a/tests/libtransmission/rpc-test.cc b/tests/libtransmission/rpc-test.cc index 41b4ea4c3..d18239b98 100644 --- a/tests/libtransmission/rpc-test.cc +++ b/tests/libtransmission/rpc-test.cc @@ -168,7 +168,7 @@ TEST_F(RpcTest, sessionGet) EXPECT_TRUE(tr_variantDictFindDict(&response, TR_KEY_arguments, &args)); // what we expected - auto const expected_keys = std::array{ + static auto constexpr ExpectedKeys = std::array{ TR_KEY_alt_speed_down, TR_KEY_alt_speed_enabled, TR_KEY_alt_speed_time_begin, @@ -204,6 +204,7 @@ TEST_F(RpcTest, sessionGet) TR_KEY_queue_stalled_enabled, TR_KEY_queue_stalled_minutes, TR_KEY_rename_partial_files, + TR_KEY_reqq, TR_KEY_rpc_version, TR_KEY_rpc_version_minimum, TR_KEY_rpc_version_semver, @@ -242,8 +243,8 @@ TEST_F(RpcTest, sessionGet) auto missing_keys = std::vector{}; std::set_difference( - std::begin(expected_keys), - std::end(expected_keys), + std::begin(ExpectedKeys), + std::end(ExpectedKeys), std::begin(actual_keys), std::end(actual_keys), std::inserter(missing_keys, std::begin(missing_keys))); @@ -253,8 +254,8 @@ TEST_F(RpcTest, sessionGet) std::set_difference( std::begin(actual_keys), std::end(actual_keys), - std::begin(expected_keys), - std::end(expected_keys), + std::begin(ExpectedKeys), + std::end(ExpectedKeys), std::inserter(unexpected_keys, std::begin(unexpected_keys))); EXPECT_EQ(decltype(unexpected_keys){}, unexpected_keys);