feat: add setting to choose between lazy-verify or full verify (#4611)

This commit is contained in:
Charles Kerr 2023-01-18 02:09:29 -06:00 committed by GitHub
parent 3bc1a1be04
commit 33a7d131b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 148 additions and 46 deletions

View File

@ -84,6 +84,7 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri
* **script-torrent-done-filename:** String (default = "") Path to script.
* **script-torrent-done-seeding-enabled:** Boolean (default = false) Run a script when a torrent is done seeding. Environmental variables are passed in as detailed on the [Scripts](./Scripts.md) page
* **script-torrent-done-seeding-filename:** String (default = "") Path to script.
* **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)
#### Peers

View File

@ -18,7 +18,7 @@ using namespace std::literals;
namespace
{
auto constexpr MyStatic = std::array<std::string_view, 400>{ ""sv,
auto constexpr MyStatic = std::array<std::string_view, 401>{ ""sv,
"activeTorrentCount"sv,
"activity-date"sv,
"activityDate"sv,
@ -367,6 +367,7 @@ auto constexpr MyStatic = std::array<std::string_view, 400>{ ""sv,
"torrent-added"sv,
"torrent-added-notification-command"sv,
"torrent-added-notification-enabled"sv,
"torrent-added-verify-mode"sv,
"torrent-complete-notification-command"sv,
"torrent-complete-notification-enabled"sv,
"torrent-complete-sound-command"sv,

View File

@ -370,6 +370,7 @@ enum
TR_KEY_torrent_added,
TR_KEY_torrent_added_notification_command,
TR_KEY_torrent_added_notification_enabled,
TR_KEY_torrent_added_verify_mode,
TR_KEY_torrent_complete_notification_command,
TR_KEY_torrent_complete_notification_enabled,
TR_KEY_torrent_complete_sound_command,

View File

@ -72,7 +72,8 @@ struct tr_variant;
V(TR_KEY_trash_original_torrent_files, should_delete_source_torrents, bool, false, "") \
V(TR_KEY_umask, umask, tr_mode_t, 022, "") \
V(TR_KEY_upload_slots_per_torrent, upload_slots_per_torrent, size_t, 8U, "") \
V(TR_KEY_utp_enabled, utp_enabled, bool, true, "")
V(TR_KEY_utp_enabled, utp_enabled, bool, true, "") \
V(TR_KEY_torrent_added_verify_mode, torrent_added_verify_mode, tr_verify_added_mode, TR_VERIFY_ADDED_FAST, "")
struct tr_session_settings
{

View File

@ -707,6 +707,11 @@ public:
return !settings_.should_start_added_torrents;
}
[[nodiscard]] constexpr auto shouldFullyVerifyAddedTorrents() const noexcept
{
return settings_.torrent_added_verify_mode == TR_VERIFY_ADDED_FULL;
}
[[nodiscard]] constexpr auto shouldDeleteSource() const noexcept
{
return settings_.should_delete_source_torrents;

View File

@ -1188,7 +1188,7 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
opts.has_local_data = has_local_data;
torrentStart(tor, opts);
}
else if (isNewTorrentASeed(tor))
else if (!session->shouldFullyVerifyAddedTorrents() && isNewTorrentASeed(tor))
{
tor->completion.setHasAll();
tor->doneDate = tor->addedDate;

View File

@ -60,6 +60,16 @@ using tr_priority_t = int8_t;
#define TR_RPC_SESSION_ID_HEADER "X-Transmission-Session-Id"
enum tr_verify_added_mode
{
// See discussion @ https://github.com/transmission/transmission/pull/2626
// Let newly-added torrents skip upfront verify do it on-demand later.
TR_VERIFY_ADDED_FAST = 0,
// Force torrents to be fully verified as they are added.
TR_VERIFY_ADDED_FULL = 1
};
enum tr_preallocation_mode
{
TR_PREALLOCATE_NONE = 0,

View File

@ -14,9 +14,40 @@
using namespace std::literals;
namespace
{
auto constexpr EncryptionKeys = std::array<std::pair<std::string_view, tr_encryption_mode>, 3>{ {
{ "required", TR_ENCRYPTION_REQUIRED },
{ "preferred", TR_ENCRYPTION_PREFERRED },
{ "allowed", TR_CLEAR_PREFERRED },
} };
auto constexpr LogKeys = std::array<std::pair<std::string_view, tr_log_level>, 7>{ {
{ "critical", TR_LOG_CRITICAL },
{ "debug", TR_LOG_DEBUG },
{ "error", TR_LOG_ERROR },
{ "info", TR_LOG_INFO },
{ "off", TR_LOG_OFF },
{ "trace", TR_LOG_TRACE },
{ "warn", TR_LOG_WARN },
} };
auto constexpr PreallocationKeys = std::array<std::pair<std::string_view, tr_preallocation_mode>, 5>{ {
{ "off", TR_PREALLOCATE_NONE },
{ "none", TR_PREALLOCATE_NONE },
{ "fast", TR_PREALLOCATE_SPARSE },
{ "sparse", TR_PREALLOCATE_SPARSE },
{ "full", TR_PREALLOCATE_FULL },
} };
auto constexpr VerifyModeKeys = std::array<std::pair<std::string_view, tr_verify_added_mode>, 2>{ {
{ "fast", TR_VERIFY_ADDED_FAST },
{ "full", TR_VERIFY_ADDED_FULL },
} };
} // namespace
namespace libtransmission
{
template<>
std::optional<bool> VariantConverter::load<bool>(tr_variant* src)
{
@ -55,21 +86,10 @@ void VariantConverter::save<double>(tr_variant* tgt, double const& val)
// ---
namespace EncryptionHelpers
{
// clang-format off
static auto constexpr Keys = std::array<std::pair<std::string_view, tr_encryption_mode>, 3>{{
{ "required", TR_ENCRYPTION_REQUIRED },
{ "preferred", TR_ENCRYPTION_PREFERRED },
{ "allowed", TR_CLEAR_PREFERRED }
}};
// clang-format on
} // namespace EncryptionHelpers
template<>
std::optional<tr_encryption_mode> VariantConverter::load<tr_encryption_mode>(tr_variant* src)
{
using namespace EncryptionHelpers;
static constexpr auto Keys = EncryptionKeys;
if (auto val = std::string_view{}; tr_variantGetStrView(src, &val))
{
@ -106,25 +126,10 @@ void VariantConverter::save<tr_encryption_mode>(tr_variant* tgt, tr_encryption_m
// ---
namespace LogLevelHelpers
{
// clang-format off
static auto constexpr Keys = std::array<std::pair<std::string_view, tr_log_level>, 7>{ {
{ "critical", TR_LOG_CRITICAL },
{ "debug", TR_LOG_DEBUG },
{ "error", TR_LOG_ERROR },
{ "info", TR_LOG_INFO },
{ "off", TR_LOG_OFF },
{ "trace", TR_LOG_TRACE },
{ "warn", TR_LOG_WARN },
}};
// clang-format on
} // namespace LogLevelHelpers
template<>
std::optional<tr_log_level> VariantConverter::load<tr_log_level>(tr_variant* src)
{
using namespace LogLevelHelpers;
static constexpr auto Keys = LogKeys;
if (auto val = std::string_view{}; tr_variantGetStrView(src, &val))
{
@ -207,23 +212,10 @@ void VariantConverter::save<tr_port>(tr_variant* tgt, tr_port const& val)
// ---
namespace PreallocationModeHelpers
{
// clang-format off
static auto constexpr Keys = std::array<std::pair<std::string_view, tr_preallocation_mode>, 5>{{
{ "off", TR_PREALLOCATE_NONE },
{ "none", TR_PREALLOCATE_NONE },
{ "fast", TR_PREALLOCATE_SPARSE },
{ "sparse", TR_PREALLOCATE_SPARSE },
{ "full", TR_PREALLOCATE_FULL },
}};
// clang-format on
} // namespace PreallocationModeHelpers
template<>
std::optional<tr_preallocation_mode> VariantConverter::load<tr_preallocation_mode>(tr_variant* src)
{
using namespace PreallocationModeHelpers;
static constexpr auto Keys = PreallocationKeys;
if (auto val = std::string_view{}; tr_variantGetStrView(src, &val))
{
@ -320,4 +312,53 @@ void VariantConverter::save<tr_tos_t>(tr_variant* tgt, tr_tos_t const& val)
tr_variantInitStr(tgt, val.toString());
}
// ---
template<>
std::optional<tr_verify_added_mode> VariantConverter::load<tr_verify_added_mode>(tr_variant* src)
{
static constexpr auto& Keys = VerifyModeKeys;
if (auto val = std::string_view{}; tr_variantGetStrView(src, &val))
{
auto const needle = tr_strlower(tr_strvStrip(val));
for (auto const& [name, value] : Keys)
{
if (name == needle)
{
return value;
}
}
}
if (auto val = int64_t{}; tr_variantGetInt(src, &val))
{
for (auto const& [name, value] : Keys)
{
if (value == val)
{
return value;
}
}
}
return {};
}
template<>
void VariantConverter::save<tr_verify_added_mode>(tr_variant* tgt, tr_verify_added_mode const& val)
{
for (auto const& [key, value] : VerifyModeKeys)
{
if (value == val)
{
tr_variantInitStrView(tgt, key);
return;
}
}
tr_variantInitInt(tgt, val);
}
} // namespace libtransmission

View File

@ -406,3 +406,45 @@ TEST_F(SettingsTest, canSaveTos)
EXPECT_EQ(ChangedValue.toString(), val);
tr_variantClear(&dict);
}
TEST_F(SettingsTest, canLoadVerify)
{
static auto constexpr Key = TR_KEY_torrent_added_verify_mode;
static auto constexpr ChangedValue = TR_VERIFY_ADDED_FULL;
auto settings = std::make_unique<tr_session_settings>();
auto const default_value = settings->torrent_added_verify_mode;
ASSERT_NE(ChangedValue, default_value);
auto dict = tr_variant{};
tr_variantInitDict(&dict, 1);
tr_variantDictAddStrView(&dict, Key, "full");
settings->load(&dict);
tr_variantClear(&dict);
EXPECT_EQ(ChangedValue, settings->torrent_added_verify_mode);
settings = std::make_unique<tr_session_settings>();
tr_variantInitDict(&dict, 1);
tr_variantDictAddInt(&dict, Key, ChangedValue);
settings->load(&dict);
tr_variantClear(&dict);
EXPECT_EQ(ChangedValue, settings->torrent_added_verify_mode);
}
TEST_F(SettingsTest, canSaveVerify)
{
static auto constexpr Key = TR_KEY_torrent_added_verify_mode;
static auto constexpr ChangedValue = TR_VERIFY_ADDED_FULL;
auto settings = tr_session_settings{};
ASSERT_NE(ChangedValue, settings.torrent_added_verify_mode);
auto dict = tr_variant{};
tr_variantInitDict(&dict, 100);
settings.torrent_added_verify_mode = ChangedValue;
settings.save(&dict);
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&dict, Key, &val));
EXPECT_EQ("full", val);
tr_variantClear(&dict);
}