From 4c5a7cda088457d7b823a82d22d87d52d7eabf48 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Thu, 2 Oct 2025 12:24:53 +0300 Subject: [PATCH] core/vdbe: Avoid cloning Arc on every VDBE step The VDBE step() function was taking Arc by value, causing it to be cloned on every single step of query execution. This resulted in thousands of atomic reference count increments/decrements per query, showing up as a major hotspot in profiling. Changed step() and related functions to take Option<&Arc> instead, passing a reference rather than cloning the Arc. This eliminates the unnecessary atomic operations while maintaining the same semantics. --- core/lib.rs | 6 +++--- core/vdbe/mod.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/lib.rs b/core/lib.rs index 034c01d08..55370df4c 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -2472,7 +2472,7 @@ impl Statement { let mut res = if !self.accesses_db { self.program.step( &mut self.state, - self.mv_store.clone(), + self.mv_store.as_ref(), self.pager.clone(), self.query_mode, ) @@ -2480,7 +2480,7 @@ impl Statement { const MAX_SCHEMA_RETRY: usize = 50; let mut res = self.program.step( &mut self.state, - self.mv_store.clone(), + self.mv_store.as_ref(), self.pager.clone(), self.query_mode, ); @@ -2493,7 +2493,7 @@ impl Statement { self.reprepare()?; res = self.program.step( &mut self.state, - self.mv_store.clone(), + self.mv_store.as_ref(), self.pager.clone(), self.query_mode, ); diff --git a/core/vdbe/mod.rs b/core/vdbe/mod.rs index fa0521b2a..f688e09a3 100644 --- a/core/vdbe/mod.rs +++ b/core/vdbe/mod.rs @@ -512,7 +512,7 @@ impl Program { pub fn step( &self, state: &mut ProgramState, - mv_store: Option>, + mv_store: Option<&Arc>, pager: Arc, query_mode: QueryMode, ) -> Result { @@ -526,7 +526,7 @@ impl Program { fn explain_step( &self, state: &mut ProgramState, - _mv_store: Option>, + _mv_store: Option<&Arc>, pager: Arc, ) -> Result { debug_assert!(state.column_count() == EXPLAIN_COLUMNS.len()); @@ -580,7 +580,7 @@ impl Program { fn explain_query_plan_step( &self, state: &mut ProgramState, - _mv_store: Option>, + _mv_store: Option<&Arc>, pager: Arc, ) -> Result { debug_assert!(state.column_count() == EXPLAIN_QUERY_PLAN_COLUMNS.len()); @@ -628,7 +628,7 @@ impl Program { fn normal_step( &self, state: &mut ProgramState, - mv_store: Option>, + mv_store: Option<&Arc>, pager: Arc, ) -> Result { let enable_tracing = tracing::enabled!(tracing::Level::TRACE); @@ -650,7 +650,7 @@ impl Program { } if let Some(err) = io.get_error() { let err = err.into(); - handle_program_error(&pager, &self.connection, &err, mv_store.as_ref())?; + handle_program_error(&pager, &self.connection, &err, mv_store)?; return Err(err); } state.io_completions = None; @@ -665,7 +665,7 @@ impl Program { // Always increment VM steps for every loop iteration state.metrics.vm_steps = state.metrics.vm_steps.saturating_add(1); - match insn_function(self, state, insn, &pager, mv_store.as_ref()) { + match insn_function(self, state, insn, &pager, mv_store) { Ok(InsnFunctionStepResult::Step) => { // Instruction completed, moving to next state.metrics.insn_executed = state.metrics.insn_executed.saturating_add(1); @@ -694,7 +694,7 @@ impl Program { return Ok(StepResult::Busy); } Err(err) => { - handle_program_error(&pager, &self.connection, &err, mv_store.as_ref())?; + handle_program_error(&pager, &self.connection, &err, mv_store)?; return Err(err); } }