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:
parent
3cc39590a7
commit
89d6a853f5
5 changed files with 152 additions and 106 deletions
|
|
@ -116,6 +116,13 @@ struct StatsDto {
|
|||
follow_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BadgeCountsDto {
|
||||
new_feed: usize,
|
||||
new_engagement: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct RedundancyDto {
|
||||
|
|
@ -666,11 +673,16 @@ async fn follow_node(state: State<'_, AppState>, node_id_hex: String) -> Result<
|
|||
let node = state.inner();
|
||||
let nid = parse_node_id(&node_id_hex)?;
|
||||
node.follow(&nid).await.map_err(|e| e.to_string())?;
|
||||
// Auto-sync: pull posts from the followed peer in the background
|
||||
// Auto-sync: pull posts from the followed peer in the background (15s timeout)
|
||||
let node_clone = state.inner().clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = node_clone.sync_with(nid).await {
|
||||
tracing::debug!(error = %e, "Auto-sync after follow failed (peer may not be connected)");
|
||||
match tokio::time::timeout(
|
||||
std::time::Duration::from_secs(15),
|
||||
node_clone.sync_with(nid),
|
||||
).await {
|
||||
Ok(Ok(())) => {}
|
||||
Ok(Err(e)) => tracing::debug!(error = %e, "Auto-sync after follow failed"),
|
||||
Err(_) => tracing::debug!("Auto-sync after follow timed out (15s)"),
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
|
|
@ -1399,6 +1411,54 @@ async fn get_seen_engagement(
|
|||
}))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_badge_counts(
|
||||
state: State<'_, AppState>,
|
||||
last_feed_view_ms: u64,
|
||||
) -> Result<BadgeCountsDto, String> {
|
||||
let node = state.inner();
|
||||
let storage = node.storage.lock().await;
|
||||
|
||||
// Feed badge: count non-DM posts from others newer than last_feed_view_ms
|
||||
let feed_posts = storage.get_feed().map_err(|e| e.to_string())?;
|
||||
let new_feed = feed_posts.iter()
|
||||
.filter(|(id, p, _vis)| {
|
||||
p.author != node.node_id
|
||||
&& p.timestamp_ms > last_feed_view_ms
|
||||
&& !matches!(
|
||||
storage.get_post_intent(id).ok().flatten(),
|
||||
Some(VisibilityIntent::Direct(_))
|
||||
)
|
||||
})
|
||||
.count();
|
||||
|
||||
// My Posts badge: count own non-DM posts with unseen engagement
|
||||
let all_posts = storage.list_posts_reverse_chron().map_err(|e| e.to_string())?;
|
||||
let mut new_engagement = 0usize;
|
||||
for (id, post, _vis) in &all_posts {
|
||||
if post.author != node.node_id { continue; }
|
||||
// Skip DMs
|
||||
if matches!(
|
||||
storage.get_post_intent(id).ok().flatten(),
|
||||
Some(VisibilityIntent::Direct(_))
|
||||
) { continue; }
|
||||
let total_reacts: u64 = storage.get_reaction_counts(id, &node.node_id)
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.map(|(_, count, _)| *count)
|
||||
.sum();
|
||||
let total_comments = storage.get_comment_count(id).unwrap_or(0);
|
||||
if total_reacts > 0 || total_comments > 0 {
|
||||
let (seen_r, seen_c) = storage.get_seen_engagement(id).unwrap_or((0, 0));
|
||||
if total_reacts > seen_r as u64 || total_comments > seen_c as u64 {
|
||||
new_engagement += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(BadgeCountsDto { new_feed, new_engagement })
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
async fn get_last_read_message(
|
||||
state: State<'_, AppState>,
|
||||
|
|
@ -2057,6 +2117,7 @@ pub fn run() {
|
|||
mark_post_seen,
|
||||
mark_conversation_read,
|
||||
get_seen_engagement,
|
||||
get_badge_counts,
|
||||
get_last_read_message,
|
||||
generate_share_link,
|
||||
])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue