From cc190816fef2604f3dfd9c7e6a175dcd0ce01216 Mon Sep 17 00:00:00 2001 From: Riz Ashraf Date: Sat, 26 Sep 2026 08:15:58 +0100 Subject: [PATCH] perf: remove redundant MemoryState::deduplicate and resolve lock contention during index rebuild --- server/src/handlers/graph.rs | 3 ++- server/src/state.rs | 45 ++++++++++++++---------------------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/server/src/handlers/graph.rs b/server/src/handlers/graph.rs index 70ddd0c..fc593d6 100644 --- a/server/src/handlers/graph.rs +++ b/server/src/handlers/graph.rs @@ -534,7 +534,8 @@ impl McpTool for MergeEntitiesHandler { if let Some(src) = master.entities.remove(&req.source_entity) { if let Some(tgt) = master.entities.get_mut(&req.target_entity) { tgt.observations.extend(src.observations); - MemoryState::deduplicate(&mut tgt.observations); + tgt.observations.sort(); + tgt.observations.dedup(); } else { let mut new_tgt = src.clone(); new_tgt.name = req.target_entity.clone(); diff --git a/server/src/state.rs b/server/src/state.rs index c80fc5c..66ad592 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -84,10 +84,6 @@ impl MemoryState { } } - pub fn deduplicate(input: &mut Vec) { - let mut keys = std::collections::HashSet::new(); - input.retain(|entry| keys.insert(entry.clone())); - } pub fn broadcast_activity(&self, message: &str) { let time = std::time::SystemTime::now() @@ -129,33 +125,26 @@ impl MemoryState { pub async fn rebuild_index(self: &Arc) { if let Ok(new_idx) = MemoryIndex::new(&self.base_dir) { - let state = Arc::clone(self); let idx = new_idx.clone(); + let entities: Vec<_> = self.graph.read_with(|g| g.entities.values().cloned().collect()); + let tasks = self.tasks.read_with(|t| t.clone()); + let snippets = self.snippets.read_with(|s| s.clone()); + let adrs = self.adrs.read_with(|a| a.clone()); + tokio::task::spawn_blocking(move || { - state.graph.read_with(|g| { - for e in g.entities.values() { - idx.add_entity_sync(e); - } - }); - - state.tasks.read_with(|t| { - for task in t { - idx.add_task_sync(task); - } - }); - - state.snippets.read_with(|s| { - for snippet in s { - idx.add_snippet_sync(snippet); - } - }); - - state.adrs.read_with(|a| { - for adr in a { - idx.add_adr_sync(adr); - } - }); + for e in entities { + idx.add_entity_sync(&e); + } + for task in tasks { + idx.add_task_sync(&task); + } + for snippet in snippets { + idx.add_snippet_sync(&snippet); + } + for adr in adrs { + idx.add_adr_sync(&adr); + } }) .await .unwrap_or_else(|e| {