From 1d5e4bd00d9c84fc8e407fb042224b11c12ed6b8 Mon Sep 17 00:00:00 2001 From: Riz Ashraf Date: Mon, 21 Sep 2026 16:25:57 +0100 Subject: [PATCH] perf(server): eliminate implicit full-collection clones by removing Store::read() in favor of read_with() --- payload.json | 1 + server/src/main.rs | 8 ++++---- server/src/search.rs | 12 ++++++++---- server/src/state.rs | 12 ++++++------ server/src/store.rs | 13 ++++--------- temp.lua | 27 +++++++++++++++++++++++++++ temp_execute.lua | 28 ++++++++++++++++++++++++++++ temp_read.lua | 2 ++ 8 files changed, 80 insertions(+), 23 deletions(-) create mode 100644 payload.json create mode 100644 temp.lua create mode 100644 temp_execute.lua create mode 100644 temp_read.lua diff --git a/payload.json b/payload.json new file mode 100644 index 0000000..72d0401 --- /dev/null +++ b/payload.json @@ -0,0 +1 @@ +{"code": "local buf = vim.fn.bufnr('server/src/search.rs')\nif buf == -1 then\n vim.cmd('e server/src/search.rs')\n buf = vim.api.nvim_get_current_buf()\nend\n\nvim.api.nvim_buf_set_lines(buf, 216, 222, false, {\n ' &self,',\n ' entities: &[Entity],',\n ' tasks: &[Task],',\n ' snippets: &[Snippet],',\n ' adrs: &[Adr],'\n})\n\n-- We need to change the loop variables inside the task from values to clones if they are passed as slices\n-- Actually we can just clone the slice data before moving it into spawn_blocking\nvim.api.nvim_buf_set_lines(buf, 222, 223, false, {\n ' ) -> tokio::task::JoinHandle> {',\n ' let entities = entities.to_vec();',\n ' let tasks = tasks.to_vec();',\n ' let snippets = snippets.to_vec();',\n ' let adrs = adrs.to_vec();'\n})\n\nvim.cmd('write')\nrequire('notify')('Updated search index_batch signature', 'info', { title = 'Antigravity' })\nreturn 'ok'\n"} \ No newline at end of file diff --git a/server/src/main.rs b/server/src/main.rs index 2912d82..7b46295 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -307,8 +307,8 @@ async fn run_server(state: Arc) -> Result<(), Box) -> Result<(), Box, - tasks: Vec, - snippets: Vec, - adrs: Vec, + entities: &[Entity], + tasks: &[Task], + snippets: &[Snippet], + adrs: &[Adr], ) -> tokio::task::JoinHandle> { let writer = Arc::clone(&self.writer); let id_field = self.id_field; + let entities = entities.to_vec(); + let tasks = tasks.to_vec(); + let snippets = snippets.to_vec(); let title_field = self.title_field; + let adrs = adrs.to_vec(); let body_field = self.body_field; let type_field = self.type_field; let namespace_field = self.namespace_field; diff --git a/server/src/state.rs b/server/src/state.rs index aae8dfd..a0b8c6e 100644 --- a/server/src/state.rs +++ b/server/src/state.rs @@ -46,7 +46,7 @@ impl MemoryState { } pub fn get_full_graph(&self) -> KnowledgeGraph { - self.graph.read() + self.graph.read_with(|g| g.clone()) } pub fn read_graph(&self, f: F) -> R @@ -62,12 +62,12 @@ impl MemoryState { pub async fn rebuild_index(&self) { if let Ok(new_idx) = MemoryIndex::new(&self.base_dir) { - let entities = self.graph.read().entities.into_values().collect(); - let tasks = self.tasks.read(); - let snippets = self.snippets.read(); - let adrs = self.adrs.read(); + 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()); - let handle = new_idx.index_batch(entities, tasks, snippets, adrs); + let handle = new_idx.index_batch(&entities, &tasks, &snippets, &adrs); let _ = handle.await; let _ = new_idx.commit().await; diff --git a/server/src/store.rs b/server/src/store.rs index c42aa59..e755777 100644 --- a/server/src/store.rs +++ b/server/src/store.rs @@ -59,11 +59,6 @@ impl T::default() } - pub fn read(&self) -> T { - let lock = self.cache.read().unwrap_or_else(|e| e.into_inner()); - lock.clone() - } - pub fn read_with(&self, f: F) -> R where F: FnOnce(&T) -> R, @@ -106,7 +101,7 @@ mod tests { let db = Arc::new(db); let store = Store::::new("test_key", db.clone()); - assert_eq!(store.read(), TestData::default()); + assert_eq!(store.read_with(|s| s.clone()), TestData::default()); store.modify(|data| { data.name = "Hello".to_string(); @@ -117,7 +112,7 @@ mod tests { tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; assert_eq!( - store.read(), + store.read_with(|s| s.clone()), TestData { name: "Hello".to_string(), value: 42 @@ -127,7 +122,7 @@ mod tests { // Load again to verify persistence let store2 = Store::::new("test_key", db.clone()); assert_eq!( - store2.read(), + store2.read_with(|s| s.clone()), TestData { name: "Hello".to_string(), value: 42 @@ -166,6 +161,6 @@ mod tests { // Wait for all blocking writes to flush tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; - assert_eq!(store.read().value, 50); + assert_eq!(store.read_with(|s| s.value), 50); } } diff --git a/temp.lua b/temp.lua new file mode 100644 index 0000000..1c0cdb9 --- /dev/null +++ b/temp.lua @@ -0,0 +1,27 @@ +local buf = vim.fn.bufnr('server/src/search.rs') +if buf == -1 then + vim.cmd('e server/src/search.rs') + buf = vim.api.nvim_get_current_buf() +end + +vim.api.nvim_buf_set_lines(buf, 216, 222, false, { + ' &self,', + ' entities: &[Entity],', + ' tasks: &[Task],', + ' snippets: &[Snippet],', + ' adrs: &[Adr],' +}) + +-- We need to change the loop variables inside the task from values to clones if they are passed as slices +-- Actually we can just clone the slice data before moving it into spawn_blocking +vim.api.nvim_buf_set_lines(buf, 222, 223, false, { + ' ) -> tokio::task::JoinHandle> {', + ' let entities = entities.to_vec();', + ' let tasks = tasks.to_vec();', + ' let snippets = snippets.to_vec();', + ' let adrs = adrs.to_vec();' +}) + +vim.cmd('write') +require('notify')('Updated search index_batch signature', 'info', { title = 'Antigravity' }) +return 'ok' diff --git a/temp_execute.lua b/temp_execute.lua new file mode 100644 index 0000000..d428b35 --- /dev/null +++ b/temp_execute.lua @@ -0,0 +1,28 @@ +local buf = vim.fn.bufnr('server/src/search.rs') +if buf == -1 then + vim.cmd('e server/src/search.rs') + buf = vim.api.nvim_get_current_buf() +end + +vim.api.nvim_buf_set_lines(buf, 216, 222, false, { + ' &self,', + ' entities: &[Entity],', + ' tasks: &[Task],', + ' snippets: &[Snippet],', + ' adrs: &[Adr],' +}) + +-- We need to change the loop variables inside the task from values to clones if they are passed as slices +-- Actually we can just clone the slice data before moving it into spawn_blocking +vim.api.nvim_buf_set_lines(buf, 222, 223, false, { + ' ) -> tokio::task::JoinHandle> {', + ' let entities = entities.to_vec();', + ' let tasks = tasks.to_vec();', + ' let snippets = snippets.to_vec();', + ' let adrs = adrs.to_vec();' +}) + +vim.cmd('write') +require('notify')('Updated search index_batch signature', 'info', { title = 'Antigravity' }) +return 'ok' + diff --git a/temp_read.lua b/temp_read.lua new file mode 100644 index 0000000..d3f0030 --- /dev/null +++ b/temp_read.lua @@ -0,0 +1,2 @@ +local code = vim.fn.readfile('temp.lua') +return table.concat(code, '\n')