From e18ddb1b507d4581151c2cd93311469e5979d0cb Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2026 04:59:39 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Pre-allocate=20and=20clone?= =?UTF-8?q?=20IndexMap=20in=20database=20query?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- .jules/bolt.md | 4 ++++ stdlib/src/database.rs | 23 ++++++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 9f33508c..51399205 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -59,3 +59,7 @@ ## 2026-09-28 - IndexMap allocation optimization **Learning:** Pre-allocating `IndexMap` with `with_capacity(len)` where the number of elements is known (e.g., in stdlib modules like `system`, `http`, and `url`) prevents unnecessary allocations and re-hashing during insertion, yielding a 10%-45% improvement in map construction performance depending on the size. **Action:** Always prefer `IndexMap::with_capacity(expected_len)` over `IndexMap::new()` when constructing maps with a known or highly predictable number of elements. + +## 2023-10-24 - Pre-allocate and clone IndexMap in database row iteration +**Learning:** When fetching rows from a database where each row's values are stored in an `IndexMap` keyed by the column name, constructing a new `IndexMap` for every row involves heavy performance penalties due to repeated string cloning (for the keys) and hashing operations. Creating a single "prototype" map with null values and cloning it for each row provides a fast memory copy that completely bypasses the hashing phase. However, `IndexMap` auto-deduplicates keys during insertion, so the mapping from database column index to `IndexMap` index must be carefully pre-computed to safely update values by index using `get_index_mut`. +**Action:** In loops over data with a fixed schema (like database rows or CSVs) where the target structure is an `IndexMap`, always pre-allocate a prototype map and clone it per iteration rather than constructing a new map and hashing keys for every single element. diff --git a/stdlib/src/database.rs b/stdlib/src/database.rs index 236e7777..51a9b5c5 100644 --- a/stdlib/src/database.rs +++ b/stdlib/src/database.rs @@ -135,6 +135,19 @@ fn std_database_query( ) })?; + // ⚡ Bolt Performance Optimization: + // Instead of constructing a new IndexMap for each row, cloning every column string, + // and re-hashing all keys, we create a prototype map once containing null values. + // For each row, we clone the prototype map (which uses a fast memory copy and avoids string cloning/hashing) + // and update the values by index. + // We map the database column indices to the deduplicated IndexMap indices. + let mut prototype_map = IndexMap::with_capacity(column_names.len()); + let mut col_idx_to_map_idx = Vec::with_capacity(column_names.len()); + for name in &column_names { + let (map_idx, _) = prototype_map.insert_full(name.clone(), RuntimeValue::Null); + col_idx_to_map_idx.push(map_idx); + } + let mut result_rows = Vec::new(); while let Some(row) = rows.next().map_err(|e| { @@ -144,8 +157,8 @@ fn std_database_query( None, ) })? { - let mut row_map = IndexMap::with_capacity(column_names.len()); - for (idx, name) in column_names.iter().enumerate() { + let mut row_map = prototype_map.clone(); + for (idx, &map_idx) in col_idx_to_map_idx.iter().enumerate() { let value = match row.get_ref(idx).map_err(|e| { RuntimeError::new( RuntimeErrorKind::InvalidOperation(format!("Database column get error: {}", e)), @@ -165,9 +178,9 @@ fn std_database_query( RuntimeValue::Str(s) } }; - // The clone here is strictly necessary because `IndexMap` requires an owned `String` - // key, and each row constructs a fresh map containing these keys. - row_map.insert(name.clone(), value); + if let Some((_, v)) = row_map.get_index_mut(map_idx) { + *v = value; + } } result_rows.push(RuntimeValue::Map { entries: Rc::new(RefCell::new(row_map)),