Skip to content

perf(usync): batch LID-PN re-learn from device response off the cold group-send path - #680

Merged
jlucaso1 merged 3 commits into
mainfrom
perf/batch-usync-lid-relearn
Jun 1, 2026
Merged

perf(usync): batch LID-PN re-learn from device response off the cold group-send path#680
jlucaso1 merged 3 commits into
mainfrom
perf/batch-usync-lid-relearn

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Context

Continued group-send benchmark profiling against the current main (post #677/#678/#679). The big bottleneck — migrate_signal_sessions_on_lid_discovery (10 GB on an 800-member cold send) — is already fixed (#677): the cold send now allocates only ~16.6 MB. Profiling the remainder surfaced one clean, latency-only redundancy.

Finding

process_device_list_response (the usync device-list handler inside get_user_devices) learned each LID↔PN mapping by awaiting add_lid_pn_mapping per entry — a serial record + DB write + migration per mapping. On a large cold group send, the device usync echoes the same mappings query_info already learned moments earlier (via its batched, detached learn_lid_pn_mappings_batch), so the send blocked on ~N serial awaited DB writes for pairs we already had.

CPU was never the issue (0.15 s total for 40 sends to 800 members); this was wall-clock latency from serial awaited spawn_blocking SQLite hops on the send's critical path.

Change

Route the usync re-learn through learn_lid_pn_mappings_batch (the same path query_info uses): one detached transaction for genuinely-new pairs, internally guarded against re-learning already-durable ones. Falls back to the per-mapping path if the owning Arc<Client> isn't available. No new ordering risk — query_info already triggers these migrations detached before get_user_devices runs.

Measurement (group-send bench, 800 members, mock server, single A/B)

metric baseline this PR Δ
ack_avg 64.50 ms 55.48 ms −14%
ack_max (cold first send) 139.33 ms 95.68 ms −31%
pong_avg 80.56 ms 73.39 ms −9%
duration 683 ms 671 ms −2%
CPU total 0.150 s 0.150 s =
dhat total alloc 16.61 MB 16.70 MB = (alloc unchanged; pure latency win)

Multiple independent metrics moved together, consistent with removing the serial awaited writes from the cold send.

Scope note

The remaining client-side cost for large groups (per-member device/LID resolution on every send: get_current_lid/resolve_lookup_keys String churn) is O(members × messages) but CPU-cheap (0.15 s total), so it isn't pursued here. The dominant per-send latency (pong ~73 ms) is server/network fanout + the per-(group,sender) chain-lock serializing the bench flood, not client work.

Tests: clippy --all-targets -D warnings clean; whatsapp-rust lib suite (659) green; existing process_response_preserves_omitted_users (merge-safety) unaffected.

…path

process_device_list_response learned every LID↔PN mapping in a usync device
response by awaiting add_lid_pn_mapping per entry — a serial record + DB write +
migration per mapping. On a large cold group send the device usync echoes the
same mappings query_info already learned (via its batched, detached learn), so
the send blocked on ~N serial awaited DB writes for pairs we already had.

Route it through learn_lid_pn_mappings_batch instead: one detached transaction
for genuinely-new pairs, internally guarded against re-learning durable ones
(same path query_info uses). Falls back to the per-mapping path if the owning
Arc<Client> isn't available.

Allocation is unchanged (the records are still built); the win is latency —
the serial awaited writes leave the cold-send critical path.

Bench (group-send, 800 members, mock server, single A/B):
  ack_avg   64.50 -> 55.48 ms  (-14%)
  ack_max  139.33 -> 95.68 ms  (-31%, the cold first send)
  pong_avg  80.56 -> 73.39 ms  (-9%)
  CPU total unchanged (0.150 s); dhat total unchanged (~16.6 MB).
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9cdeff8f-b4b0-43b3-81c6-2eeaa641f6ed

📥 Commits

Reviewing files that changed from the base of the PR and between 3002df1 and 9ddc7d9.

📒 Files selected for processing (1)
  • src/usync.rs

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Device sync now batches and persists identifier-to-phone mappings more efficiently, with a safer fallback to per-item persistence if batching isn’t available.
  • Bug Fixes
    • Newly learned mappings are guaranteed available immediately after sync completes, reducing transient lookup failures and improving reliability.

Walkthrough

process_device_list_response now batches LID↔phone-number persistence via learn_lid_pn_mappings_batch when Client is available, collecting pairs first; otherwise it falls back to per-mapping add_lid_pn_mapping and warns on failures. A Tokio test ensures the batched path warms lid_pn_cache synchronously before returning.

Changes

Batched LID↔Phone Number Persistence

Layer / File(s) Summary
Batched mapping persistence with fallback
src/usync.rs
process_device_list_response collects (lid, phone_number) pairs, attempts to upgrade self_weak to an owned Client, and calls learn_lid_pn_mappings_batch. If upgrade fails, it falls back to sequential add_lid_pn_mapping and emits warnings on per-mapping failures. Removed unconditional per-mapping persistence and per-success debug logging. Added a Tokio test to assert lid_pn_cache is resolvable immediately after the batched branch returns.

Sequence Diagram

sequenceDiagram
    participant Response as process_device_list_response
    participant Weak as self_weak
    participant Client
    participant Batch as learn_lid_pn_mappings_batch
    participant Fallback as add_lid_pn_mapping

    Response->>Response: collect (lid, pn) pairs
    Response->>Weak: upgrade to Client
    alt Client obtained
        Weak-->>Client: owned reference
        Response->>Batch: call with collected pairs
        Batch-->>Response: batch persist complete
    else Client unavailable
        Weak-->>Response: None
        Response->>Response: log warning
        loop per mapping
            Response->>Fallback: persist individual mapping
            Fallback-->>Response: result
            Response->>Response: warn on failure
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: batching LID-PN re-learning from device response during the cold group-send path.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, providing context, findings, implementation details, benchmarks, and test results.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/batch-usync-lid-relearn

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6fe7a1dd7d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/usync.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.

Actionable comments posted: 1

🤖 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/usync.rs`:
- Around line 84-87: The warn! call is logging raw PII (mapping.lid and
mapping.phone_number); replace those with non-identifying representations (e.g.,
deterministic hash or masked/redacted string) before logging. Update the
usync.rs code path that emits warn! to compute a safe identifier (e.g.,
hash_and_truncate(mapping.lid) and hash_and_truncate(mapping.phone_number) or
mask_last_n()) and use those values in the warn! message instead of
mapping.lid/mapping.phone_number so logs never contain raw LIDs or phone
numbers.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2f5d8042-7ab8-4040-9016-4d7de2337fd8

📥 Commits

Reviewing files that changed from the base of the PR and between 29d4689 and 6fe7a1d.

📒 Files selected for processing (1)
  • src/usync.rs

Comment thread src/usync.rs
@jlucaso1

jlucaso1 commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Jun 1, 2026

Copy link
Copy Markdown

Claude finished @jlucaso1's task in 3m 0s —— View job


Code Review

  • Read src/usync.rs change
  • Examined learn_lid_pn_mappings_batch and persist_and_migrate_lid_pn_batch to evaluate ordering semantics
  • Evaluated Codex P1 finding (PN→LID migration ordering race)
  • Evaluated CodeRabbit P1 finding (PII in warn log)
  • Cross-checked the query_info precedent in src/features/groups.rs
  • Could not run cargo clippy/cargo test in this environment (permission denied)

Summary

The change is well-motivated, narrowly scoped, and follows an already-established pattern: query_info in src/features/groups.rs:249-265 already uses learn_lid_pn_mappings_batch with the same self_weak-upgrade fallback shape. Collapsing N awaited per-mapping DB writes into one detached batched transaction is the right shape and the measurement table (cold ack_max −31%, ack_avg −14%) is consistent with removing serial spawn_blocking SQLite hops from the cold critical path.

The dedup-by-phone + can_skip_relearn filter inside learn_lid_pn_mappings_batch (src/client/lid_pn.rs:157-185) correctly handles the common case where query_info already learned a pair moments earlier — those entries are filtered out before the detached task is even spawned, which is the actual source of the latency win on a cold group send.

The if !response.lid_mappings.is_empty() guard keeps the existing process_response_preserves_omitted_users test path unchanged (empty lid_mappings short-circuits before the new code).

Findings

1. Codex P1 (ordering): real-but-narrow concern, worth a direct response from the author.

The race shape Codex describes is real in theory: the previous add_lid_pn_mapping awaited migrate_signal_sessions_on_lid_discovery before returning, so any caller of get_user_devices that proceeded to resolve_encryption_jid + Signal-encrypt on the freshly-resolved LID was guaranteed to see a clean LID slot (PN-wins migration had already moved the session over). This PR drops that guarantee for the standalone usync paths.

That said, two important mitigations limit the blast radius:

  • It's not new for the cold group-send path. query_info (src/features/groups.rs:249-265) already learns LID↔PN mappings via the same detached batched path before get_user_devices runs, and its detached migration is racing the same window. The PR description is correct that the group-send call site doesn't change its ordering risk — usync just stops re-doing work query_info already detached.
  • Even when the race fires, migrate_signal_sessions_on_lid_discovery takes the same per-address session_lock_for locks that encrypt/decrypt take (src/client/lid_pn.rs:431-441). A concurrent encrypt on LID cannot interleave with the put/delete; it can only be fully-before or fully-after. The hazard is therefore strictly the "ratchet on empty LID before migration overwrites with PN-wins" sequence — only triggerable when usync is the first learner of a particular LID for a contact that already has PN Signal state.

Practically, that narrows the concern to standalone usyncs that are not preceded by query_info's batch — primarily flush_pending_device_sync (src/usync.rs:239-270) when the user already had a PN session and sync_own_device_list (src/usync.rs:204-236). For the latter, own-device LIDs are typically learned via the pairing flow rather than discovered later, so the empirical race window is small.

Suggested action: acknowledge this in the PR description or a one-line code comment noting the standalone-usync window, so a future reader understands why the fallback path is kept and what guarantee was traded for the latency win. No need to revert; the existing locking discipline is the actual correctness barrier.

2. CodeRabbit P1 (PII in warn log) — pre-existing, not introduced here.

The warn!("Failed to persist LID {} -> {} from usync: {err}", mapping.lid, mapping.phone_number) at src/usync.rs:84-87 logs raw LID + phone number. CodeRabbit is right that this is PII, but:

  • The exact same warn! (and a debug! peer that was actually removed) existed on main before this PR — see the - lines in the diff. The fallback branch is a verbatim copy of the pre-existing loop body.
  • Identical-shape logs already exist elsewhere (migrate_signal_sessions_on_lid_discovery at src/client/lid_pn.rs:452-455, :484 etc., log raw pn_proto/lid_proto JIDs).

So this is a pre-existing log hygiene issue, not a regression. Reasonable to defer to a separate redaction-pass PR that covers the whole module consistently rather than tackling one line here.

3. Test coverage — minor gap, optional.

The new batched path in process_device_list_response is exercised indirectly by test_learn_lid_pn_mappings_batch_* in src/client/lid_pn.rs:822+. The only test that touches process_device_list_response directly (process_response_preserves_omitted_users, src/usync.rs:396-454) uses lid_mappings: vec![] and short-circuits past the new code. A small addition with non-empty lid_mappings asserting that (a) the cache is warmed synchronously and (b) the function returns without awaiting per-mapping persistence would lock the new contract in place. Not a blocker.

Nits

  • The fallback else branch (Arc upgrade fails) is effectively unreachable in normal operation — self_weak is populated during Client construction. Keeping it as a safety net is fine; just noting it for readers who might wonder when it can fire.
  • Minor: the inline doc comment at src/usync.rs:53-59 is good context, but the "previously per-mapping ... redid ~N writes" sentence will rot if query_info ever stops being the upstream learner. Optional: shorten to the invariant ("usync mappings are routed through the same batched learner query_info uses") rather than the historical comparison.

Verdict

Solid latency-only optimization with measurements that line up with the mechanism. The ordering concern Codex raises is real but limited to a narrow window the codebase's locking already partially covers, and not strictly a regression for the cold-group-send path the PR targets. I'd merge with (optionally) a one-line comment acknowledging the standalone-usync ordering window, and leave the PII-log cleanup for a focused follow-up.
• branch perf/batch-usync-lid-relearn

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

Benchmark Results

67 unchanged benchmark(s)
Benchmark Current Baseline Change
reporting_token_benchmark::content_extraction_group::bench_content_extraction simple:setup_simple_message() 3,933 3,933 +0.0%
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message() 12,038 12,038 +0.0%
reporting_token_benchmark::key_derivation_group::bench_key_derivation 43,514 43,514 +0.0%
reporting_token_benchmark::token_calculation_group::bench_token_calculation 19,365 19,365 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple() 68,579 68,579 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended() 76,679 76,679 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message() 2,230 2,230 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message() 5,988 5,988 +0.0%
send_receive_benchmark::dm_send::bench_dm_send text:setup_dm_send() 183,120 183,396 -0.2%
send_receive_benchmark::dm_recv::bench_dm_recv text:setup_dm_recv() 2,204,889 2,204,889 +0.0%
send_receive_benchmark::group_send::bench_group_send group_10:setup_group_send_10() 932,987 933,109 -0.0%
send_receive_benchmark::group_send::bench_group_send group_50:setup_group_send_50() 1,211,796 1,212,508 -0.1%
send_receive_benchmark::group_send::bench_group_send group_256:setup_group_send_256() 2,733,246 2,733,056 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_10:setup_group_skdm_10() 1,142,984 1,143,322 -0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_50:setup_group_skdm_50() 2,188,091 2,191,480 -0.2%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_256:setup_group_skdm_256() 7,630,199 7,626,325 +0.1%
send_receive_benchmark::group_recv::bench_group_recv text:setup_group_recv() 12,689,072 12,760,941 -0.6%
binary_benchmark::marshal_group::bench_marshal_allocating 71,296 71,296 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_allocating 71,349 71,349 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_allocating 98,416 98,416 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer 78,796 78,796 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer 71,396 71,396 +0.0%
binary_benchmark::marshal_group::bench_marshal_long_string 7,599 7,599 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_long_string 7,642 7,642 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_long_string 9,354 9,354 +0.0%
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating 530,581 530,581 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating 530,149 530,149 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating 531,504 531,504 +0.0%
binary_benchmark::marshal_group::bench_marshal_many_children_allocating 8,506,104 8,506,104 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating 8,450,452 8,450,452 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating 19,677,941 19,677,941 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled() 2,468 2,468 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled() 33,558 33,558 +0.0%
binary_benchmark::unpack_group::bench_unpack_uncompressed 787 787 +0.0%
binary_benchmark::unpack_group::bench_unpack_compressed 526,830 526,830 +0.0%
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled() 4,990 4,990 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled() 5,315 5,315 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled() 61,874 61,874 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled() 5,347 5,347 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled() 61,942 61,942 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled() 6,734 6,734 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled() 85,585 85,585 +0.0%
binary_benchmark::child_iteration_group::bench_get_children_by_tag 477,570 477,570 +0.0%
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled() 11,563 11,563 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u32 396 396 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u32 120 120 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u64 439 439 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u64 153 153 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_i64 499 499 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_i64 162 162 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_loop_100_u64 44,624 44,624 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_loop_100_u64 16,424 16,424 +0.0%
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users() 17,216,820 17,180,310 +0.2%
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session() 157,179 157,179 +0.0%
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message() 5,513,975 5,513,975 +0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session() 157,539 157,539 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender() 296,767 296,767 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution() 706,282 706,282 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message() 12,666,337 12,545,853 +1.0%
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data() 27,559,843 27,673,477 -0.4%
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message() 3,467,011 3,467,011 +0.0%
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message() 126,137,913 125,827,783 +0.2%
libsignal_benchmark::signature_group::bench_key_generation keygen 2,830,452 2,830,452 +0.0%
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions() 46,566 46,566 +0.0%
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages() 5,197,012 5,197,012 +0.0%
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session() 360,648 360,648 +0.0%
libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction() 14,255,917 14,255,917 +0.0%
No significant changes detected.

Addresses the code review on #680:
- Reword the comment to the invariant (route usync mappings through the same
  batched learner query_info uses) and add an ordering note: detaching the
  migration trades the awaited PN->LID migration ordering on standalone usync
  paths (sync_own_device_list / flush_pending_device_sync), but the per-address
  session_lock_for both the migration and encrypt take is the real barrier (no
  interleave); the group-send path is unchanged since query_info already learns
  these pairs detached upstream. No revert (per review).
- Add process_response_warms_lid_pn_cache_synchronously: non-empty lid_mappings
  is resolvable in-cache the moment the call returns (persist runs detached),
  locking the new path's synchronous-warm contract.

PII-in-log finding skipped: pre-existing (verbatim from the prior loop) and out
of scope per the owner.

@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: 1

🤖 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/usync.rs`:
- Around line 466-497: The test
process_response_warms_lid_pn_cache_synchronously is insufficient because it
never forces the batched path (learn_lid_pn_mappings_batch) to run detached —
both learn_lid_pn_mappings_batch and add_lid_pn_mapping currently warm
lid_pn_cache before returning, so the test can pass even when self_weak fails to
upgrade and falls back to the slow path. Modify the test to assert or arrange
that the batched branch is taken: ensure the fixture (create_test_client /
Client) can provide a valid Arc<Client> upgrade from self_weak (or otherwise
mock/spy the client so learn_lid_pn_mappings_batch is invoked), and then verify
the detached behavior (for example, by stubbing/instrumenting
learn_lid_pn_mappings_batch to run asynchronously and ensuring lid_pn_cache is
not populated until the detached task runs) rather than relying on
add_lid_pn_mapping; reference process_device_list_response,
learn_lid_pn_mappings_batch, add_lid_pn_mapping, lid_pn_cache and self_weak when
making the change.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1753d832-b241-4895-b9c0-b46b73cb17dd

📥 Commits

Reviewing files that changed from the base of the PR and between 6fe7a1d and 3002df1.

📒 Files selected for processing (1)
  • src/usync.rs

Comment thread src/usync.rs
The test could have passed via the per-mapping fallback (both paths warm the
cache). create_test_client populates self_weak (client.rs sets it right after
the Arc is built), so the batched branch is in fact the one taken; assert the
self_weak upgrade to pin that deterministically.

Skipped the reviewer's "verify cache is not populated until the detached task
runs" suggestion: the batched path warms the cache synchronously by design
(record_lid_pn_in_memory is sync; only the persist is detached), so that
assertion would contradict the intended behavior the test locks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant