Skip to content

v4.2.10#78

Merged
Power2All merged 4 commits into
masterfrom
v4.2.10
May 8, 2026
Merged

v4.2.10#78
Power2All merged 4 commits into
masterfrom
v4.2.10

Conversation

@Power2All

@Power2All Power2All commented May 8, 2026

Copy link
Copy Markdown
Owner

v4.2.10

  • Various audit findings and performance fixes

Summary by CodeRabbit

  • Bug Fixes

    • Improved server startup error handling with consistent logging and graceful shutdown on bind failures
    • Enhanced database initialization error reporting and exit behavior
  • Performance

    • More efficient scrape responses using precomputed torrent counts and inclusion of IPv6 peer/seed counts
    • Refined torrent update aggregation and synchronization for reduced overhead
  • Documentation

    • ChangeLog updated for v4.2.10
  • Chores

    • Version bumped to 4.2.10 (packaging and image tags updated)
  • Tests

    • Minor test formatting cleanups

@Power2All Power2All self-assigned this May 8, 2026
@Power2All Power2All added bug Something isn't working enhancement New feature or request labels May 8, 2026
@coderabbitai

coderabbitai Bot commented May 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Release v4.2.10: introduce TorrentCounts and aggregated scrape handling, add shared hex utilities, centralize env parsing, replace unwraps/panics in startup and DB init with logged exit(1), and bump packaging/version metadata.

Changes

Core Functionality and Refactoring

Layer / File(s) Summary
TorrentCounts Data Structure
src/tracker/structs/torrent_counts.rs, src/tracker/structs.rs, src/tracker/structs/scrape_query_request.rs
New TorrentCounts struct holds IPv4/IPv6 seeds and peers plus completed. from_entry() derives counts; ScrapeQueryRequest derives Deserialize, Clone, Debug.
Hex Encoding Utilities
src/common/common.rs
Added Hex20 wrapper and bin20_to_hex() converter; renamed hex_char_to_nibblehex_to_nibble; removed obsolete debug helpers.
Hex Serialization Integration
src/tracker/impls/info_hash.rs, src/tracker/impls/peer_id.rs, src/tracker/impls/user_id.rs
InfoHash, PeerId, and UserId serialization now use bin20_to_hex() and hex_to_nibble helpers instead of manual buffer logic.
Configuration Env Var Parsing
src/config/impls/configuration.rs
Centralized parse_env_bool, parse_env_optional_bool, parse_env_num replace ad-hoc parsing across env_overrides and server/database/cache blocks.
Server Initialization Error Handling
src/api/api.rs, src/http/http.rs, src/websocket/websocket.rs, src/common/common.rs, src/main.rs
API/HTTP/WSS bind and key-extraction failures now log errors and call exit(1) instead of panicking; host/port check helpers now take &str and return std::io::Result<()>; main propagates errors with ?.
Database Connection/Table Errors
src/database/impls/database_connector_*.rs
MySQL, PostgreSQL, and SQLite connection and CREATE TABLE failures now log prefixed errors and call exit(1) instead of panicking or relying on structured error extraction.
Scrape Response Implementation
src/tracker/impls/torrent_tracker_handlers.rs, src/tracker/impls/torrent_tracker_torrents.rs, src/http/http.rs, src/udp/impls/udp_server.rs, src/websocket/websocket.rs
handle_scrape now returns BTreeMap<InfoHash, TorrentCounts>; added get_torrent_counts(); HTTP/UDP/WSS handlers use aggregated total_seeds(), total_peers(), and completed.
Torrent Update Management
src/tracker/impls/torrent_tracker_torrents_updates.rs
Replaced SystemTime nanos with monotonic UPDATE_SEQ for dedupe keys; save_torrent_updates drains updates, aggregates newest per InfoHash, decrements stats, and restores drained entries on sync failure only where timestamp slots are vacant.
Startup Wiring and Cleanup
src/main.rs, src/udp/impls/parse_pool.rs, src/stats/impls/torrent_tracker.rs, src/structs.rs, tests/udp_tests.rs
Pass bind addresses by reference and propagate errors; removed unnecessary mem::forget; small whitespace/formatting and clap requires adjustments; minor test formatting fixes.

Version Bump to 4.2.10

Layer / File(s) Summary
Package Metadata
Cargo.toml, docker/Dockerfile, docker/build.bat, torrust-actix.desktop
Bumped version from 4.2.94.2.10 across package metadata, Docker checkout/build tags, and desktop entry.
Changelog
README.md
Added v4.2.10 entry noting audit findings and performance fixes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Poem

🐰 A rabbit hops to v4.2.10:
Counts condensed, hex helpers bright,
Startup checks now log at night.
Panics trimmed, configs refined,
A tidy release — hop, joy, and bind!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'v4.2.10' is a version number bump and does not meaningfully describe the actual changes in the PR, which include bug fixes, performance improvements, error handling refactoring, and API changes. Replace with a descriptive title summarizing the main changes, e.g., 'Improve error handling and refactor configuration parsing' or 'Apply audit findings and performance optimizations'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v4.2.10

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Cargo.toml (1)

104-104: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Critical: Bundle version was not updated.

The package.metadata.bundle.version at line 104 still shows "4.2.9" and does not have a change marker, indicating it was not updated in this PR. This creates a version mismatch with the main package.version = "4.2.10" at line 8.

Both versions should be kept in sync for consistency.

🔧 Proposed fix
-version = "4.2.9"
+version = "4.2.10"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Cargo.toml` at line 104, The package.metadata.bundle.version ("4.2.9") in
Cargo.toml is out of sync with package.version ("4.2.10"); update the
package.metadata.bundle.version value to match the main package.version so both
read "4.2.10", ensuring the bundle version and package.version stay consistent
(look for the keys package.version and package.metadata.bundle.version in
Cargo.toml and change the bundle.version entry to the new version).
src/database/impls/database_connector_sqlite.rs (1)

71-75: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid logging full DB DSN/path in connection errors

config.database.path can contain credentials; logging it leaks secrets. Log redacted endpoint/context instead.

Suggested fix
-            error!(
-                "{} Unable to connect to SQLite on DSL {}",
-                LOG_PREFIX,
-                config.database.clone().path
-            );
+            error!("{LOG_PREFIX} Unable to connect to SQLite");
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/database/impls/database_connector_sqlite.rs` around lines 71 - 75, The
error message in the SQLite connector logs the full DSN/path
(config.database.path) which may contain secrets; change the error! call that
currently references LOG_PREFIX and config.database.clone().path to log a
redacted endpoint instead—implement or call a small redaction helper (e.g.,
redact_db_path or mask_credentials) and pass
redact_db_path(&config.database.path) or simply log a non-secret context string
like "sqlite://<REDACTED_PATH>" along with LOG_PREFIX and any safe fields
(database type or host if applicable) in the DatabaseConnectorSqlite connection
error path so credentials are not emitted.
🧹 Nitpick comments (4)
README.md (1)

569-570: ⚡ Quick win

Improve changelog specificity.

The changelog entry "Various audit findings and performance fixes" is too vague for users to understand what changed in this release. Given that the AI summary mentions specific improvements (scrape response refactoring, hex encoding utilities, environment variable parsing, error handling), consider adding more detail.

For example:

#### v4.2.10
* Refactored scrape responses to use aggregated TorrentCounts
* Extracted hex encoding utilities into reusable helpers
* Centralized environment variable parsing
* Improved error handling across server initialization and database operations
* Various performance optimizations

This helps users and maintainers understand the scope of changes and aids in debugging if issues arise.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 569 - 570, Update the v4.2.10 changelog entry (the
"#### v4.2.10" section) to replace the vague line "Various audit findings and
performance fixes" with specific bullet points describing the notable changes:
mention the refactor of scrape responses to use aggregated TorrentCounts,
extraction of hex encoding utilities into reusable helpers, centralization of
environment variable parsing, improvements to error handling across server
initialization and database operations, and a general note about performance
optimizations.
src/tracker/impls/torrent_tracker_torrents_updates.rs (1)

111-116: ⚡ Quick win

Avoid cloning the full batch on the persistence hot path.

torrents_to_save.clone() duplicates every TorrentEntry right before save_torrents, which can eat a lot of CPU and memory on large batches and undercuts the gain from draining instead of cloning the queue. Precompute the small cache/delete payloads you need later, then move torrents_to_save into save_torrents (or change save_torrents to borrow).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tracker/impls/torrent_tracker_torrents_updates.rs` around lines 111 -
116, The code clones the entire BTreeMap into save_torrents by calling
torrents_to_save.clone(), which is expensive; instead, avoid duplicating
TorrentEntry by either (A) constructing only the minimal payloads needed for
persistence (e.g., separate small cache/delete lists) from mapping and pass
those to save_torrents, or (B) change the signature of save_torrents to accept
torrents_to_save by value (moving it) or by reference/borrow
(&BTreeMap<InfoHash,(TorrentEntry,UpdatesAction)>) so you can move
torrents_to_save into the call without cloning; locate the creation of
torrents_to_save (mapping.iter().map(...).collect()) and the save_torrents call
and replace the clone with a move or pass a smaller precomputed payload as
appropriate, keeping symbols mapping, torrents_to_save, save_torrents,
TorrentEntry, UpdatesAction, is_persistent and torrent_tracker in mind.
src/websocket/websocket.rs (1)

587-591: ⚡ Quick win

Inconsistent bind error handling compared to HTTP/API servers.

The websocket_master_service still uses .unwrap() on bind operations (lines 588, 605), while the HTTP and API server handlers were updated to use .unwrap_or_else() with proper error logging before exit(1).

For consistency with the audit fixes applied elsewhere, consider applying the same pattern here.

♻️ Proposed fix for consistent error handling
         .bind_rustls_0_23((addr.ip(), addr.port()), tls_config)
-        .unwrap()
+        .unwrap_or_else(|e| {
+            error!("[WEBSOCKET MASTER] Unable to bind to {addr}: {e}");
+            exit(1);
+        })
         .disable_signals()

And for the non-SSL path:

     .bind((addr.ip(), addr.port()))
-    .unwrap()
+    .unwrap_or_else(|e| {
+        error!("[WEBSOCKET MASTER] Unable to bind to {addr}: {e}");
+        exit(1);
+    })
     .disable_signals()

Also applies to: 604-608

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/websocket/websocket.rs` around lines 587 - 591, The
websocket_master_service currently calls .bind_rustls_0_23(...).unwrap() (and
the non-SSL .bind(...) path) which is inconsistent with the HTTP/API servers;
change those unwrap() calls to use .unwrap_or_else(|e| { error!("Failed to bind
websocket server on {}:{}: {}", addr.ip(), addr.port(), e);
std::process::exit(1) }) (or the existing project logger/exit pattern) so
binding failures are logged with the error before exiting; apply the same
replacement for both the TLS bind (bind_rustls_0_23) and the non-TLS bind to
match the other servers and preserve returning (server.handle(), server).
src/database/impls/database_connector_mysql.rs (1)

69-88: ⚡ Quick win

Use match for clearer error handling

The current if let Err pattern works, but using match is more idiomatic and makes the flow explicit. This would avoid shadowing the variable name and make it clear that only the Ok path continues to the unwrap:

Suggested refactor
-        let mysql_connect =
-            DatabaseConnectorMySQL::create(config.database.clone().path.as_str()).await;
-        if let Err(mysql_connect) = mysql_connect {
+        let mysql_pool =
+            match DatabaseConnectorMySQL::create(config.database.clone().path.as_str()).await {
+                Ok(pool) => pool,
+                Err(mysql_connect) => {
                     error!(
                         "{} Unable to connect to MySQL on DSL {}",
                         LOG_PREFIX,
                         config.database.clone().path
                     );
-            error!("{LOG_PREFIX} Message: {mysql_connect}");
-            exit(1);
-        }
+                    error!("{LOG_PREFIX} Message: {mysql_connect}");
+                    exit(1);
+                }
+            };
@@
         structure.mysql = Some(DatabaseConnectorMySQL {
-            pool: mysql_connect.unwrap(),
+            pool: mysql_pool,
         });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/database/impls/database_connector_mysql.rs` around lines 69 - 88, Replace
the current if-let shadowing flow with a match on the result returned by
DatabaseConnectorMySQL::create so the Ok and Err branches are explicit; in the
Err branch log the error using processLogger-style error calls (preserving
LOG_PREFIX and config.database.path) and exit, and in the Ok(branch) take the
successful pool value and set structure.mysql = Some(DatabaseConnectorMySQL {
pool: pool_value }) without calling unwrap; reference
DatabaseConnectorMySQL::create, the mysql_connect variable/result, and the
structure.mysql assignment to locate and change the logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/config/impls/configuration.rs`:
- Around line 597-601: The env fallback defaults for HTTP server timeouts are
incorrect: in the configuration init() the http_server defaults use
request_timeout = 15 and disconnect_timeout = 15, but the env parsing for
HTTP_{n}_REQUEST_TIMEOUT and HTTP_{n}_DISCONNECT_TIMEOUT currently falls back to
30; update the parse_env_num calls for block.request_timeout and
block.disconnect_timeout to use 15 as the default value so
parse_env_num(format!("HTTP_{http_iteration}_REQUEST_TIMEOUT"), &value, 15) and
parse_env_num(format!("HTTP_{http_iteration}_DISCONNECT_TIMEOUT"), &value, 15)
match the http_server init() defaults.
- Line 287: The rtc_interval fallback is set to 10 when parsing env in the
assignment to config.tracker_config.rtc_interval using
parse_env_num::<u64>("TRACKER__RTC_INTERVAL", &value, 10) but init() defines the
default as 30; update the fallback constant to 30 so the parse_env_num call uses
30 (i.e., replace the third argument 10 with 30) to keep defaults consistent
with init().

In `@src/structs.rs`:
- Around line 45-57: The import flags (e.g., the struct fields
import_file_torrents, import_file_whitelists, import_file_blacklists,
import_file_keys and the import_file_users entry) are incorrectly set to
requires("export"); change each attribute to requires("import") so the CLI
enforces that these --import-file-* options require the --import flag instead of
--export, then run cargo build to verify the CLI parsing compiles.

In `@src/tracker/impls/torrent_tracker_torrents_updates.rs`:
- Around line 97-103: The code currently uses SystemTime-derived nanoseconds for
"timestamp" which is non-monotonic; replace that with a process-local monotonic
sequence (e.g., an AtomicU64 incremented at enqueue time) or use
std::time::Instant-based monotonic ordering so newer updates never lose to older
ones on clock jumps. Change the places that create timestamps (the enqueue sites
currently using SystemTime at the locations corresponding to the original lines
~26 and ~42) to assign the monotonic sequence value instead, keep the same
"timestamp" variable name/type everywhere it flows, and update comparisons in
the dedupe logic (the mapping.entry(...) branch around the current match/if
timestamp > o.get().0) and in the restore handling (the code path around the
current lines ~166-168) to compare the monotonic sequence rather than wall-clock
nanoseconds.

In `@src/tracker/impls/torrent_tracker_torrents.rs`:
- Around line 100-106: get_torrent_counts() can return stale IPv6 totals because
add_torrent's occupied branch only replaces seeds and peers but not
seeds_ipv6/peers_ipv6; locate the add_torrent function and in the code path that
updates an existing entry (the "occupied" branch) also update/replace the IPv6
counters (seeds_ipv6 and peers_ipv6) to match the incoming/refresh values (or
recompute them consistently), so the entry stored under torrents_sharding (the
shard obtained via get_shard and locked via read_recursive) has both IPv4 and
IPv6 fields updated and TorrentCounts::from_entry will return correct totals.

---

Outside diff comments:
In `@Cargo.toml`:
- Line 104: The package.metadata.bundle.version ("4.2.9") in Cargo.toml is out
of sync with package.version ("4.2.10"); update the
package.metadata.bundle.version value to match the main package.version so both
read "4.2.10", ensuring the bundle version and package.version stay consistent
(look for the keys package.version and package.metadata.bundle.version in
Cargo.toml and change the bundle.version entry to the new version).

In `@src/database/impls/database_connector_sqlite.rs`:
- Around line 71-75: The error message in the SQLite connector logs the full
DSN/path (config.database.path) which may contain secrets; change the error!
call that currently references LOG_PREFIX and config.database.clone().path to
log a redacted endpoint instead—implement or call a small redaction helper
(e.g., redact_db_path or mask_credentials) and pass
redact_db_path(&config.database.path) or simply log a non-secret context string
like "sqlite://<REDACTED_PATH>" along with LOG_PREFIX and any safe fields
(database type or host if applicable) in the DatabaseConnectorSqlite connection
error path so credentials are not emitted.

---

Nitpick comments:
In `@README.md`:
- Around line 569-570: Update the v4.2.10 changelog entry (the "#### v4.2.10"
section) to replace the vague line "Various audit findings and performance
fixes" with specific bullet points describing the notable changes: mention the
refactor of scrape responses to use aggregated TorrentCounts, extraction of hex
encoding utilities into reusable helpers, centralization of environment variable
parsing, improvements to error handling across server initialization and
database operations, and a general note about performance optimizations.

In `@src/database/impls/database_connector_mysql.rs`:
- Around line 69-88: Replace the current if-let shadowing flow with a match on
the result returned by DatabaseConnectorMySQL::create so the Ok and Err branches
are explicit; in the Err branch log the error using processLogger-style error
calls (preserving LOG_PREFIX and config.database.path) and exit, and in the
Ok(branch) take the successful pool value and set structure.mysql =
Some(DatabaseConnectorMySQL { pool: pool_value }) without calling unwrap;
reference DatabaseConnectorMySQL::create, the mysql_connect variable/result, and
the structure.mysql assignment to locate and change the logic.

In `@src/tracker/impls/torrent_tracker_torrents_updates.rs`:
- Around line 111-116: The code clones the entire BTreeMap into save_torrents by
calling torrents_to_save.clone(), which is expensive; instead, avoid duplicating
TorrentEntry by either (A) constructing only the minimal payloads needed for
persistence (e.g., separate small cache/delete lists) from mapping and pass
those to save_torrents, or (B) change the signature of save_torrents to accept
torrents_to_save by value (moving it) or by reference/borrow
(&BTreeMap<InfoHash,(TorrentEntry,UpdatesAction)>) so you can move
torrents_to_save into the call without cloning; locate the creation of
torrents_to_save (mapping.iter().map(...).collect()) and the save_torrents call
and replace the clone with a move or pass a smaller precomputed payload as
appropriate, keeping symbols mapping, torrents_to_save, save_torrents,
TorrentEntry, UpdatesAction, is_persistent and torrent_tracker in mind.

In `@src/websocket/websocket.rs`:
- Around line 587-591: The websocket_master_service currently calls
.bind_rustls_0_23(...).unwrap() (and the non-SSL .bind(...) path) which is
inconsistent with the HTTP/API servers; change those unwrap() calls to use
.unwrap_or_else(|e| { error!("Failed to bind websocket server on {}:{}: {}",
addr.ip(), addr.port(), e); std::process::exit(1) }) (or the existing project
logger/exit pattern) so binding failures are logged with the error before
exiting; apply the same replacement for both the TLS bind (bind_rustls_0_23) and
the non-TLS bind to match the other servers and preserve returning
(server.handle(), server).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 424de258-6641-4c06-90b5-e051e66e1d1a

📥 Commits

Reviewing files that changed from the base of the PR and between 328e4f2 and 0d2403a.

📒 Files selected for processing (28)
  • Cargo.toml
  • README.md
  • docker/Dockerfile
  • docker/build.bat
  • src/api/api.rs
  • src/common/common.rs
  • src/config/impls/configuration.rs
  • src/database/impls/database_connector_mysql.rs
  • src/database/impls/database_connector_pgsql.rs
  • src/database/impls/database_connector_sqlite.rs
  • src/http/http.rs
  • src/main.rs
  • src/stats/impls/torrent_tracker.rs
  • src/structs.rs
  • src/tracker/impls/info_hash.rs
  • src/tracker/impls/peer_id.rs
  • src/tracker/impls/torrent_tracker_handlers.rs
  • src/tracker/impls/torrent_tracker_torrents.rs
  • src/tracker/impls/torrent_tracker_torrents_updates.rs
  • src/tracker/impls/user_id.rs
  • src/tracker/structs.rs
  • src/tracker/structs/scrape_query_request.rs
  • src/tracker/structs/torrent_counts.rs
  • src/udp/impls/parse_pool.rs
  • src/udp/impls/udp_server.rs
  • src/websocket/websocket.rs
  • tests/udp_tests.rs
  • torrust-actix.desktop
💤 Files with no reviewable changes (2)
  • src/tracker/structs/scrape_query_request.rs
  • src/udp/impls/parse_pool.rs

Comment thread src/config/impls/configuration.rs Outdated
Comment thread src/config/impls/configuration.rs Outdated
Comment thread src/structs.rs Outdated
Comment thread src/tracker/impls/torrent_tracker_torrents_updates.rs
Comment thread src/tracker/impls/torrent_tracker_torrents.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/tracker/impls/torrent_tracker_torrents.rs (1)

80-81: 💤 Low value

Verify: RTC peers intentionally excluded from global stats?

The rtc_seeds and rtc_peers fields are now correctly copied during updates, but they're not included in the Seeds/Peers stats calculations (unlike IPv4 and IPv6 counts). This appears consistent with the vacant path, so likely intentional.

Please confirm this is the desired behavior—if RTC peers should contribute to the global seed/peer counts, the delta calculations on lines 62-65 would need to include them as well.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tracker/impls/torrent_tracker_torrents.rs` around lines 80 - 81, The
update copies current.rtc_seeds and current.rtc_peers from torrent_entry but the
global Seeds/Peers stats computations (the seed_delta/peer_delta calculation
that sums IPv4/IPv6 counts) currently omit RTC counts; if RTC peers should
contribute, add current.rtc_seeds and current.rtc_peers (and corresponding
previous values) into the seed_delta and peer_delta calculations used to update
global stats so the deltas include RTC counts alongside IPv4/IPv6; otherwise
leave as-is and add a comment in the update path near
current.rtc_seeds/current.rtc_peers to document that RTC is intentionally
excluded.
src/tracker/impls/torrent_tracker_torrents_updates.rs (1)

175-183: 💤 Low value

On failure, only deduplicated entries are restored—superseded updates are lost.

The restore loop iterates over mapping which contains only the newest entry per InfoHash. If the original queue had multiple updates for the same hash (e.g., timestamps 1, 2, 3 for hash A), only the newest (timestamp 3) is restored after a DB failure. The older updates (1, 2) are permanently discarded.

This is likely acceptable since superseded updates represent stale state, but if the intent was to preserve all original entries on failure for potential retry, this behavior differs. The stats accounting is correct for the post-restore state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tracker/impls/torrent_tracker_torrents_updates.rs` around lines 175 -
183, The restore loop currently iterates over a deduplicated `mapping` (newest
per `InfoHash`) and inserts only one entry per hash into
`self.torrents_updates.write()` via `lock.entry(timestamp)`, losing superseded
updates; change the restore logic to iterate over the full original set of saved
updates (or make `mapping` map each `InfoHash` to a Vec of `(timestamp,
torrent_entry, updates_action)`) and insert each preserved update into the
write-lock (ensuring you still use `lock.entry(timestamp)` or a disambiguated
key to avoid collisions), then compute `restored` as the count of all
re-inserted entries and call `self.update_stats(StatsEvent::TorrentsUpdates,
restored)` so all original updates are restored rather than only the
deduplicated newest ones.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/tracker/impls/torrent_tracker_torrents_updates.rs`:
- Around line 175-183: The restore loop currently iterates over a deduplicated
`mapping` (newest per `InfoHash`) and inserts only one entry per hash into
`self.torrents_updates.write()` via `lock.entry(timestamp)`, losing superseded
updates; change the restore logic to iterate over the full original set of saved
updates (or make `mapping` map each `InfoHash` to a Vec of `(timestamp,
torrent_entry, updates_action)`) and insert each preserved update into the
write-lock (ensuring you still use `lock.entry(timestamp)` or a disambiguated
key to avoid collisions), then compute `restored` as the count of all
re-inserted entries and call `self.update_stats(StatsEvent::TorrentsUpdates,
restored)` so all original updates are restored rather than only the
deduplicated newest ones.

In `@src/tracker/impls/torrent_tracker_torrents.rs`:
- Around line 80-81: The update copies current.rtc_seeds and current.rtc_peers
from torrent_entry but the global Seeds/Peers stats computations (the
seed_delta/peer_delta calculation that sums IPv4/IPv6 counts) currently omit RTC
counts; if RTC peers should contribute, add current.rtc_seeds and
current.rtc_peers (and corresponding previous values) into the seed_delta and
peer_delta calculations used to update global stats so the deltas include RTC
counts alongside IPv4/IPv6; otherwise leave as-is and add a comment in the
update path near current.rtc_seeds/current.rtc_peers to document that RTC is
intentionally excluded.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2aeb64d1-ba44-4c76-ac0d-39566d970d69

📥 Commits

Reviewing files that changed from the base of the PR and between 0d2403a and 34f5e91.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • src/config/impls/configuration.rs
  • src/structs.rs
  • src/tracker/impls/torrent_tracker_torrents.rs
  • src/tracker/impls/torrent_tracker_torrents_updates.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/config/impls/configuration.rs

@Power2All Power2All merged commit f95ba67 into master May 8, 2026
2 checks passed
@Power2All Power2All deleted the v4.2.10 branch May 8, 2026 12:10
This was referenced May 31, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Jun 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant