diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index ab49ec39bfd..ee53ad938c3 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -239,7 +239,7 @@ char const* torrentStop(tr_session* session, tr_variant* args_in, tr_variant* /* { for (auto* tor : getTorrents(session, args_in)) { - if (tor->is_running() || tor->is_queued() || tor->verify_state() != TR_VERIFY_NONE) + if (tor->activity() != TR_STATUS_STOPPED) { tor->is_stopping_ = true; session->rpcNotify(TR_RPC_TORRENT_STOPPED, tor); diff --git a/libtransmission/session.cc b/libtransmission/session.cc index 885cf380129..f59697d4da7 100644 --- a/libtransmission/session.cc +++ b/libtransmission/session.cc @@ -2004,6 +2004,24 @@ size_t tr_session::countQueueFreeSlots(tr_direction dir) const noexcept // --- +void tr_session::verify_remove(tr_torrent const* const tor) +{ + if (verifier_) + { + verifier_->remove(tor->info_hash()); + } +} + +void tr_session::verify_add(tr_torrent* const tor) +{ + if (verifier_) + { + verifier_->add(std::make_unique(tor), tor->get_priority()); + } +} + +// --- + void tr_session::closeTorrentFiles(tr_torrent* tor) noexcept { this->cache->flush_torrent(tor); @@ -2122,8 +2140,6 @@ tr_session::tr_session(std::string_view config_dir, tr_variant const& settings_d stats().save(); }); save_timer_->start_repeating(SaveIntervalSecs); - - verifier_->add_callback(tr_torrentOnVerifyDone); } void tr_session::addIncoming(tr_peer_socket&& socket) diff --git a/libtransmission/session.h b/libtransmission/session.h index 933171805dc..ac213ab5bd4 100644 --- a/libtransmission/session.h +++ b/libtransmission/session.h @@ -888,21 +888,8 @@ struct tr_session return settings_.ratio_limit; } - void verifyRemove(tr_torrent* tor) - { - if (verifier_) - { - verifier_->remove(tor); - } - } - - void verifyAdd(tr_torrent* tor) - { - if (verifier_) - { - verifier_->add(tor); - } - } + void verify_add(tr_torrent* tor); + void verify_remove(tr_torrent const* tor); void fetch(tr_web::FetchOptions&& options) const { diff --git a/libtransmission/torrent-ctor.cc b/libtransmission/torrent-ctor.cc index 5d5f3644ce6..07bf62573f3 100644 --- a/libtransmission/torrent-ctor.cc +++ b/libtransmission/torrent-ctor.cc @@ -60,6 +60,8 @@ struct tr_ctor std::vector contents; + tr_torrent::VerifyDoneCallback verify_done_callback_; + explicit tr_ctor(tr_session const* session_in) : session{ session_in } { @@ -68,6 +70,20 @@ struct tr_ctor // --- +void tr_ctorSetVerifyDoneCallback(tr_ctor* ctor, tr_torrent::VerifyDoneCallback&& callback) +{ + ctor->verify_done_callback_ = std::move(callback); +} + +tr_torrent::VerifyDoneCallback tr_ctorStealVerifyDoneCallback(tr_ctor* ctor) +{ + auto tmp = tr_torrent::VerifyDoneCallback{}; + std::swap(ctor->verify_done_callback_, tmp); + return tmp; +} + +// --- + bool tr_ctorSetMetainfoFromFile(tr_ctor* ctor, std::string_view filename, tr_error** error) { if (std::empty(filename)) diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index c12a27b53b7..c124f0f8d08 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -698,7 +698,7 @@ void removeTorrentInSessionThread(tr_torrent* tor, bool delete_flag, tr_fileFunc { // ensure the files are all closed and idle before moving tor->session->closeTorrentFiles(tor); - tor->session->verifyRemove(tor); + tor->session->verify_remove(tor); if (delete_func == nullptr) { @@ -829,7 +829,7 @@ void torrentStop(tr_torrent* const tor) tr_logAddInfoTor(tor, _("Pausing torrent")); } - tor->session->verifyRemove(tor); + tor->session->verify_remove(tor); tor->stopped_.emit(tor); tor->session->announcer_->stopTorrent(tor); @@ -1172,6 +1172,7 @@ tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of) } auto* const tor = new tr_torrent{ std::move(metainfo) }; + tor->verify_done_callback_ = tr_ctorStealVerifyDoneCallback(ctor); torrentInit(tor, ctor); return tor; } @@ -1202,7 +1203,7 @@ void setLocationInSessionThread( // ensure the files are all closed and idle before moving tor->session->closeTorrentFiles(tor); - tor->session->verifyRemove(tor); + tor->session->verify_remove(tor); tr_error* error = nullptr; ok = tor->metainfo_.files().move(tor->current_dir(), path, setme_progress, tor->name(), &error); @@ -1689,7 +1690,7 @@ void verifyTorrent(tr_torrent* const tor, bool force) } /* if the torrent's already being verified, stop it */ - tor->session->verifyRemove(tor); + tor->session->verify_remove(tor); if (!tor->has_metainfo()) { @@ -1703,38 +1704,99 @@ void verifyTorrent(tr_torrent* const tor, bool force) if (force || !setLocalErrorIfFilesDisappeared(tor)) { - tor->session->verifyAdd(tor); + tor->session->verify_add(tor); } } } // namespace verify_helpers } // namespace -void tr_torrentOnVerifyDone(tr_torrent* tor, bool aborted) +void tr_torrentVerify(tr_torrent* tor, bool force) { using namespace verify_helpers; - if (aborted || tor->is_deleting_) + tor->session->runInSessionThread(verifyTorrent, tor, force); +} + +void tr_torrent::set_verify_state(VerifyState const state) +{ + TR_ASSERT(state == VerifyState::None || state == VerifyState::Queued || state == VerifyState::Active); + + verify_state_ = state; + verify_progress_ = {}; + mark_changed(); +} + +tr_torrent_metainfo const& tr_torrent::VerifyMediator::metainfo() const +{ + return tor_->metainfo_; +} + +std::optional tr_torrent::VerifyMediator::find_file(tr_file_index_t const file_index) const +{ + if (auto const found = tor_->find_file(file_index); found) { - return; + return std::string{ found->filename().sv() }; } - tor->session->runInSessionThread(onVerifyDoneThreadFunc, tor); + return {}; } -void tr_torrentVerify(tr_torrent* tor, bool force) +void tr_torrent::VerifyMediator::on_verify_queued() { - using namespace verify_helpers; + tr_logAddTraceTor(tor_, "Queued for verification"); + tor_->set_verify_state(VerifyState::Queued); +} - tor->session->runInSessionThread(verifyTorrent, tor, force); +void tr_torrent::VerifyMediator::on_verify_started() +{ + tr_logAddDebugTor(tor_, "Verifying torrent"); + time_started_ = tr_time(); + tor_->set_verify_state(VerifyState::Active); } -void tr_torrent::set_verify_state(tr_verify_state state) +void tr_torrent::VerifyMediator::on_piece_checked(tr_piece_index_t const piece, bool const has_piece) { - TR_ASSERT(state == TR_VERIFY_NONE || state == TR_VERIFY_WAIT || state == TR_VERIFY_NOW); + auto const had_piece = tor_->has_piece(piece); - this->verify_state_ = state; - this->verify_progress_ = {}; - this->mark_changed(); + if (has_piece || had_piece) + { + tor_->set_has_piece(piece, has_piece); + tor_->set_dirty(); + } + + tor_->checked_pieces_.set(piece, true); + tor_->mark_changed(); + tor_->verify_progress_ = std::clamp(static_cast(piece + 1U) / tor_->metainfo_.piece_count(), 0.0F, 1.0F); +} + +void tr_torrent::VerifyMediator::on_verify_done(bool const aborted) +{ + using namespace verify_helpers; + + if (time_started_.has_value()) + { + auto const total_size = tor_->total_size(); + auto const duration_secs = tr_time() - *time_started_; + tr_logAddDebugTor( + tor_, + fmt::format( + "Verification is done. It took {} seconds to verify {} bytes ({} bytes per second)", + duration_secs, + total_size, + total_size / (1 + duration_secs))); + } + + tor_->set_verify_state(VerifyState::None); + + if (!aborted && !tor_->is_deleting_) + { + tor_->session->runInSessionThread(onVerifyDoneThreadFunc, tor_); + } + + if (tor_->verify_done_callback_) + { + tor_->verify_done_callback_(tor_); + } } // --- diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index 7c411e2045f..9b580cc85e2 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -11,6 +11,7 @@ #include // size_t #include +#include #include #include #include @@ -28,13 +29,14 @@ #include "libtransmission/crypto-utils.h" #include "libtransmission/file-piece-map.h" #include "libtransmission/interned-string.h" -#include "libtransmission/observable.h" #include "libtransmission/log.h" +#include "libtransmission/observable.h" #include "libtransmission/session.h" #include "libtransmission/torrent-magnet.h" #include "libtransmission/torrent-metainfo.h" #include "libtransmission/tr-assert.h" #include "libtransmission/tr-macros.h" +#include "libtransmission/verify.h" class tr_swarm; struct tr_error; @@ -73,17 +75,35 @@ void tr_torrentCheckSeedLimit(tr_torrent* tor); /** save a torrent's .resume file if it's changed since the last time it was saved */ void tr_torrentSave(tr_torrent* tor); -enum tr_verify_state : uint8_t -{ - TR_VERIFY_NONE, - TR_VERIFY_WAIT, - TR_VERIFY_NOW -}; - /** @brief Torrent object */ struct tr_torrent final : public tr_completion::torrent_view { public: + using VerifyDoneCallback = std::function; + + class VerifyMediator : public tr_verify_worker::Mediator + { + public: + explicit VerifyMediator(tr_torrent* const tor) + : tor_{ tor } + { + } + + ~VerifyMediator() override = default; + + [[nodiscard]] tr_torrent_metainfo const& metainfo() const override; + [[nodiscard]] std::optional find_file(tr_file_index_t file_index) const override; + + void on_verify_queued() override; + void on_verify_started() override; + void on_piece_checked(tr_piece_index_t piece, bool has_piece) override; + void on_verify_done(bool aborted) override; + + private: + tr_torrent* const tor_; + std::optional time_started_; + }; + explicit tr_torrent(tr_torrent_metainfo&& tm) : metainfo_{ std::move(tm) } , completion{ this, &this->metainfo_.block_info() } @@ -581,21 +601,9 @@ struct tr_torrent final : public tr_completion::torrent_view void refresh_current_dir(); - void set_verify_state(tr_verify_state state); - - [[nodiscard]] constexpr auto verify_state() const noexcept - { - return verify_state_; - } - - constexpr void set_verify_progress(float f) noexcept - { - verify_progress_ = f; - } - [[nodiscard]] constexpr std::optional verify_progress() const noexcept { - if (verify_state_ == TR_VERIFY_NOW) + if (verify_state_ == VerifyState::Active) { return verify_progress_; } @@ -622,12 +630,12 @@ struct tr_torrent final : public tr_completion::torrent_view { bool const is_seed = this->is_done(); - if (this->verify_state() == TR_VERIFY_NOW) + if (verify_state_ == VerifyState::Active) { return TR_STATUS_CHECK; } - if (this->verify_state() == TR_VERIFY_WAIT) + if (verify_state_ == VerifyState::Queued) { return TR_STATUS_CHECK_WAIT; } @@ -992,6 +1000,14 @@ struct tr_torrent final : public tr_completion::torrent_view private: friend tr_stat const* tr_torrentStat(tr_torrent* tor); + friend tr_torrent* tr_torrentNew(tr_ctor* ctor, tr_torrent** setme_duplicate_of); + + enum class VerifyState : uint8_t + { + None, + Queued, + Active + }; // Tracks a torrent's error state, either local (e.g. file IO errors) // or tracker errors (e.g. warnings returned by a tracker). @@ -1129,8 +1145,12 @@ struct tr_torrent final : public tr_completion::torrent_view } } + void set_verify_state(VerifyState state); + Error error_; + VerifyDoneCallback verify_done_callback_; + tr_interned_string bandwidth_group_; SimpleSmoothedSpeed eta_speed_; @@ -1153,7 +1173,7 @@ struct tr_torrent final : public tr_completion::torrent_view tr_idlelimit idle_limit_mode_ = TR_IDLELIMIT_GLOBAL; - tr_verify_state verify_state_ = TR_VERIFY_NONE; + VerifyState verify_state_ = VerifyState::None; uint16_t idle_limit_minutes_ = 0; @@ -1183,7 +1203,8 @@ void tr_ctorSetBandwidthPriority(tr_ctor* ctor, tr_priority_t priority); tr_priority_t tr_ctorGetBandwidthPriority(tr_ctor const* ctor); tr_torrent::labels_t const& tr_ctorGetLabels(tr_ctor const* ctor); -void tr_torrentOnVerifyDone(tr_torrent* tor, bool aborted); +void tr_ctorSetVerifyDoneCallback(tr_ctor* ctor, tr_torrent::VerifyDoneCallback&& callback); +tr_torrent::VerifyDoneCallback tr_ctorStealVerifyDoneCallback(tr_ctor* ctor); #define tr_logAddCriticalTor(tor, msg) tr_logAddCritical(msg, (tor)->name()) #define tr_logAddErrorTor(tor, msg) tr_logAddError(msg, (tor)->name()) diff --git a/libtransmission/verify.cc b/libtransmission/verify.cc index 47141c64c21..f68bfc22334 100644 --- a/libtransmission/verify.cc +++ b/libtransmission/verify.cc @@ -4,6 +4,7 @@ // License text can be found in the licenses/ folder. #include +#include #include #include #include @@ -17,79 +18,49 @@ #include "libtransmission/completion.h" #include "libtransmission/crypto-utils.h" #include "libtransmission/file.h" -#include "libtransmission/log.h" -#include "libtransmission/torrent.h" -#include "libtransmission/tr-assert.h" -#include "libtransmission/utils.h" // tr_time() #include "libtransmission/verify.h" using namespace std::chrono_literals; namespace { - auto constexpr SleepPerSecondDuringVerify = 100ms; -} - -int tr_verify_worker::Node::compare(tr_verify_worker::Node const& that) const +[[nodiscard]] auto current_time_secs() { - // higher priority comes before lower priority - auto const pa = tr_torrentGetPriority(torrent); - auto const pb = tr_torrentGetPriority(that.torrent); - if (auto const val = tr_compare_3way(pa, pb); val != 0) - { - return -val; - } - - // smaller torrents come before larger ones because they verify faster - if (auto const val = tr_compare_3way(current_size, that.current_size); val != 0) - { - return val; - } - - // tertiary compare just to ensure they don't compare equal - return tr_compare_3way(torrent->id(), that.torrent->id()); + return std::chrono::time_point_cast(std::chrono::steady_clock::now()); } +} // namespace -bool tr_verify_worker::verify_torrent(tr_torrent* tor, std::atomic const& stop_flag) +void tr_verify_worker::verify_torrent(Mediator& verify_mediator, std::atomic const& abort_flag) { - auto const begin = tr_time(); + verify_mediator.on_verify_started(); tr_sys_file_t fd = TR_BAD_SYS_FILE; - uint64_t file_pos = 0; - bool changed = false; - bool had_piece = false; - time_t last_slept_at = 0; - uint32_t piece_pos = 0; - tr_file_index_t file_index = 0; + uint64_t file_pos = 0U; + uint32_t piece_pos = 0U; + tr_file_index_t file_index = 0U; tr_file_index_t prev_file_index = ~file_index; - tr_piece_index_t piece = 0; - auto buffer = std::vector(1024 * 256); + tr_piece_index_t piece = 0U; + auto buffer = std::vector(1024U * 256U); auto sha = tr_sha1::create(); + auto last_slept_at = current_time_secs(); - tr_logAddDebugTor(tor, "verifying torrent..."); - - while (!stop_flag && piece < tor->piece_count()) + auto const& metainfo = verify_mediator.metainfo(); + while (!abort_flag && piece < metainfo.piece_count()) { - auto const file_length = tor->file_size(file_index); - - /* if we're starting a new piece... */ - if (piece_pos == 0) - { - had_piece = tor->has_piece(piece); - } + auto const file_length = metainfo.file_size(file_index); /* if we're starting a new file... */ if (file_pos == 0 && fd == TR_BAD_SYS_FILE && file_index != prev_file_index) { - auto const found = tor->find_file(file_index); - fd = !found ? TR_BAD_SYS_FILE : tr_sys_file_open(found->filename(), TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0); + auto const found = verify_mediator.find_file(file_index); + fd = !found ? TR_BAD_SYS_FILE : tr_sys_file_open(found->c_str(), TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0); prev_file_index = file_index; } /* figure out how much we can read this pass */ - uint64_t left_in_piece = tor->piece_size(piece) - piece_pos; + uint64_t left_in_piece = metainfo.piece_size(piece) - piece_pos; uint64_t left_in_file = file_length - file_pos; uint64_t bytes_this_pass = std::min(left_in_file, left_in_piece); bytes_this_pass = std::min(bytes_this_pass, uint64_t(std::size(buffer))); @@ -115,18 +86,12 @@ bool tr_verify_worker::verify_torrent(tr_torrent* tor, std::atomic const& /* if we're finishing a piece... */ if (left_in_piece == 0) { - if (auto const has_piece = sha->finish() == tor->piece_hash(piece); has_piece || had_piece) - { - tor->set_has_piece(piece, has_piece); - changed |= has_piece != had_piece; - } - - tor->checked_pieces_.set(piece, true); - tor->mark_changed(); + auto const has_piece = sha->finish() == 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 = tr_time(); last_slept_at != now) + if (auto const now = current_time_secs(); last_slept_at != now) { last_slept_at = now; std::this_thread::sleep_for(SleepPerSecondDuringVerify); @@ -134,7 +99,6 @@ bool tr_verify_worker::verify_torrent(tr_torrent* tor, std::atomic const& sha->clear(); ++piece; - tor->set_verify_progress(piece / float(tor->piece_count())); piece_pos = 0; } @@ -158,17 +122,7 @@ bool tr_verify_worker::verify_torrent(tr_torrent* tor, std::atomic const& tr_sys_file_close(fd); } - /* stopwatch */ - time_t const end = tr_time(); - tr_logAddDebugTor( - tor, - fmt::format( - "Verification is done. It took {} seconds to verify {} bytes ({} bytes per second)", - end - begin, - tor->total_size(), - tor->total_size() / (1 + (end - begin)))); - - return changed; + verify_mediator.on_verify_done(abort_flag); } void tr_verify_worker::verify_thread_func() @@ -176,7 +130,7 @@ void tr_verify_worker::verify_thread_func() for (;;) { { - auto const lock = std::lock_guard(verify_mutex_); + auto const lock = std::lock_guard{ verify_mutex_ }; if (stop_current_) { @@ -191,39 +145,19 @@ void tr_verify_worker::verify_thread_func() return; } - auto const it = std::begin(todo_); - current_node_ = *it; - todo_.erase(it); - } - - auto* const tor = current_node_->torrent; - tr_logAddTraceTor(tor, "Verifying torrent"); - tor->set_verify_state(TR_VERIFY_NOW); - auto const changed = verify_torrent(tor, stop_current_); - tor->set_verify_state(TR_VERIFY_NONE); - TR_ASSERT(tr_isTorrent(tor)); - - if (!stop_current_ && changed) - { - tor->set_dirty(); + current_node_ = std::move(todo_.extract(std::begin(todo_)).value()); } - call_callback(tor, stop_current_); + verify_torrent(*current_node_->mediator_, stop_current_); } } -void tr_verify_worker::add(tr_torrent* tor) +void tr_verify_worker::add(std::unique_ptr mediator, tr_priority_t priority) { - TR_ASSERT(tr_isTorrent(tor)); - tr_logAddTraceTor(tor, "Queued for verification"); - - auto node = Node{}; - node.torrent = tor; - node.current_size = tor->has_total(); + auto const lock = std::lock_guard{ verify_mutex_ }; - auto const lock = std::lock_guard(verify_mutex_); - tor->set_verify_state(TR_VERIFY_WAIT); - todo_.insert(node); + mediator->on_verify_queued(); + todo_.emplace(std::move(mediator), priority); if (!verify_thread_id_) { @@ -233,38 +167,30 @@ void tr_verify_worker::add(tr_torrent* tor) } } -void tr_verify_worker::remove(tr_torrent* tor) +void tr_verify_worker::remove(tr_sha1_digest_t const& info_hash) { - TR_ASSERT(tr_isTorrent(tor)); - auto lock = std::unique_lock(verify_mutex_); - if (current_node_ && current_node_->torrent == tor) + if (current_node_ && current_node_->matches(info_hash)) { stop_current_ = true; stop_current_cv_.wait(lock, [this]() { return !stop_current_; }); } - else + else if (auto const iter = std::find_if( + std::begin(todo_), + std::end(todo_), + [&info_hash](auto const& node) { return node.matches(info_hash); }); + iter != std::end(todo_)) { - auto const iter = std::find_if( - std::begin(todo_), - std::end(todo_), - [tor](auto const& task) { return tor == task.torrent; }); - - tor->set_verify_state(TR_VERIFY_NONE); - - if (iter != std::end(todo_)) - { - call_callback(tor, true); - todo_.erase(iter); - } + iter->mediator_->on_verify_done(true /*aborted*/); + todo_.erase(iter); } } tr_verify_worker::~tr_verify_worker() { { - auto const lock = std::lock_guard(verify_mutex_); + auto const lock = std::lock_guard{ verify_mutex_ }; stop_current_ = true; todo_.clear(); } @@ -274,3 +200,30 @@ tr_verify_worker::~tr_verify_worker() std::this_thread::sleep_for(20ms); } } + +int tr_verify_worker::Node::compare(Node const& that) const noexcept +{ + // prefer higher-priority torrents + if (priority_ != that.priority_) + { + return priority_ > that.priority_ ? -1 : 1; + } + + // prefer smaller torrents, since they will verify faster + auto const& metainfo = mediator_->metainfo(); + auto const& that_metainfo = that.mediator_->metainfo(); + if (metainfo.total_size() != that_metainfo.total_size()) + { + return metainfo.total_size() < that_metainfo.total_size() ? -1 : 1; + } + + // uniqueness check + auto const& this_hash = metainfo.info_hash(); + auto const& that_hash = that_metainfo.info_hash(); + if (this_hash != that_hash) + { + return this_hash < that_hash ? -1 : 1; + } + + return 0; +} diff --git a/libtransmission/verify.h b/libtransmission/verify.h index 1585ff07abb..4ea3d5aea82 100644 --- a/libtransmission/verify.h +++ b/libtransmission/verify.h @@ -14,56 +14,66 @@ #include #include #include +#include #include #include #include #include -struct tr_session; -struct tr_torrent; +#include "libtransmission/torrent-metainfo.h" class tr_verify_worker { public: - using callback_func = std::function; + class Mediator + { + public: + virtual ~Mediator() = default; - ~tr_verify_worker(); + [[nodiscard]] virtual tr_torrent_metainfo const& metainfo() const = 0; + [[nodiscard]] virtual std::optional find_file(tr_file_index_t file_index) const = 0; - void add_callback(callback_func callback) - { - callbacks_.emplace_back(std::move(callback)); - } + virtual void on_verify_queued() = 0; + virtual void on_verify_started() = 0; + virtual void on_piece_checked(tr_piece_index_t piece, bool has_piece) = 0; + virtual void on_verify_done(bool aborted) = 0; + }; - void add(tr_torrent* tor); + ~tr_verify_worker(); + + void add(std::unique_ptr mediator, tr_priority_t priority); - void remove(tr_torrent* tor); + void remove(tr_sha1_digest_t const& info_hash); private: struct Node { - tr_torrent* torrent = nullptr; - uint64_t current_size = 0; + Node(std::unique_ptr mediator, tr_priority_t priority) noexcept + : mediator_{ std::move(mediator) } + , priority_{ priority } + { + } - [[nodiscard]] int compare(Node const& that) const; + [[nodiscard]] int compare(Node const& that) const noexcept; // <=> - [[nodiscard]] bool operator<(Node const& that) const + [[nodiscard]] auto operator<(Node const& that) const noexcept { return compare(that) < 0; } - }; - void call_callback(tr_torrent* tor, bool aborted) const - { - for (auto const& callback : callbacks_) + [[nodiscard]] bool matches(tr_sha1_digest_t const& info_hash) const noexcept { - callback(tor, aborted); + return mediator_->metainfo().info_hash() == info_hash; } - } + + std::unique_ptr mediator_; + tr_priority_t priority_; + }; + + static void verify_torrent(Mediator& verify_mediator, std::atomic const& abort_flag); void verify_thread_func(); - [[nodiscard]] static bool verify_torrent(tr_torrent* tor, std::atomic const& stop_flag); - std::list callbacks_; std::mutex verify_mutex_; std::set todo_; diff --git a/tests/libtransmission/test-fixtures.h b/tests/libtransmission/test-fixtures.h index 2bbad2d3ed8..ebb937d0311 100644 --- a/tests/libtransmission/test-fixtures.h +++ b/tests/libtransmission/test-fixtures.h @@ -396,8 +396,17 @@ class SessionTest : public SandboxedTest { auto verified_lock = std::unique_lock(verified_mutex_); auto const n_previously_verified = std::size(verified_); - auto* const tor = tr_torrentNew(ctor, nullptr); + tr_ctorSetVerifyDoneCallback( + ctor, + [this](tr_torrent* const tor) + { + auto verified_lock = std::lock_guard{ verified_mutex_ }; + verified_.emplace_back(tor); + verified_cv_.notify_one(); + }); + + auto* const tor = tr_torrentNew(ctor, nullptr); auto const stop_waiting = [this, tor, n_previously_verified]() { return std::size(verified_) > n_previously_verified && verified_.back() == tor; @@ -514,15 +523,7 @@ class SessionTest : public SandboxedTest init_mgr_ = tr_lib_init(); - auto callback = [this](tr_torrent* tor, bool /*aborted*/) - { - auto verified_lock = std::scoped_lock(verified_mutex_); - verified_.emplace_back(tor); - verified_cv_.notify_one(); - }; - session_ = sessionInit(*settings()); - session_->verifier_->add_callback(callback); } virtual void TearDown() override