Fix storage lock contention: reduce lock holds across 6 hot paths

- get_blob_for_post: 3 sequential locks → 1 combined acquisition
- prefetch_blobs_from_peer: lock only for DB reads, blob checks outside lock
- fetch_engagement_from_peer: explicit lock release before next network I/O
- serve_post: 4 locks (2 redundant) → 2
- run_replication_check: 2 locks → 1 combined
- Badge cycle: N+2 IPC calls → 1 (new get_badge_counts command)
- Follow timeout: 15s cap on auto-sync-on-follow to prevent UI hang
- Notification clearing: clear system notifications on conversation read

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Scott Reimers 2026-03-21 13:02:30 -04:00
parent 3cc39590a7
commit 89d6a853f5
5 changed files with 152 additions and 106 deletions

View file

@ -1716,7 +1716,7 @@ impl ConnectionManager {
.get(peer_id)
.ok_or_else(|| anyhow::anyhow!("not connected to {}", hex::encode(peer_id)))?;
// Get post IDs and their current header timestamps
// Brief lock: gather post IDs and their current header timestamps
let post_headers: Vec<([u8; 32], u64)> = {
let storage = self.storage.lock().await;
let post_ids = storage.list_post_ids()?;
@ -1733,6 +1733,7 @@ impl ConnectionManager {
})
.collect()
};
// Lock RELEASED — all network I/O happens without the lock
let mut updated = 0;
// Request headers in batches to avoid opening too many streams
@ -1757,6 +1758,7 @@ impl ConnectionManager {
if response.updated {
if let Some(json) = &response.header_json {
if let Ok(header) = serde_json::from_str::<crate::types::BlobHeader>(json) {
// Brief re-lock for writes only
let storage = self.storage.lock().await;
// Store the full header JSON
let _ = storage.store_blob_header(
@ -1775,6 +1777,7 @@ impl ConnectionManager {
let _ = storage.store_comment(comment);
}
let _ = storage.set_comment_policy(&header.post_id, &header.policy);
drop(storage);
updated += 1;
}
}