Skip to content

Commit 9654fd3

Browse files
committed
avoid allocating intermediary serialized dependency edges
1 parent dd8c7b4 commit 9654fd3

File tree

8 files changed

+75
-26
lines changed

8 files changed

+75
-26
lines changed

src/accumulator.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use std::panic::UnwindSafe;
88
use accumulated::{Accumulated, AnyAccumulated};
99

1010
use crate::function::{VerifyCycleHeads, VerifyResult};
11+
use crate::hash::FxIndexSet;
1112
use crate::ingredient::{Ingredient, Jar};
1213
use crate::plumbing::ZalsaLocal;
1314
use crate::sync::Arc;
@@ -111,7 +112,12 @@ impl<A: Accumulator> Ingredient for IngredientImpl<A> {
111112
panic!("nothing should ever depend on an accumulator directly")
112113
}
113114

114-
fn minimum_serialized_edges(&self, _zalsa: &Zalsa, _edge: QueryEdge) -> Vec<QueryEdge> {
115+
fn collect_minimum_serialized_edges(
116+
&self,
117+
_zalsa: &Zalsa,
118+
_edge: QueryEdge,
119+
_serialized_edges: &mut FxIndexSet<QueryEdge>,
120+
) {
115121
panic!("nothing should ever depend on an accumulator directly")
116122
}
117123

src/function.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::cycle::{
1313
use crate::database::RawDatabase;
1414
use crate::function::delete::DeletedEntries;
1515
use crate::function::sync::{ClaimResult, SyncTable};
16+
use crate::hash::FxIndexSet;
1617
use crate::ingredient::{Ingredient, WaitForResult};
1718
use crate::key::DatabaseKeyIndex;
1819
use crate::plumbing::{self, MemoIngredientMap};
@@ -288,26 +289,27 @@ where
288289
self.maybe_changed_after(db, input, revision, cycle_heads)
289290
}
290291

291-
fn minimum_serialized_edges(&self, zalsa: &Zalsa, edge: QueryEdge) -> Vec<QueryEdge> {
292+
fn collect_minimum_serialized_edges(
293+
&self,
294+
zalsa: &Zalsa,
295+
edge: QueryEdge,
296+
serialized_edges: &mut FxIndexSet<QueryEdge>,
297+
) {
292298
let input = edge.key().key_index();
293299

294300
let Some(memo) =
295301
self.get_memo_from_table_for(zalsa, input, self.memo_ingredient_index(zalsa, input))
296302
else {
297-
return Vec::new();
303+
return;
298304
};
299305

300306
let origin = memo.revisions.origin.as_ref();
301307

302308
// Collect the minimum dependency tree.
303-
origin
304-
.edges()
305-
.iter()
306-
.flat_map(|&edge| {
307-
let dependency = zalsa.lookup_ingredient(edge.key().ingredient_index());
308-
dependency.minimum_serialized_edges(zalsa, edge)
309-
})
310-
.collect()
309+
for edge in origin.edges() {
310+
let dependency = zalsa.lookup_ingredient(edge.key().ingredient_index());
311+
dependency.collect_minimum_serialized_edges(zalsa, *edge, serialized_edges)
312+
}
311313
}
312314

313315
/// Returns `final` only if the memo has the `verified_final` flag set and the cycle recovery strategy is not `FallbackImmediate`.
@@ -588,7 +590,7 @@ mod persistence {
588590
flattened_edges.insert(edge);
589591
} else {
590592
// Otherwise, serialize the minimum edges necessary to cover the dependency.
591-
flattened_edges.extend(dependency.minimum_serialized_edges(zalsa, edge));
593+
dependency.collect_minimum_serialized_edges(zalsa, edge, &mut flattened_edges);
592594
}
593595
}
594596

src/ingredient.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::cycle::{
66
};
77
use crate::database::RawDatabase;
88
use crate::function::{VerifyCycleHeads, VerifyResult};
9+
use crate::hash::FxIndexSet;
910
use crate::runtime::Running;
1011
use crate::sync::Arc;
1112
use crate::table::memo::MemoTableTypes;
@@ -55,14 +56,19 @@ pub trait Ingredient: Any + std::fmt::Debug + Send + Sync {
5556
cycle_heads: &mut VerifyCycleHeads,
5657
) -> VerifyResult;
5758

58-
/// Returns the minimum edges necessary to serialize a given dependency edge on this ingredient,
59+
/// Collects the minimum edges necessary to serialize a given dependency edge on this ingredient,
5960
/// without necessarily serializing the dependency edge itself.
6061
///
6162
/// This generally only returns any transitive input dependencies, i.e. the leaves of the dependency
6263
/// tree, as most other fine-grained dependencies are covered by the inputs.
6364
///
6465
/// Note that any ingredients returned by this function must be persistable.
65-
fn minimum_serialized_edges(&self, zalsa: &Zalsa, edge: QueryEdge) -> Vec<QueryEdge>;
66+
fn collect_minimum_serialized_edges(
67+
&self,
68+
zalsa: &Zalsa,
69+
edge: QueryEdge,
70+
serialized_edges: &mut FxIndexSet<QueryEdge>,
71+
);
6672

6773
/// Returns information about the current provisional status of `input`.
6874
///

src/input.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod singleton;
99
use input_field::FieldIngredientImpl;
1010

1111
use crate::function::{VerifyCycleHeads, VerifyResult};
12+
use crate::hash::FxIndexSet;
1213
use crate::id::{AsId, FromId, FromIdWithDb};
1314
use crate::ingredient::Ingredient;
1415
use crate::input::singleton::{Singleton, SingletonChoice};
@@ -278,7 +279,12 @@ impl<C: Configuration> Ingredient for IngredientImpl<C> {
278279
panic!("nothing should ever depend on an input struct directly")
279280
}
280281

281-
fn minimum_serialized_edges(&self, _zalsa: &Zalsa, _edge: QueryEdge) -> Vec<QueryEdge> {
282+
fn collect_minimum_serialized_edges(
283+
&self,
284+
_zalsa: &Zalsa,
285+
_edge: QueryEdge,
286+
_serialized_edges: &mut FxIndexSet<QueryEdge>,
287+
) {
282288
panic!("nothing should ever depend on an input struct directly")
283289
}
284290

src/input/input_field.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::fmt;
22
use std::marker::PhantomData;
33

44
use crate::function::{VerifyCycleHeads, VerifyResult};
5+
use crate::hash::FxIndexSet;
56
use crate::ingredient::Ingredient;
67
use crate::input::{Configuration, IngredientImpl, Value};
78
use crate::sync::Arc;
@@ -62,14 +63,19 @@ where
6263
VerifyResult::changed_if(value.revisions[self.field_index] > revision)
6364
}
6465

65-
fn minimum_serialized_edges(&self, _zalsa: &Zalsa, edge: QueryEdge) -> Vec<QueryEdge> {
66+
fn collect_minimum_serialized_edges(
67+
&self,
68+
_zalsa: &Zalsa,
69+
edge: QueryEdge,
70+
serialized_edges: &mut FxIndexSet<QueryEdge>,
71+
) {
6672
assert!(
6773
C::PERSIST,
6874
"the inputs of a persistable tracked function must be persistable"
6975
);
7076

7177
// Input dependencies are the leaves of the minimum dependency tree.
72-
Vec::from([edge])
78+
serialized_edges.insert(edge);
7379
}
7480

7581
fn fmt_index(&self, index: crate::Id, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {

src/interned.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_hash::FxBuildHasher;
1212

1313
use crate::durability::Durability;
1414
use crate::function::{VerifyCycleHeads, VerifyResult};
15+
use crate::hash::FxIndexSet;
1516
use crate::id::{AsId, FromId};
1617
use crate::ingredient::Ingredient;
1718
use crate::plumbing::{self, Jar, ZalsaLocal};
@@ -897,18 +898,22 @@ where
897898
VerifyResult::unchanged()
898899
}
899900

900-
fn minimum_serialized_edges(&self, _zalsa: &Zalsa, edge: QueryEdge) -> Vec<QueryEdge> {
901+
fn collect_minimum_serialized_edges(
902+
&self,
903+
_zalsa: &Zalsa,
904+
edge: QueryEdge,
905+
serialized_edges: &mut FxIndexSet<QueryEdge>,
906+
) {
901907
if C::PERSIST {
902908
// If the interned struct is being persisted, it may be reachable through transitive queries.
903909
// Additionally, interned struct dependencies are impure in that garbage collection can
904910
// invalidate a dependency without a base input necessarily being updated. Thus, we must
905911
// preserve the transitive dependency on the interned struct.
906-
Vec::from([edge])
907-
} else {
908-
// The dependency is covered by the base inputs, as the interned struct itself is
909-
// not being persisted.
910-
Vec::new()
912+
serialized_edges.insert(edge);
911913
}
914+
915+
// Otherwise, the dependency is covered by the base inputs, as the interned struct itself is
916+
// not being persisted.
912917
}
913918

914919
fn debug_name(&self) -> &'static str {

src/tracked_struct.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use thin_vec::ThinVec;
1212
use tracked_field::FieldIngredientImpl;
1313

1414
use crate::function::{VerifyCycleHeads, VerifyResult};
15+
use crate::hash::FxIndexSet;
1516
use crate::id::{AsId, FromId};
1617
use crate::ingredient::{Ingredient, Jar};
1718
use crate::key::DatabaseKeyIndex;
@@ -943,7 +944,19 @@ where
943944
panic!("nothing should ever depend on a tracked struct directly")
944945
}
945946

946-
fn minimum_serialized_edges(&self, _zalsa: &Zalsa, _edge: QueryEdge) -> Vec<QueryEdge> {
947+
fn collect_minimum_serialized_edges(
948+
&self,
949+
_zalsa: &Zalsa,
950+
_edge: QueryEdge,
951+
_serialized_edges: &mut FxIndexSet<QueryEdge>,
952+
) {
953+
// Note that tracked structs are referenced by the identity map, but that
954+
// only matters if we are serializing the creating query, in which case
955+
// the dependency edge will be serialized directly.
956+
//
957+
// TODO: We could flatten the identity map here if the tracked struct is being
958+
// persisted, in order to more aggressively preserve the tracked struct IDs if
959+
// the transitive query is re-executed.
947960
panic!("nothing should ever depend on a tracked struct directly")
948961
}
949962

src/tracked_struct/tracked_field.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::marker::PhantomData;
22

33
use crate::function::{VerifyCycleHeads, VerifyResult};
4+
use crate::hash::FxIndexSet;
45
use crate::ingredient::Ingredient;
56
use crate::sync::Arc;
67
use crate::table::memo::MemoTableTypes;
@@ -68,10 +69,14 @@ where
6869
VerifyResult::changed_if(field_changed_at > revision)
6970
}
7071

71-
fn minimum_serialized_edges(&self, _zalsa: &Zalsa, _edge: QueryEdge) -> Vec<QueryEdge> {
72+
fn collect_minimum_serialized_edges(
73+
&self,
74+
_zalsa: &Zalsa,
75+
_edge: QueryEdge,
76+
_serialized_edges: &mut FxIndexSet<QueryEdge>,
77+
) {
7278
// Tracked structs do not have transitive dependencies, and their dependencies are covered by
7379
// the base inputs.
74-
Vec::new()
7580
}
7681

7782
fn fmt_index(&self, index: crate::Id, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {

0 commit comments

Comments
 (0)