From 68f3c89e3c84c862f83fc91c08fbb3a26e05e4e0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 3 Oct 2023 20:18:55 -0500 Subject: [PATCH] refactor: make tr_torrent idle fields private (#6070) --- libtransmission/resume.cc | 12 +- libtransmission/rpcimpl.cc | 12 +- libtransmission/torrent.cc | 214 ++++++++++----------------------- libtransmission/torrent.h | 151 +++++++++++++++++++---- libtransmission/transmission.h | 2 - 5 files changed, 203 insertions(+), 188 deletions(-) diff --git a/libtransmission/resume.cc b/libtransmission/resume.cc index 6e55ae510..65acc13dc 100644 --- a/libtransmission/resume.cc +++ b/libtransmission/resume.cc @@ -246,8 +246,8 @@ void saveSpeedLimits(tr_variant* dict, tr_torrent const* tor) void saveRatioLimits(tr_variant* dict, tr_torrent const* tor) { tr_variant* d = tr_variantDictAddDict(dict, TR_KEY_ratio_limit, 2); - tr_variantDictAddReal(d, TR_KEY_ratio_limit, tr_torrentGetRatioLimit(tor)); - tr_variantDictAddInt(d, TR_KEY_ratio_mode, tr_torrentGetRatioMode(tor)); + tr_variantDictAddReal(d, TR_KEY_ratio_limit, tor->seed_ratio()); + tr_variantDictAddInt(d, TR_KEY_ratio_mode, tor->seed_ratio_mode()); } void saveIdleLimits(tr_variant* dict, tr_torrent const* tor) @@ -306,12 +306,12 @@ auto loadRatioLimits(tr_variant* dict, tr_torrent* tor) { if (auto dratio = double{}; tr_variantDictFindReal(d, TR_KEY_ratio_limit, &dratio)) { - tr_torrentSetRatioLimit(tor, dratio); + tor->set_seed_ratio(dratio); } if (auto i = int64_t{}; tr_variantDictFindInt(d, TR_KEY_ratio_mode, &i)) { - tor->set_ratio_mode(tr_ratiolimit(i)); + tor->set_seed_ratio_mode(static_cast(i)); } ret = tr_resume::Ratiolimit; @@ -328,12 +328,12 @@ auto loadIdleLimits(tr_variant* dict, tr_torrent* tor) { if (auto imin = int64_t{}; tr_variantDictFindInt(d, TR_KEY_idle_limit, &imin)) { - tor->set_idle_limit(imin); + tor->set_idle_limit_minutes(imin); } if (auto i = int64_t{}; tr_variantDictFindInt(d, TR_KEY_idle_mode, &i)) { - tr_torrentSetIdleMode(tor, tr_idlelimit(i)); + tor->set_idle_limit_mode(static_cast(i)); } ret = tr_resume::Idlelimit; diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index b4bbcacdb..e40886cbf 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -669,8 +669,8 @@ namespace make_torrent_field_helpers case TR_KEY_secondsSeeding: return st.secondsSeeding; case TR_KEY_seedIdleLimit: return tor.idle_limit_minutes(); case TR_KEY_seedIdleMode: return tor.idle_limit_mode(); - case TR_KEY_seedRatioLimit: return tr_torrentGetRatioLimit(&tor); - case TR_KEY_seedRatioMode: return tr_torrentGetRatioMode(&tor); + case TR_KEY_seedRatioLimit: return tor.seed_ratio(); + case TR_KEY_seedRatioMode: return tor.seed_ratio_mode(); case TR_KEY_sequentialDownload: return tor.is_sequential_download(); case TR_KEY_sizeWhenDone: return st.sizeWhenDone; case TR_KEY_source: return tor.source(); @@ -1075,22 +1075,22 @@ char const* torrentSet(tr_session* session, tr_variant* args_in, tr_variant* /*a if (tr_variantDictFindInt(args_in, TR_KEY_seedIdleLimit, &tmp)) { - tor->set_idle_limit(static_cast(tmp)); + tor->set_idle_limit_minutes(static_cast(tmp)); } if (tr_variantDictFindInt(args_in, TR_KEY_seedIdleMode, &tmp)) { - tr_torrentSetIdleMode(tor, (tr_idlelimit)tmp); + tor->set_idle_limit_mode(static_cast(tmp)); } if (tr_variantDictFindReal(args_in, TR_KEY_seedRatioLimit, &d)) { - tr_torrentSetRatioLimit(tor, d); + tor->set_seed_ratio(d); } if (tr_variantDictFindInt(args_in, TR_KEY_seedRatioMode, &tmp)) { - tor->set_ratio_mode(static_cast(tmp)); + tor->set_seed_ratio_mode(static_cast(tmp)); } if (tr_variantDictFindInt(args_in, TR_KEY_queuePosition, &tmp)) diff --git a/libtransmission/torrent.cc b/libtransmission/torrent.cc index be1c8b640..427f10215 100644 --- a/libtransmission/torrent.cc +++ b/libtransmission/torrent.cc @@ -174,11 +174,11 @@ bool tr_torrentGetSeedRatioBytes(tr_torrent const* tor, uint64_t* setme_left, ui TR_ASSERT(tr_isTorrent(tor)); - if (auto seed_ratio = double{}; tr_torrentGetSeedRatio(tor, &seed_ratio)) + if (auto const seed_ratio = tor->effective_seed_ratio(); seed_ratio) { auto const uploaded = tor->uploadedCur + tor->uploadedPrev; auto const baseline = tor->size_when_done(); - auto const goal = baseline * seed_ratio; + auto const goal = baseline * *seed_ratio; if (setme_left != nullptr) { @@ -252,146 +252,78 @@ bool tr_torrentUsesSessionLimits(tr_torrent const* tor) // --- Download Ratio -void tr_torrentSetRatioMode(tr_torrent* tor, tr_ratiolimit mode) +void tr_torrentSetRatioMode(tr_torrent* const tor, tr_ratiolimit mode) { TR_ASSERT(tr_isTorrent(tor)); - TR_ASSERT(mode == TR_RATIOLIMIT_GLOBAL || mode == TR_RATIOLIMIT_SINGLE || mode == TR_RATIOLIMIT_UNLIMITED); - tor->set_ratio_mode(mode); + tor->set_seed_ratio_mode(mode); } -tr_ratiolimit tr_torrentGetRatioMode(tr_torrent const* tor) +tr_ratiolimit tr_torrentGetRatioMode(tr_torrent const* const tor) { TR_ASSERT(tr_isTorrent(tor)); - return tor->ratioLimitMode; + return tor->seed_ratio_mode(); } -void tr_torrentSetRatioLimit(tr_torrent* tor, double desired_ratio) +void tr_torrentSetRatioLimit(tr_torrent* const tor, double desired_ratio) { TR_ASSERT(tr_isTorrent(tor)); - if ((int)(desired_ratio * 100.0) != (int)(tor->desiredRatio * 100.0)) + tor->set_seed_ratio(desired_ratio); +} + +double tr_torrentGetRatioLimit(tr_torrent const* const tor) +{ + TR_ASSERT(tr_isTorrent(tor)); + + return tor->seed_ratio(); +} + +bool tr_torrentGetSeedRatio(tr_torrent const* const tor, double* ratio) +{ + TR_ASSERT(tr_isTorrent(tor)); + + auto const val = tor->effective_seed_ratio(); + + if (ratio != nullptr && val) { - tor->desiredRatio = desired_ratio; - - tor->set_dirty(); - } -} - -double tr_torrentGetRatioLimit(tr_torrent const* tor) -{ - TR_ASSERT(tr_isTorrent(tor)); - - return tor->desiredRatio; -} - -bool tr_torrentGetSeedRatio(tr_torrent const* tor, double* ratio) -{ - auto is_limited = bool{}; - - TR_ASSERT(tr_isTorrent(tor)); - - switch (tr_torrentGetRatioMode(tor)) - { - case TR_RATIOLIMIT_SINGLE: - is_limited = true; - - if (ratio != nullptr) - { - *ratio = tr_torrentGetRatioLimit(tor); - } - - break; - - case TR_RATIOLIMIT_GLOBAL: - is_limited = tor->session->isRatioLimited(); - - if (is_limited && ratio != nullptr) - { - *ratio = tor->session->desiredRatio(); - } - - break; - - default: /* TR_RATIOLIMIT_UNLIMITED */ - is_limited = false; - break; + *ratio = *val; } - return is_limited; + return val.has_value(); } // --- -void tr_torrentSetIdleMode(tr_torrent* tor, tr_idlelimit mode) +void tr_torrentSetIdleMode(tr_torrent* const tor, tr_idlelimit mode) { TR_ASSERT(tr_isTorrent(tor)); - TR_ASSERT(mode == TR_IDLELIMIT_GLOBAL || mode == TR_IDLELIMIT_SINGLE || mode == TR_IDLELIMIT_UNLIMITED); - if (tor->idle_limit_mode_ != mode) - { - tor->idle_limit_mode_ = mode; - - tor->set_dirty(); - } + tor->set_idle_limit_mode(mode); } -tr_idlelimit tr_torrentGetIdleMode(tr_torrent const* tor) +tr_idlelimit tr_torrentGetIdleMode(tr_torrent const* const tor) { TR_ASSERT(tr_isTorrent(tor)); return tor->idle_limit_mode(); } -void tr_torrentSetIdleLimit(tr_torrent* tor, uint16_t idle_minutes) +void tr_torrentSetIdleLimit(tr_torrent* const tor, uint16_t idle_minutes) { TR_ASSERT(tr_isTorrent(tor)); - tor->set_idle_limit(idle_minutes); + tor->set_idle_limit_minutes(idle_minutes); } -uint16_t tr_torrentGetIdleLimit(tr_torrent const* tor) +uint16_t tr_torrentGetIdleLimit(tr_torrent const* const tor) { TR_ASSERT(tr_isTorrent(tor)); return tor->idle_limit_minutes(); } -bool tr_torrentGetSeedIdle(tr_torrent const* tor, uint16_t* idle_minutes) -{ - auto is_limited = bool{}; - - switch (tor->idle_limit_mode()) - { - case TR_IDLELIMIT_SINGLE: - is_limited = true; - - if (idle_minutes != nullptr) - { - *idle_minutes = tor->idle_limit_minutes(); - } - - break; - - case TR_IDLELIMIT_GLOBAL: - is_limited = tor->session->isIdleLimited(); - - if (is_limited && idle_minutes != nullptr) - { - *idle_minutes = tor->session->idleLimitMinutes(); - } - - break; - - default: /* TR_IDLELIMIT_UNLIMITED */ - is_limited = false; - break; - } - - return is_limited; -} - namespace { namespace script_helpers @@ -498,11 +430,10 @@ namespace { namespace seed_limit_helpers { -bool tr_torrentIsSeedIdleLimitDone(tr_torrent const* tor) +bool torrent_is_seed_idle_limit_done(tr_torrent const& tor, time_t now) { - auto idle_minutes = uint16_t{}; - return tr_torrentGetSeedIdle(tor, &idle_minutes) && - difftime(tr_time(), std::max(tor->startDate, tor->activityDate)) >= idle_minutes * 60U; + auto const secs_left = tor.idle_seconds_left(now); + return secs_left && *secs_left == 0U; } } // namespace seed_limit_helpers } // namespace @@ -526,7 +457,7 @@ void tr_torrentCheckSeedLimit(tr_torrent* tor) tor->session->onRatioLimitHit(tor); } /* if we're seeding and reach our inactivity limit, stop the torrent */ - else if (tr_torrentIsSeedIdleLimitDone(tor)) + else if (torrent_is_seed_idle_limit_done(*tor, tr_time())) { tr_logAddInfoTor(tor, _("Seeding idle limit reached; pausing torrent")); @@ -845,7 +776,7 @@ void torrentStart(tr_torrent* tor, torrent_start_opts opts) if (tr_torrentIsSeedRatioDone(tor)) { tr_logAddInfoTor(tor, _("Restarted manually -- disabling its seed ratio")); - tor->set_ratio_mode(TR_RATIOLIMIT_UNLIMITED); + tor->set_seed_ratio_mode(TR_RATIOLIMIT_UNLIMITED); } tor->is_running_ = true; @@ -1093,14 +1024,14 @@ void torrentInit(tr_torrent* tor, tr_ctor const* ctor) if ((loaded & tr_resume::Ratiolimit) == 0) { - tor->set_ratio_mode(TR_RATIOLIMIT_GLOBAL); - tr_torrentSetRatioLimit(tor, tor->session->desiredRatio()); + tor->set_seed_ratio_mode(TR_RATIOLIMIT_GLOBAL); + tor->set_seed_ratio(tor->session->desiredRatio()); } if ((loaded & tr_resume::Idlelimit) == 0) { - tr_torrentSetIdleMode(tor, TR_IDLELIMIT_GLOBAL); - tor->set_idle_limit(tor->session->idleLimitMinutes()); + tor->set_idle_limit_mode(TR_IDLELIMIT_GLOBAL); + tor->set_idle_limit_minutes(tor->session->idleLimitMinutes()); } auto has_local_data = std::optional{}; @@ -1442,10 +1373,11 @@ tr_stat const* tr_torrentStat(tr_torrent* tor) auto const now_sec = tr_time(); auto const swarm_stats = tor->swarm != nullptr ? tr_swarmGetStats(tor->swarm) : tr_swarm_stats{}; + auto const activity = tor->activity(); tr_stat* const s = &tor->stats; s->id = tor->id(); - s->activity = tor->activity(); + s->activity = activity; s->error = tor->error; s->queuePosition = tor->queuePosition; s->idleSecs = torrentGetIdleSecs(tor, s->activity); @@ -1497,13 +1429,14 @@ tr_stat const* tr_torrentStat(tr_torrent* tor) auto seed_ratio_bytes_goal = uint64_t{}; bool const seed_ratio_applies = tr_torrentGetSeedRatioBytes(tor, &seed_ratio_bytes_left, &seed_ratio_bytes_goal); - switch (s->activity) + s->eta = TR_ETA_NOT_AVAIL; + s->etaIdle = TR_ETA_NOT_AVAIL; + if (activity == TR_STATUS_DOWNLOAD) { - /* etaSpeed exists because if we use the piece speed directly, - * brief fluctuations cause the ETA to jump all over the place. - * so, etaXLSpeed is a smoothed-out version of the piece speed - * to dampen the effect of fluctuations */ - case TR_STATUS_DOWNLOAD: + /* etaSpeed exists because if we use the piece speed directly, + * brief fluctuations cause the ETA to jump all over the place. + * so, etaXLSpeed is a smoothed-out version of the piece speed + * to dampen the effect of fluctuations */ if (tor->etaSpeedCalculatedAt + 800 < now) { tor->etaSpeed_Bps = tor->etaSpeedCalculatedAt + 4000 < now ? @@ -1512,28 +1445,18 @@ tr_stat const* tr_torrentStat(tr_torrent* tor) tor->etaSpeedCalculatedAt = now; } - if (s->leftUntilDone > s->desiredAvailable && tor->webseed_count() < 1) - { - s->eta = TR_ETA_NOT_AVAIL; - } - else if (tor->etaSpeed_Bps == 0) + if (tor->etaSpeed_Bps == 0) { s->eta = TR_ETA_UNKNOWN; } - else + else if (s->leftUntilDone <= s->desiredAvailable || tor->webseed_count() >= 1U) { s->eta = s->leftUntilDone / tor->etaSpeed_Bps; } - - s->etaIdle = TR_ETA_NOT_AVAIL; - break; - - case TR_STATUS_SEED: - if (!seed_ratio_applies) - { - s->eta = TR_ETA_NOT_AVAIL; - } - else + } + else if (activity == TR_STATUS_SEED) + { + if (seed_ratio_applies) { if (tor->etaSpeedCalculatedAt + 800 < now) { @@ -1543,29 +1466,16 @@ tr_stat const* tr_torrentStat(tr_torrent* tor) tor->etaSpeedCalculatedAt = now; } - if (tor->etaSpeed_Bps == 0) - { - s->eta = TR_ETA_UNKNOWN; - } - else - { - s->eta = seed_ratio_bytes_left / tor->etaSpeed_Bps; - } + s->eta = tor->etaSpeed_Bps == 0U ? TR_ETA_UNKNOWN : seed_ratio_bytes_left / tor->etaSpeed_Bps; } + if (tor->etaSpeed_Bps < 1U) { - auto seed_idle_minutes = uint16_t{}; - s->etaIdle = tor->etaSpeed_Bps < 1 && tr_torrentGetSeedIdle(tor, &seed_idle_minutes) ? - seed_idle_minutes * 60 - s->idleSecs : - TR_ETA_NOT_AVAIL; + if (auto const secs_left = tor->idle_seconds_left(now); secs_left) + { + s->etaIdle = *secs_left; + } } - - break; - - default: - s->eta = TR_ETA_NOT_AVAIL; - s->etaIdle = TR_ETA_NOT_AVAIL; - break; } /* s->haveValid is here to make sure a torrent isn't marked 'finished' diff --git a/libtransmission/torrent.h b/libtransmission/torrent.h index ca9788ca8..1126145cd 100644 --- a/libtransmission/torrent.h +++ b/libtransmission/torrent.h @@ -32,6 +32,7 @@ #include "libtransmission/session.h" #include "libtransmission/torrent-magnet.h" #include "libtransmission/torrent-metainfo.h" +#include "libtransmission/tr-assert.h" #include "libtransmission/tr-macros.h" class tr_swarm; @@ -711,31 +712,30 @@ public: return bandwidth_group_; } - [[nodiscard]] constexpr auto idle_limit_mode() const noexcept - { - return idle_limit_mode_; - } - - [[nodiscard]] constexpr auto idle_limit_minutes() const noexcept - { - return idle_limit_minutes_; - } - [[nodiscard]] constexpr auto peer_limit() const noexcept { return max_connected_peers_; } - constexpr void set_ratio_mode(tr_ratiolimit mode) noexcept + // --- idleness + + void set_idle_limit_mode(tr_idlelimit mode) noexcept { - if (ratioLimitMode != mode) + auto const is_valid = mode == TR_IDLELIMIT_GLOBAL || mode == TR_IDLELIMIT_SINGLE || mode == TR_IDLELIMIT_UNLIMITED; + TR_ASSERT(is_valid); + if (idle_limit_mode_ != mode && is_valid) { - ratioLimitMode = mode; + idle_limit_mode_ = mode; set_dirty(); } } - constexpr void set_idle_limit(uint16_t idle_minutes) noexcept + [[nodiscard]] constexpr auto idle_limit_mode() const noexcept + { + return idle_limit_mode_; + } + + constexpr void set_idle_limit_minutes(uint16_t idle_minutes) noexcept { if ((idle_limit_minutes_ != idle_minutes) && (idle_minutes > 0)) { @@ -744,6 +744,80 @@ public: } } + [[nodiscard]] constexpr auto idle_limit_minutes() const noexcept + { + return idle_limit_minutes_; + } + + [[nodiscard]] constexpr std::optional idle_seconds_left(time_t now) const noexcept + { + auto const idle_limit_minutes = effective_idle_limit_minutes(); + if (!idle_limit_minutes) + { + return {}; + } + + auto const idle_seconds = this->idle_seconds(now); + if (!idle_seconds) + { + return {}; + } + + auto const idle_limit_seconds = size_t{ *idle_limit_minutes } * 60U; + return idle_limit_seconds > *idle_seconds ? idle_limit_seconds - *idle_seconds : 0U; + } + + // --- seed ratio + + constexpr void set_seed_ratio_mode(tr_ratiolimit mode) noexcept + { + auto const is_valid = mode == TR_RATIOLIMIT_GLOBAL || mode == TR_RATIOLIMIT_SINGLE || mode == TR_RATIOLIMIT_UNLIMITED; + TR_ASSERT(is_valid); + if (seed_ratio_mode_ != mode && is_valid) + { + seed_ratio_mode_ = mode; + set_dirty(); + } + } + + [[nodiscard]] constexpr auto seed_ratio_mode() const noexcept + { + return seed_ratio_mode_; + } + + constexpr void set_seed_ratio(double desired_ratio) + { + if (static_cast(seed_ratio_ * 100.0) != static_cast(desired_ratio * 100.0)) + { + seed_ratio_ = desired_ratio; + set_dirty(); + } + } + + [[nodiscard]] auto seed_ratio() const noexcept + { + return seed_ratio_; + } + + [[nodiscard]] constexpr std::optional effective_seed_ratio() const noexcept + { + auto const mode = seed_ratio_mode(); + + if (mode == TR_RATIOLIMIT_SINGLE) + { + return seed_ratio_; + } + + if (mode == TR_RATIOLIMIT_GLOBAL) + { + return session->desiredRatio(); + } + + return {}; + } + + // --- + [[nodiscard]] constexpr auto seconds_downloading(time_t now) const noexcept { auto n_secs = seconds_downloading_before_current_start_; @@ -910,15 +984,8 @@ public: tr_completeness completeness = TR_LEECH; - float desiredRatio = 0.0F; - tr_ratiolimit ratioLimitMode = TR_RATIOLIMIT_GLOBAL; - - tr_idlelimit idle_limit_mode_ = TR_IDLELIMIT_GLOBAL; - uint16_t max_connected_peers_ = TR_DEFAULT_PEER_LIMIT_TORRENT; - uint16_t idle_limit_minutes_ = 0; - bool finished_seeding_by_idle_ = false; bool is_deleting_ = false; @@ -932,6 +999,39 @@ public: bool start_when_stable = false; private: + [[nodiscard]] constexpr std::optional effective_idle_limit_minutes() const noexcept + { + auto const mode = idle_limit_mode(); + + if (mode == TR_IDLELIMIT_SINGLE) + { + return idle_limit_minutes(); + } + + if (mode == TR_IDLELIMIT_GLOBAL && session->isIdleLimited()) + { + return session->idleLimitMinutes(); + } + + return {}; + } + + [[nodiscard]] constexpr std::optional idle_seconds(time_t now) const noexcept + { + auto const activity = this->activity(); + + if (activity == TR_STATUS_DOWNLOAD || activity == TR_STATUS_SEED) + { + if (auto const latest = std::max(startDate, activityDate); latest != 0) + { + TR_ASSERT(now >= latest); + return now - latest; + } + } + + return {}; + } + [[nodiscard]] constexpr bool is_piece_transfer_allowed(tr_direction direction) const noexcept { if (uses_speed_limit(direction) && speed_limit_bps(direction) <= 0) @@ -975,12 +1075,19 @@ private: tr_verify_state verify_state_ = TR_VERIFY_NONE; - float verify_progress_ = -1; + float verify_progress_ = -1.0F; + float seed_ratio_ = 0.0F; + + uint16_t idle_limit_minutes_ = 0; tr_announce_key_t announce_key_ = tr_rand_obj(); tr_interned_string bandwidth_group_; + tr_ratiolimit seed_ratio_mode_ = TR_RATIOLIMIT_GLOBAL; + + tr_idlelimit idle_limit_mode_ = TR_IDLELIMIT_GLOBAL; + bool needs_completeness_check_ = true; bool sequential_download_ = false; diff --git a/libtransmission/transmission.h b/libtransmission/transmission.h index 474e2e9da..25896bf32 100644 --- a/libtransmission/transmission.h +++ b/libtransmission/transmission.h @@ -1022,8 +1022,6 @@ void tr_torrentSetIdleMode(tr_torrent* tor, tr_idlelimit mode); uint16_t tr_torrentGetIdleLimit(tr_torrent const* tor); void tr_torrentSetIdleLimit(tr_torrent* tor, uint16_t idle_minutes); -bool tr_torrentGetSeedIdle(tr_torrent const* tor, uint16_t* minutes); - // --- Peer Limits uint16_t tr_torrentGetPeerLimit(tr_torrent const* tor);