Skip to content

perf(store): cache the device snapshot as Arc<Device> - #808

Merged
jlucaso1 merged 3 commits into
mainfrom
perf/arc-device-snapshot
Jun 9, 2026
Merged

perf(store): cache the device snapshot as Arc<Device>#808
jlucaso1 merged 3 commits into
mainfrom
perf/arc-device-snapshot

Conversation

@jlucaso1

@jlucaso1 jlucaso1 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Problem

get_device_snapshot() deep-cloned the whole Device on every call (persistence_manager.rs:66-68): two Jids, push_name, props_hash, edge_routing_info (up to ~KB), nct_salt — ~5-8 heap allocations per call. It has ~72 call sites, including once per inbound message (parse_message_info reads pn/lid) and throughout the send/receipt paths. Separately, many read-only paths paid an RwLock read on the device arc just to reach .backend or clone two fields, and the get_pn/get_lid/get_push_name accessors did an async lock dance per call.

Change

PersistenceManager keeps a device_snapshot: std::sync::RwLock<Arc<Device>>, rebuilt under the device write guard inside modify_device — the single mutation funnel (process_command and every direct modify_device caller go through it; the signal-store write locks only delegate to the backend and never mutate Device fields, verified across all impl *Store for Device). Reads can therefore never observe a stale snapshot relative to a committed mutation, and the rebuild cost is one Device clone per mutation (rare: pairing, push-name sync, prekey counter) instead of one per read.

  • get_device_snapshot() is now sync and returns Arc<Device> — a refcount bump, no lock against writers, no clone.
  • get_pn / get_lid / get_push_name / require_pn are now sync via the snapshot; the owned return is the only clone left.
  • ~15 read-only get_device_arc() sites (retry base-key/session checks, ensure_sessions_inner, prekey upload paths, signal feature checks, send force-SKDM checks, parse_message_info) switch to the snapshot.
  • Per "avoid unnecessary clones": send status/group paths and parse_message_info now borrow pn/lid/account from the held snapshot instead of cloning (the old code cloned the whole Device precisely so it could .take() two fields); clones remain only where ownership escapes the scope (e.g. PDO's MessageInfo.sender).
  • get_device_arc() stays, documented as store-adapter-only (&mut Device trait access).

Invariant made explicit

Direct Device mutation through the raw write lock now bypasses the cached snapshot — it was already against the documented convention, but four tests in message/tests.rs did it; they now use modify_device. AGENTS.md (State convention) and agent_docs/feature_implementation.md updated: mutations via DeviceCommand/modify_device only (tests included), reads via the cheap snapshot, borrow over clone.

Verification

Full workspace cargo test: 2087 passed, 0 failed (includes e2e compile via cargo check -p e2e-tests --tests). cargo clippy --all --tests clean, fmt clean. Diff: 52 files, +254/−365.

Breaking (pre-1.0)

  • get_device_snapshot(): async fn → Device becomes fn → Arc<Device>.
  • get_push_name() / get_pn() / get_lid(): no longer async.
    Call-site migration is mechanical: drop .await, and either deref fields (snapshot.pn.as_ref()) or clone where ownership is needed.

Generated by Claude Code

get_device_snapshot() cloned the whole Device on every call — Jids,
push_name, props_hash, edge_routing_info and nct_salt heap allocations —
and it is called on every inbound message plus ~70 other sites. The
snapshot is now an Arc<Device> rebuilt under the device write guard in
modify_device (the single mutation funnel), so reads become a refcount
bump with no lock against writers and no clone, and can never observe a
stale snapshot relative to a committed mutation.

Fallout, in the same spirit of avoiding needless work:
- get_device_snapshot() and the get_pn/get_lid/get_push_name/require_pn
  accessors are now sync (no async lock dance); call sites updated.
- Read-only get_device_arc() users (retry, sessions, prekeys, signal
  feature, send force-skdm checks, receive parse_message_info) switch to
  the snapshot — each was paying an RwLock read just to reach .backend
  or clone pn/lid.
- Send/receive paths borrow pn/lid/account from the held snapshot
  instead of cloning them; clones remain only where ownership leaves
  the scope.
- Tests that mutated Device through the raw write lock now go through
  modify_device — direct mutation would bypass the cached snapshot, so
  the docs now state that invariant explicitly (AGENTS.md, agent_docs).

Breaking (pre-1.0): get_device_snapshot returns Arc<Device> and is no
longer async; the three accessors are no longer async; get_device_arc
is documented as store-adapter-only.
@coderabbitai

coderabbitai Bot commented Jun 9, 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: d2af3c77-468b-419e-ac2f-b868422e51af

📥 Commits

Reviewing files that changed from the base of the PR and between 98b0921 and e79f1c6.

📒 Files selected for processing (7)
  • src/client/app_state.rs
  • src/client/messaging.rs
  • src/message/tests.rs
  • src/pdo.rs
  • src/request.rs
  • src/send.rs
  • tests/e2e/tests/receipts.rs

📝 Walkthrough

Summary by CodeRabbit

  • Refactor
    • Device state access moved to a cached, synchronous snapshot for faster, lower-latency reads.
    • Internal call sites and tests updated to use the new snapshot API.
    • No functional changes; users should see improved responsiveness and stability across messaging, presence, media, syncing, and session flows.

Walkthrough

Convert PersistenceManager to expose a cached Arc via a synchronous get_device_snapshot(), make client identity getters synchronous, refactor runtime/send/session/prekey/retry flows to use borrowed snapshot fields, and update tests and docs to the new mutation/read conventions.

Changes

Synchronous Device Snapshot Access Refactoring

Layer / File(s) Summary
PersistenceManager core & docs
src/store/persistence_manager.rs, AGENTS.md, agent_docs/feature_implementation.md
Adds device_snapshot: RwLock<Arc<Device>>, changes get_device_snapshot() to return Arc<Device>, rebuilds snapshot in modify_device, and documents read/mutation conventions (no direct Device mutation).
Client accessors converted to synchronous
src/client/accessors.rs
get_push_name, get_pn, get_lid, require_pn become non-async and read fields from the synchronous snapshot; call sites updated.
Runtime call-sites & handlers
src/* (lifecycle, node_io, app_state, handlers, pairing, handshake)
Remove .await on snapshot/getter calls across lifecycle, node IO, app-state mutation, pairing, handshake, and notification handlers; use borrowed snapshot fields where required.
Signal/session/retry/prekey backend access
src/client/sessions.rs, src/features/signal.rs, src/retry.rs, src/prekeys.rs
Replace async device-store read-guard backend access with snapshot.backend reads for session checks, sender-key queries, prekey operations, and retry/session recovery logic.
Send/receive & message flows
src/send.rs, src/message/*, src/pdo.rs, src/request.rs
Make message-id generation sync, borrow identity fields from snapshots during send and parse flows, rewire sender-key gating to use snapshot backend, and update phash/fallback handling accordingly.
Tests: unit/integration and e2e
src/message/tests.rs, tests/e2e/*, src/bot.rs, src/client/device_registry.rs
Update tests to call get_device_snapshot() synchronously, replace direct device write guards with pm.modify_device mutations, and remove .await from many helper getters.
Feature modules
src/features/* (media_reupload, polls, presence, contacts, events)
Use synchronous snapshot/getters for identity resolution and state checks; preserve existing logic while changing data-access patterns.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the core performance optimization: converting device snapshot retrieval to use Arc caching for efficiency.
Description check ✅ Passed The description comprehensively explains the problem, solution, invariants, verification results, and breaking changes, all directly relevant to the changeset.
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/arc-device-snapshot

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.

@github-actions

github-actions Bot commented Jun 9, 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() 2,927 2,927 +0.0%
reporting_token_benchmark::content_extraction_group::bench_content_extraction extended:setup_extended_message() 8,448 8,448 +0.0%
reporting_token_benchmark::key_derivation_group::bench_key_derivation 31,317 31,317 +0.0%
reporting_token_benchmark::token_calculation_group::bench_token_calculation 13,827 13,827 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation simple:setup_full_gen_simple() 49,487 49,487 +0.0%
reporting_token_benchmark::full_generation_group::bench_full_token_generation extended:setup_full_gen_extended() 55,003 55,003 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding simple:setup_simple_message() 1,679 1,679 +0.0%
reporting_token_benchmark::message_encoding_group::bench_message_encoding extended:setup_extended_message() 4,393 4,393 +0.0%
send_receive_benchmark::dm_send::bench_dm_send text:setup_dm_send() 113,198 112,952 +0.2%
send_receive_benchmark::dm_recv::bench_dm_recv text:setup_dm_recv() 1,656,621 1,656,732 -0.0%
send_receive_benchmark::group_send::bench_group_send group_10:setup_group_send_10() 644,107 643,876 +0.0%
send_receive_benchmark::group_send::bench_group_send group_50:setup_group_send_50() 870,058 870,044 +0.0%
send_receive_benchmark::group_send::bench_group_send group_256:setup_group_send_256() 2,075,843 2,075,883 -0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_10:setup_group_skdm_10() 742,277 742,277 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_50:setup_group_skdm_50() 1,320,840 1,320,628 +0.0%
send_receive_benchmark::group_send_skdm::bench_group_send_skdm skdm_256:setup_group_skdm_256() 4,388,503 4,363,858 +0.6%
send_receive_benchmark::group_recv::bench_group_recv text:setup_group_recv() 518,219 515,856 +0.5%
binary_benchmark::marshal_group::bench_marshal_allocating 45,381 45,381 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_allocating 45,431 45,431 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_allocating 66,334 66,334 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer 43,492 43,492 +0.0%
binary_benchmark::marshal_group::bench_marshal_reusing_buffer_vec_writer 45,487 45,487 +0.0%
binary_benchmark::marshal_group::bench_marshal_long_string 4,945 4,945 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_long_string 4,976 4,976 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_long_string 6,747 6,747 +0.0%
binary_benchmark::marshal_group::bench_marshal_huge_bytes_allocating 528,544 528,544 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_huge_bytes_allocating 528,165 528,165 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_huge_bytes_allocating 529,411 529,411 +0.0%
binary_benchmark::marshal_group::bench_marshal_many_children_allocating 5,417,732 5,417,732 +0.0%
binary_benchmark::marshal_group::bench_marshal_auto_many_children_allocating 5,362,047 5,362,047 +0.0%
binary_benchmark::marshal_group::bench_marshal_exact_many_children_allocating 13,276,365 13,276,365 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal small:setup_small_marshaled() 1,850 1,850 +0.0%
binary_benchmark::unmarshal_group::bench_unmarshal large:setup_large_marshaled() 29,217 29,217 +0.0%
binary_benchmark::unpack_group::bench_unpack_uncompressed 618 618 +0.0%
binary_benchmark::unpack_group::bench_unpack_compressed 672,890 672,890 +0.0%
binary_benchmark::attr_parser_group::bench_attr_parser attr_lookup:setup_attr_marshaled() 3,736 3,736 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip small:setup_small_marshaled() 3,840 3,840 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip large:setup_large_marshaled() 48,274 48,274 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto small:setup_small_marshaled() 3,866 3,866 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_auto large:setup_large_marshaled() 48,335 48,335 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact small:setup_small_marshaled() 5,206 5,206 +0.0%
binary_benchmark::roundtrip_group::bench_roundtrip_exact large:setup_large_marshaled() 66,659 66,659 +0.0%
binary_benchmark::child_iteration_group::bench_get_children_by_tag 310,312 310,312 +0.0%
binary_benchmark::jid_optimization_group::bench_jid_to_owned_access jid_access:setup_jid_heavy_marshaled() 8,291 8,291 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u32 254 254 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u32 91 91 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_u64 292 292 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_u64 137 137 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_i64 317 317 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_i64 145 145 +0.0%
numeric_attr_benchmark::bench_group::bench_baseline_loop_100_u64 27,425 27,425 +0.0%
numeric_attr_benchmark::bench_group::bench_proposed_loop_100_u64 10,725 10,725 +0.0%
libsignal_benchmark::dm_group::bench_dm_session_establishment setup:setup_dm_users() 4,138,451 4,139,538 -0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_first_message first_msg:setup_dm_session() 100,131 100,131 +0.0%
libsignal_benchmark::dm_group::bench_dm_decrypt_first_message decrypt_prekey:setup_dm_with_first_message() 4,264,189 4,264,189 +0.0%
libsignal_benchmark::dm_group::bench_dm_encrypt_subsequent_message subsequent:setup_established_dm_session() 100,399 100,399 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_create_distribution_message create:setup_group_sender() 210,262 210,262 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_encrypt_message encrypt:setup_group_with_distribution() 496,921 496,921 +0.0%
libsignal_benchmark::group_messaging_group::bench_group_decrypt_message decrypt:setup_group_with_encrypted_message() 509,931 504,005 +1.2%
libsignal_benchmark::conversation_group::bench_full_dm_conversation full:setup_conversation_data() 11,973,821 11,979,056 -0.0%
libsignal_benchmark::signature_group::bench_signature_creation sign:setup_keypair_with_message() 2,466,138 2,466,138 +0.0%
libsignal_benchmark::signature_group::bench_signature_verification verify:setup_keypair_with_message() 4,912,402 4,921,132 -0.2%
libsignal_benchmark::signature_group::bench_key_generation keygen 2,043,351 2,043,351 +0.0%
libsignal_benchmark::session_optimization_group::bench_decrypt_with_previous_session previous_session:setup_with_archived_sessions() 37,414 37,414 +0.0%
libsignal_benchmark::session_optimization_group::bench_out_of_order_decryption out_of_order:setup_out_of_order_messages() 3,617,967 3,617,967 +0.0%
libsignal_benchmark::session_optimization_group::bench_promote_matching_session promote:setup_promote_matching_session() 230,648 230,658 -0.0%
libsignal_benchmark::session_optimization_group::bench_message_key_eviction eviction:setup_message_key_eviction() 9,980,959 9,980,959 +0.0%
No significant changes detected.

@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: 23ef08c178

ℹ️ 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/store/persistence_manager.rs
The borrowed pn/lid bindings made the explicit &x at call sites a
double reference (clippy needless_borrow under -D warnings).

Review follow-up: set the dirty flag immediately after the modifier,
before the snapshot clone — a shutdown flush racing that window checked
dirty, saw clean, and could exit without persisting the committed
mutation. The flush's device read lock still serializes against the
held write guard, so it always saves post-mutation state.

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

Caution

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

⚠️ Outside diff range comments (2)
src/message/tests.rs (1)

1753-1765: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Extract a shared identity-seeding helper for these tests.

You repeat the same pm.modify_device setup four times. Pulling this into one helper will keep these tests easier to evolve and reduces drift risk when device identity setup changes again.

Also applies to: 2452-2464, 2550-2562, 2644-2656

🤖 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/message/tests.rs` around lines 1753 - 1765, Extract the repeated
pm.modify_device block into a single async test helper (e.g.,
seed_test_device_identity or setup_test_device_identity) that takes &pm (or &mut
PM test handle) and performs the device.pn and device.lid assignments currently
done inside pm.modify_device; replace each duplicated inline
pm.modify_device({...}).await with a call to that helper from the four test
sites (the occurrences around lines 1753, 2452, 2550, 2644) so tests call await
seed_test_device_identity(&pm). Ensure the helper is async and lives in the same
test module (or a common tests::helpers mod) so it can be reused by all tests.
src/features/events.rs (1)

133-141: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider removing async from resolve_responder_jid.

Look, this method doesn't await anything anymore since get_lid() is now synchronous. The async keyword here is just dead weight. Not a blocker, but you should clean this up - we don't ship unnecessary complexity at Meta.

♻️ Suggested cleanup
-    async fn resolve_responder_jid(&self, event_creator_jid: &Jid, own_pn: &Jid) -> Jid {
+    fn resolve_responder_jid(&self, event_creator_jid: &Jid, own_pn: &Jid) -> Jid {

And update the call site at line 86-88:

         let responder = self
             .resolve_responder_jid(event_creator_jid, &my_base)
-            .await;
+            ;
🤖 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/features/events.rs` around lines 133 - 141, The function
resolve_responder_jid no longer needs to be async because it does not await
anything; change its signature to remove async (e.g., fn
resolve_responder_jid(&self, event_creator_jid: &Jid, own_pn: &Jid) -> Jid) and
keep the same body (calling self.client.get_lid()). Then update all call sites
that currently await this method to call it synchronously (remove .await and
handle the returned Jid directly); also update any trait signatures or impls if
they declared the method as async so the types remain consistent.
🤖 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/message/tests.rs`:
- Line 1040: Tests call client.persistence_manager.get_device_snapshot()
multiple times within the same JID resolution fallback chain (e.g., when
resolving lid/pn), which can produce flaky behavior; fix by calling
get_device_snapshot() once at the start of the resolution path, store the
returned Arc<Device> in a local variable (e.g., snapshot) and then use
snapshot.lid.clone() / snapshot.pn.clone() (or equivalent fields) for all
fallback .or(...) branches instead of re-invoking get_device_snapshot(); update
all occurrences in the test (the chains currently calling get_device_snapshot()
repeatedly) to reference that single snapshot variable so the resolution uses a
consistent point-in-time Device.

In `@src/request.rs`:
- Around line 91-95: The public method generate_message_id in impl Request is
unnecessarily async because get_device_snapshot is now synchronous and there are
no await points; change generate_message_id to a synchronous fn returning String
(remove async) and update its signature and any internal .await usage, keeping
the same body calling self.persistence_manager.get_device_snapshot() and
self.get_request_utils().generate_message_id(...); then update all callers to
remove `.await` when calling Request::generate_message_id so call sites compile
cleanly.

---

Outside diff comments:
In `@src/features/events.rs`:
- Around line 133-141: The function resolve_responder_jid no longer needs to be
async because it does not await anything; change its signature to remove async
(e.g., fn resolve_responder_jid(&self, event_creator_jid: &Jid, own_pn: &Jid) ->
Jid) and keep the same body (calling self.client.get_lid()). Then update all
call sites that currently await this method to call it synchronously (remove
.await and handle the returned Jid directly); also update any trait signatures
or impls if they declared the method as async so the types remain consistent.

In `@src/message/tests.rs`:
- Around line 1753-1765: Extract the repeated pm.modify_device block into a
single async test helper (e.g., seed_test_device_identity or
setup_test_device_identity) that takes &pm (or &mut PM test handle) and performs
the device.pn and device.lid assignments currently done inside pm.modify_device;
replace each duplicated inline pm.modify_device({...}).await with a call to that
helper from the four test sites (the occurrences around lines 1753, 2452, 2550,
2644) so tests call await seed_test_device_identity(&pm). Ensure the helper is
async and lives in the same test module (or a common tests::helpers mod) so it
can be reused by all tests.
🪄 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: 33cff748-7b2a-467a-afc7-670ecd56a162

📥 Commits

Reviewing files that changed from the base of the PR and between 89f5487 and 23ef08c.

📒 Files selected for processing (52)
  • AGENTS.md
  • agent_docs/feature_implementation.md
  • src/bot.rs
  • src/client/accessors.rs
  • src/client/app_state.rs
  • src/client/device_registry.rs
  • src/client/iq_ops.rs
  • src/client/lifecycle.rs
  • src/client/messaging.rs
  • src/client/node_io.rs
  • src/client/sender_keys.rs
  • src/client/sessions.rs
  • src/features/contacts.rs
  • src/features/events.rs
  • src/features/media_reupload.rs
  • src/features/polls.rs
  • src/features/presence.rs
  • src/features/signal.rs
  • src/handlers/call.rs
  • src/handlers/notification/device.rs
  • src/handshake.rs
  • src/history_sync.rs
  • src/message/msg_secret.rs
  • src/message/receive.rs
  • src/message/special.rs
  • src/message/tests.rs
  • src/pair.rs
  • src/pair_code.rs
  • src/pdo.rs
  • src/prekeys.rs
  • src/receipt.rs
  • src/request.rs
  • src/retry.rs
  • src/send.rs
  • src/store/persistence_manager.rs
  • src/usync.rs
  • src/version.rs
  • tests/e2e/src/lib.rs
  • tests/e2e/tests/app_state.rs
  • tests/e2e/tests/chat_actions.rs
  • tests/e2e/tests/community.rs
  • tests/e2e/tests/digest_key.rs
  • tests/e2e/tests/groups.rs
  • tests/e2e/tests/lid_sessions.rs
  • tests/e2e/tests/media.rs
  • tests/e2e/tests/memory_soak.rs
  • tests/e2e/tests/prekey_sessions.rs
  • tests/e2e/tests/privacy_tokens.rs
  • tests/e2e/tests/profile.rs
  • tests/e2e/tests/profile_picture.rs
  • tests/e2e/tests/session_reuse.rs
  • tests/handshake_integration.rs
💤 Files with no reviewable changes (6)
  • tests/e2e/tests/community.rs
  • tests/e2e/tests/prekey_sessions.rs
  • tests/e2e/tests/profile_picture.rs
  • tests/e2e/tests/groups.rs
  • tests/e2e/tests/chat_actions.rs
  • tests/e2e/tests/media.rs

Comment thread src/message/tests.rs Outdated
Comment thread src/request.rs Outdated
…test chain

Review follow-ups: generate_message_id lost its only await point with the
sync snapshot, so drop the async (call sites updated). The test JID
fallback chains re-read the snapshot mid-chain — besides defeating the
point-in-time contract, .or(...) evaluated the second snapshot + clone
eagerly; they now take one snapshot and borrow.
@jlucaso1
jlucaso1 merged commit 2b380e8 into main Jun 9, 2026
19 checks passed
@jlucaso1
jlucaso1 deleted the perf/arc-device-snapshot branch June 9, 2026 20:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants