From 3c13bf083eb71d903bfe1be7a95422538815fbb9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 20 Mar 2025 14:19:36 +0100 Subject: [PATCH] refactor: Shrink `QueryRevisions` by 3 usize by boxing `IdentityMap` Not all queries actually create tracked structs and so this may be empty in those cases --- src/active_query.rs | 5 ++++- src/function/diff_outputs.rs | 18 +++++++++++------- src/function/execute.rs | 14 +++++++++++--- src/function/memo.rs | 2 +- src/zalsa_local.rs | 6 +++++- 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/active_query.rs b/src/active_query.rs index a2d5b08cf..c96747bed 100644 --- a/src/active_query.rs +++ b/src/active_query.rs @@ -173,7 +173,10 @@ impl ActiveQuery { .is_empty() .not() .then(|| Box::new(mem::take(accumulated))); - let tracked_struct_ids = mem::take(tracked_struct_ids); + let tracked_struct_ids = tracked_struct_ids + .is_empty() + .not() + .then(|| Box::new(mem::take(tracked_struct_ids))); let accumulated_inputs = AtomicInputAccumulatedValues::new(accumulated_inputs); let cycle_heads = mem::take(cycle_heads); QueryRevisions { diff --git a/src/function/diff_outputs.rs b/src/function/diff_outputs.rs index 6608bd3d4..924a5ab1c 100644 --- a/src/function/diff_outputs.rs +++ b/src/function/diff_outputs.rs @@ -27,19 +27,23 @@ where ) { // Iterate over the outputs of the `old_memo` and put them into a hashset let mut old_outputs: FxHashSet<_> = old_memo.revisions.origin.outputs().collect(); - // Iterate over the outputs of the current query // and remove elements from `old_outputs` when we find them for new_output in revisions.origin.outputs() { old_outputs.remove(&new_output); } - if !old_outputs.is_empty() { - // Remove the outputs that are no longer present in the current revision - // to prevent that the next revision is seeded with a id mapping that no longer exists. - revisions.tracked_struct_ids.retain(|&k, &mut value| { - !old_outputs.contains(&DatabaseKeyIndex::new(k.ingredient_index(), value)) - }); + if let Some(tracked_struct_ids) = &mut revisions.tracked_struct_ids { + if !old_outputs.is_empty() { + // Remove the outputs that are no longer present in the current revision + // to prevent that the next revision is seeded with a id mapping that no longer exists. + tracked_struct_ids.retain(|&k, &mut value| { + !old_outputs.contains(&DatabaseKeyIndex::new(k.ingredient_index(), value)) + }); + } + if tracked_struct_ids.is_empty() { + revisions.tracked_struct_ids = None; + } } for old_output in old_outputs { diff --git a/src/function/execute.rs b/src/function/execute.rs index c2907fbd4..0a49557fb 100644 --- a/src/function/execute.rs +++ b/src/function/execute.rs @@ -1,7 +1,7 @@ use crate::{ cycle::{CycleRecoveryStrategy, MAX_ITERATIONS}, zalsa::ZalsaDatabase, - zalsa_local::ActiveQueryGuard, + zalsa_local::{ActiveQueryGuard, QueryRevisions}, Database, Event, EventKind, }; @@ -52,8 +52,16 @@ where loop { // If we already executed this query once, then use the tracked-struct ids from the // previous execution as the starting point for the new one. - if let Some(old_memo) = opt_old_memo { - active_query.seed_tracked_struct_ids(&old_memo.revisions.tracked_struct_ids); + if let Some(Memo { + revisions: + QueryRevisions { + tracked_struct_ids: Some(tracked_struct_ids), + .. + }, + .. + }) = opt_old_memo + { + active_query.seed_tracked_struct_ids(tracked_struct_ids); } // Query was not previously executed, or value is potentially diff --git a/src/function/memo.rs b/src/function/memo.rs index 194c8721a..e86e016ba 100644 --- a/src/function/memo.rs +++ b/src/function/memo.rs @@ -142,7 +142,7 @@ pub(super) struct Memo { // Memo's are stored a lot, make sure their size is doesn't randomly increase. // #[cfg(test)] const _: [(); std::mem::size_of::>()] = - [(); std::mem::size_of::<[usize; 13]>()]; + [(); std::mem::size_of::<[usize; 10]>()]; impl Memo { pub(super) fn new(value: Option, revision_now: Revision, revisions: QueryRevisions) -> Self { diff --git a/src/zalsa_local.rs b/src/zalsa_local.rs index 46d9c2a6b..7c47c7fce 100644 --- a/src/zalsa_local.rs +++ b/src/zalsa_local.rs @@ -310,7 +310,11 @@ pub(crate) struct QueryRevisions { /// previous revision. To handle this, `diff_outputs` compares /// the structs from the old/new revision and retains /// only entries that appeared in the new revision. - pub(super) tracked_struct_ids: IdentityMap, + /// + /// Since not all queries produce a tracked struct, wrapping + /// `IdentityMap` in an `Option>` reduces the size of + /// `QueryRevisions` by 3 words (24 bytes on a 64-bit platform). + pub(super) tracked_struct_ids: Option>, pub(super) accumulated: Option>,