From f06cb37c06900911178961ef4af897549a427fa3 Mon Sep 17 00:00:00 2001 From: Mrnikifabio <46873729+Mrnikifabio@users.noreply.github.com> Date: Mon, 12 Feb 2024 16:30:40 +0100 Subject: [PATCH] feat: added `sleep-per-seconds-during-verify` to settings.json (#6572) * feat: added `sleep-per-seconds-during-verify` to settings.json * Ensuring `sleep_per_seconds_during_verify > 0` in `verify_torrent` for better performance * `#include` list reordered alphabetically * fix: `[readability-inconsistent-declaration-parameter-name]` warning --- docs/Editing-Configuration-Files.md | 1 + libtransmission/quark.cc | 1 + libtransmission/quark.h | 1 + libtransmission/session-settings.h | 2 ++ libtransmission/session.cc | 6 ++++ libtransmission/variant-converters.cc | 18 +++++++++++ libtransmission/verify.cc | 27 +++++++++++------ libtransmission/verify.h | 14 ++++++++- tests/libtransmission/settings-test.cc | 42 ++++++++++++++++++++++++++ 9 files changed, 102 insertions(+), 10 deletions(-) diff --git a/docs/Editing-Configuration-Files.md b/docs/Editing-Configuration-Files.md index d38a56c69..bb6d4a7ed 100644 --- a/docs/Editing-Configuration-Files.md +++ b/docs/Editing-Configuration-Files.md @@ -91,6 +91,7 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri * **torrent-added-verify-mode:** String ("fast", "full", default: "fast") Whether newly-added torrents' local data should be fully verified when added, or wait and verify them on-demand later. See [#2626](https://github.com/transmission/transmission/pull/2626) for more discussion. * **utp-enabled:** Boolean (default = true) Enable [Micro Transport Protocol (µTP)](https://en.wikipedia.org/wiki/Micro_Transport_Protocol) * **preferred-transport:** String ("utp" = Prefer µTP, "tcp" = Prefer TCP; default = "utp") Choose your preferred transport protocol (has no effect if one of them is disabled). + * **sleep-per-seconds-during-verify:** Number (default = 100) Controls the duration in milliseconds for which the verification process will pause to reduce disk I/O pressure. #### Peers * **bind-address-ipv4:** String (default = "") Where to listen for peer connections. When no valid IPv4 address is provided, Transmission will bind to "0.0.0.0". diff --git a/libtransmission/quark.cc b/libtransmission/quark.cc index 408d50cfa..44ffe72df 100644 --- a/libtransmission/quark.cc +++ b/libtransmission/quark.cc @@ -351,6 +351,7 @@ auto constexpr MyStatic = std::array{ "size-bytes"sv, "size-units"sv, "sizeWhenDone"sv, + "sleep-per-seconds-during-verify"sv, "sort-mode"sv, "sort-reversed"sv, "source"sv, diff --git a/libtransmission/quark.h b/libtransmission/quark.h index 333f41f9c..8375148ce 100644 --- a/libtransmission/quark.h +++ b/libtransmission/quark.h @@ -352,6 +352,7 @@ enum TR_KEY_size_bytes, TR_KEY_size_units, TR_KEY_sizeWhenDone, + TR_KEY_sleep_per_seconds_during_verify, TR_KEY_sort_mode, TR_KEY_sort_reversed, TR_KEY_source, diff --git a/libtransmission/session-settings.h b/libtransmission/session-settings.h index 62d4817aa..9046986a9 100644 --- a/libtransmission/session-settings.h +++ b/libtransmission/session-settings.h @@ -5,6 +5,7 @@ #pragma once +#include // for tr_sleep_per_seconds_during_verify #include // for size_t #include @@ -67,6 +68,7 @@ struct tr_variant; V(TR_KEY_script_torrent_done_seeding_filename, script_torrent_done_seeding_filename, std::string, "", "") \ V(TR_KEY_seed_queue_enabled, seed_queue_enabled, bool, false, "") \ V(TR_KEY_seed_queue_size, seed_queue_size, size_t, 10U, "") \ + V(TR_KEY_sleep_per_seconds_during_verify, sleep_per_seconds_during_verify, std::chrono::milliseconds, 100, "") \ V(TR_KEY_speed_limit_down, speed_limit_down, size_t, 100U, "") \ V(TR_KEY_speed_limit_down_enabled, speed_limit_down_enabled, bool, false, "") \ V(TR_KEY_speed_limit_up, speed_limit_up, size_t, 100U, "") \ diff --git a/libtransmission/session.cc b/libtransmission/session.cc index f9fa242c0..7e79b6989 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -871,6 +871,12 @@ void tr_session::setSettings(tr_session_settings&& settings_in, bool force) dht_ = tr_dht::create(dht_mediator_, localPeerPort(), udp_core_->socket4(), udp_core_->socket6()); } + if (auto const& val = new_settings.sleep_per_seconds_during_verify; + force || val != old_settings.sleep_per_seconds_during_verify) + { + verifier_->set_sleep_per_seconds_during_verify(val); + } + // We need to update bandwidth if speed settings changed. // It's a harmless call, so just call it instead of checking for settings changes update_bandwidth(TR_UP); diff --git a/libtransmission/variant-converters.cc b/libtransmission/variant-converters.cc index fc73a6106..dfd910db9 100644 --- a/libtransmission/variant-converters.cc +++ b/libtransmission/variant-converters.cc @@ -10,6 +10,7 @@ #include #include #include +#include //std::chrono::milliseconds #include @@ -424,4 +425,21 @@ tr_variant VariantConverter::save(tr_verify_added_mode con return static_cast(val); } +template<> +std::optional VariantConverter::load(tr_variant const& src) +{ + if (auto val = src.get_if(); val != nullptr) + { + return std::chrono::milliseconds(*val); + } + + return {}; +} + +template<> +tr_variant VariantConverter::save(std::chrono::milliseconds const& val) +{ + return val.count(); +} + } // namespace libtransmission diff --git a/libtransmission/verify.cc b/libtransmission/verify.cc index 78bb921c5..ac20b1ed6 100644 --- a/libtransmission/verify.cc +++ b/libtransmission/verify.cc @@ -25,15 +25,16 @@ using namespace std::chrono_literals; namespace { -auto constexpr SleepPerSecondDuringVerify = 100ms; - [[nodiscard]] auto current_time_secs() { return std::chrono::time_point_cast(std::chrono::steady_clock::now()); } } // namespace -void tr_verify_worker::verify_torrent(Mediator& verify_mediator, std::atomic const& abort_flag) +void tr_verify_worker::verify_torrent( + Mediator& verify_mediator, + std::atomic const& abort_flag, + std::chrono::milliseconds const sleep_per_seconds_during_verify) { verify_mediator.on_verify_started(); @@ -89,12 +90,15 @@ void tr_verify_worker::verify_torrent(Mediator& verify_mediator, std::atomicfinish() == metainfo.piece_hash(piece); verify_mediator.on_piece_checked(piece, has_piece); - /* sleeping even just a few msec per second goes a long - * way towards reducing IO load... */ - if (auto const now = current_time_secs(); last_slept_at != now) + if (sleep_per_seconds_during_verify > std::chrono::milliseconds::zero()) { - last_slept_at = now; - std::this_thread::sleep_for(SleepPerSecondDuringVerify); + /* sleeping even just a few msec per second goes a long + * way towards reducing IO load... */ + if (auto const now = current_time_secs(); last_slept_at != now) + { + last_slept_at = now; + std::this_thread::sleep_for(sleep_per_seconds_during_verify); + } } sha->clear(); @@ -148,7 +152,7 @@ void tr_verify_worker::verify_thread_func() current_node_ = std::move(todo_.extract(std::begin(todo_)).value()); } - verify_torrent(*current_node_->mediator_, stop_current_); + verify_torrent(*current_node_->mediator_, stop_current_, sleep_per_seconds_during_verify_); } } @@ -201,6 +205,11 @@ tr_verify_worker::~tr_verify_worker() } } +void tr_verify_worker::set_sleep_per_seconds_during_verify(std::chrono::milliseconds const sleep_per_seconds_during_verify) +{ + sleep_per_seconds_during_verify_ = sleep_per_seconds_during_verify; +} + int tr_verify_worker::Node::compare(Node const& that) const noexcept { // prefer higher-priority torrents diff --git a/libtransmission/verify.h b/libtransmission/verify.h index 1790a6c5f..4572fd8c3 100644 --- a/libtransmission/verify.h +++ b/libtransmission/verify.h @@ -47,6 +47,13 @@ public: void remove(tr_sha1_digest_t const& info_hash); + void set_sleep_per_seconds_during_verify(std::chrono::milliseconds sleep_per_seconds_during_verify); + + [[nodiscard]] constexpr auto sleep_per_seconds_during_verify() const noexcept + { + return sleep_per_seconds_during_verify_; + } + private: struct Node { @@ -72,7 +79,10 @@ private: tr_priority_t priority_; }; - static void verify_torrent(Mediator& verify_mediator, std::atomic const& abort_flag); + static void verify_torrent( + Mediator& verify_mediator, + std::atomic const& abort_flag, + std::chrono::milliseconds sleep_per_seconds_during_verify); void verify_thread_func(); @@ -85,4 +95,6 @@ private: std::atomic stop_current_ = false; std::condition_variable stop_current_cv_; + + std::chrono::milliseconds sleep_per_seconds_during_verify_; }; diff --git a/tests/libtransmission/settings-test.cc b/tests/libtransmission/settings-test.cc index 665b2c741..ccdd730a6 100644 --- a/tests/libtransmission/settings-test.cc +++ b/tests/libtransmission/settings-test.cc @@ -454,3 +454,45 @@ TEST_F(SettingsTest, canSavePreferredTransport) EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val)); EXPECT_EQ("tcp", val); } + +TEST_F(SettingsTest, canLoadSleepPerSecondsDuringVerify) +{ + static auto constexpr Key = TR_KEY_sleep_per_seconds_during_verify; + auto constexpr ExpectedValue = 90ms; + + auto settings = std::make_unique(); + auto const default_value = settings->sleep_per_seconds_during_verify; + ASSERT_NE(ExpectedValue, default_value); + + auto var = tr_variant{}; + tr_variantInitDict(&var, 1); + tr_variantDictAddInt(&var, Key, ExpectedValue.count()); + settings->load(var); + EXPECT_EQ(ExpectedValue, settings->sleep_per_seconds_during_verify); + var.clear(); + + settings = std::make_unique(); + tr_variantInitDict(&var, 1); + tr_variantDictAddInt(&var, Key, 90); + settings->load(var); + EXPECT_EQ(ExpectedValue, settings->sleep_per_seconds_during_verify); +} + +TEST_F(SettingsTest, canSaveSleepPerSecondsDuringVerify) +{ + static auto constexpr Key = TR_KEY_sleep_per_seconds_during_verify; + static auto constexpr ExpectedValue = 90ms; + + auto settings = tr_session_settings{}; + auto const default_value = settings.sleep_per_seconds_during_verify; + ASSERT_NE(ExpectedValue, default_value); + + auto var = tr_variant{}; + tr_variantInitDict(&var, 100); + settings.sleep_per_seconds_during_verify = ExpectedValue; + var = settings.settings(); + + int64_t val_raw; + EXPECT_TRUE(tr_variantDictFindInt(&var, Key, &val_raw)); + EXPECT_EQ(ExpectedValue, std::chrono::milliseconds{ val_raw }); +} \ No newline at end of file