From eab707f3fe06dbb152d50ba51f431bf24dc967a4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 9 Jun 2026 20:11:21 +0000 Subject: [PATCH] perf(signal-cache): share cached sessions via Arc, peek without deep clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SessionEntry stored Box, so peek_session deep-cloned the record (KBs with archived states + skipped message keys) on every call — it runs on the retry-receipt and LID-migration check paths. Entries are now Arc, matching the sender-key cache's existing pattern: - peek_session returns Option> — a refcount bump on cache hit, and the backend-miss path no longer clones to populate the cache either. - get_session (checkout) unwraps via Arc::try_unwrap: unique in steady state (a move, exactly like the old Box), cloning only if a peek's short-lived Arc is still alive. - flush serializes through the Arc unchanged. Callers (retry.rs, message tests) only read through the record, so the signature change is source-compatible at every site. --- wacore/src/store/signal_cache.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/wacore/src/store/signal_cache.rs b/wacore/src/store/signal_cache.rs index e1e3b6388..36dc79175 100644 --- a/wacore/src/store/signal_cache.rs +++ b/wacore/src/store/signal_cache.rs @@ -91,7 +91,9 @@ pub struct SignalStoreCache { /// Cache entry tracking whether a session is present, absent, or checked out /// by an encrypt/decrypt operation. enum SessionEntry { - Present(Box), + // `Arc` so `peek_session` (retry / LID-migration checks) bumps a refcount + // instead of deep-cloning the record (KBs with archived states). + Present(Arc), Absent, /// Taken by load_session; has_session treats as present, flush/eviction skip. CheckedOut, @@ -124,7 +126,7 @@ impl SessionStoreState { fn put(&mut self, address: &str, record: SessionRecord) { let addr = self.key_for(address); self.cache - .insert(addr.clone(), SessionEntry::Present(Box::new(record))); + .insert(addr.clone(), SessionEntry::Present(Arc::new(record))); self.dirty.insert(addr.clone()); self.deleted.remove(&addr); } @@ -349,7 +351,11 @@ impl SignalStoreCache { else { unreachable!() }; - return Ok(Some(*record)); + // Unique unless a peek's Arc is still alive (short-lived + // inspection paths), so this is a move, not a clone. + return Ok(Some( + Arc::try_unwrap(record).unwrap_or_else(|arc| (*arc).clone()), + )); } return Ok(None); } @@ -386,13 +392,13 @@ impl SignalStoreCache { &self, address: &ProtocolAddress, backend: &dyn SignalStore, - ) -> Result> { + ) -> Result>> { let key = address.as_str(); { let state = self.sessions.lock().await; if let Some(entry) = state.cache.get(key) { return match entry { - SessionEntry::Present(record) => Ok(Some((**record).clone())), + SessionEntry::Present(record) => Ok(Some(record.clone())), _ => Ok(None), }; } @@ -402,12 +408,11 @@ impl SignalStoreCache { let mut state = self.sessions.lock().await; match backend_result { Some(bytes) => { - let record = SessionRecord::deserialize(&bytes)?; + let record = Arc::new(SessionRecord::deserialize(&bytes)?); if !state.cache.contains_key(key) { - state.cache.insert( - Arc::from(key), - SessionEntry::Present(Box::new(record.clone())), - ); + state + .cache + .insert(Arc::from(key), SessionEntry::Present(record.clone())); state.evict_if_needed(self.max_entries); } Ok(Some(record))