Skip to content

Commit 027db45

Browse files
committed
Track revisions for tracked fields only
1 parent 181902f commit 027db45

File tree

4 files changed

+62
-36
lines changed

4 files changed

+62
-36
lines changed

components/salsa-macro-rules/src/setup_tracked_struct.rs

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ macro_rules! setup_tracked_struct {
5050
// Absolute indices of any untracked fields.
5151
absolute_untracked_indices: [$($absolute_untracked_index:tt),*],
5252

53-
// A set of "field options" for each field.
53+
// A set of "field options" for each tracked field.
5454
//
5555
// Each field option is a tuple `(maybe_clone, maybe_backdate)` where:
5656
//
@@ -59,16 +59,21 @@ macro_rules! setup_tracked_struct {
5959
//
6060
// These are used to drive conditional logic for each field via recursive macro invocation
6161
// (see e.g. @maybe_clone below).
62-
field_options: [$($field_option:tt),*],
63-
64-
// A set of "field options" for each tracked field.
6562
tracked_options: [$($tracked_option:tt),*],
6663

6764
// A set of "field options" for each untracked field.
65+
//
66+
// Each field option is a tuple `(maybe_clone, maybe_backdate)` where:
67+
//
68+
// * `maybe_clone` is either the identifier `clone` or `no_clone`
69+
// * `maybe_backdate` is either the identifier `backdate` or `no_backdate`
70+
//
71+
// These are used to drive conditional logic for each field via recursive macro invocation
72+
// (see e.g. @maybe_clone below).
6873
untracked_options: [$($untracked_option:tt),*],
6974

70-
// Number of fields.
71-
num_fields: $N:literal,
75+
// Number of tracked fields.
76+
num_tracked_fields: $N:literal,
7277

7378
// If true, generate a debug impl.
7479
generate_debug_impl: $generate_debug_impl:tt,
@@ -111,7 +116,7 @@ macro_rules! setup_tracked_struct {
111116
];
112117

113118
const TRACKED_FIELD_INDICES: &'static [usize] = &[
114-
$($absolute_tracked_index,)*
119+
$($relative_tracked_index,)*
115120
];
116121

117122
type Fields<$db_lt> = ($($field_ty,)*);
@@ -141,21 +146,33 @@ macro_rules! setup_tracked_struct {
141146
revisions: &mut Self::Revisions,
142147
old_fields: *mut Self::Fields<$db_lt>,
143148
new_fields: Self::Fields<$db_lt>,
144-
) {
149+
) -> bool {
145150
use $zalsa::UpdateFallback as _;
146151
unsafe {
147152
$(
148153
$crate::maybe_backdate!(
149-
$field_option,
150-
$field_ty,
151-
(*old_fields).$field_index,
152-
new_fields.$field_index,
153-
revisions[$field_index],
154+
$tracked_option,
155+
$tracked_ty,
156+
(*old_fields).$absolute_tracked_index,
157+
new_fields.$absolute_tracked_index,
158+
revisions[$relative_tracked_index],
154159
current_revision,
155160
$zalsa,
156161
);
157162
)*
158163
}
164+
165+
// If any untracked field has changed, return `true`, indicating that the tracked struct
166+
// itself should be considered changed.
167+
unsafe {
168+
$(
169+
$zalsa::UpdateDispatch::<$untracked_ty>::maybe_update(
170+
&mut (*old_fields).$absolute_untracked_index,
171+
new_fields.$absolute_untracked_index,
172+
)
173+
|
174+
)* false
175+
}
159176
}
160177
}
161178

@@ -236,7 +253,7 @@ macro_rules! setup_tracked_struct {
236253
$Db: ?Sized + $zalsa::Database,
237254
{
238255
let db = db.as_dyn_database();
239-
let fields = $Configuration::ingredient(db).tracked_field(db, self, $absolute_tracked_index, $relative_tracked_index);
256+
let fields = $Configuration::ingredient(db).tracked_field(db, self, $relative_tracked_index);
240257
$crate::maybe_clone!(
241258
$tracked_option,
242259
$tracked_ty,

components/salsa-macros/src/salsa_struct.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,10 @@ where
227227
Literal::usize_unsuffixed(self.fields.len())
228228
}
229229

230+
pub(crate) fn num_tracked_fields(&self) -> Literal {
231+
Literal::usize_unsuffixed(self.tracked_fields_iter().count())
232+
}
233+
230234
pub(crate) fn required_fields(&self) -> Vec<TokenStream> {
231235
self.fields
232236
.iter()

components/salsa-macros/src/tracked_struct.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,14 @@ impl Macro {
101101

102102
let absolute_untracked_indices = salsa_struct.untracked_field_indices();
103103

104-
let field_options = salsa_struct.field_options();
105104
let tracked_options = salsa_struct.tracked_options();
106105
let untracked_options = salsa_struct.untracked_options();
107106

108107
let field_tys = salsa_struct.field_tys();
109108
let tracked_tys = salsa_struct.tracked_tys();
110109
let untracked_tys = salsa_struct.untracked_tys();
111110

112-
let num_fields = salsa_struct.num_fields();
111+
let num_tracked_fields = salsa_struct.num_tracked_fields();
113112
let generate_debug_impl = salsa_struct.generate_debug_impl();
114113

115114
let zalsa = self.hygiene.ident("zalsa");
@@ -147,11 +146,10 @@ impl Macro {
147146

148147
absolute_untracked_indices: [#(#absolute_untracked_indices),*],
149148

150-
field_options: [#(#field_options),*],
151149
tracked_options: [#(#tracked_options),*],
152150
untracked_options: [#(#untracked_options),*],
153151

154-
num_fields: #num_fields,
152+
num_tracked_fields: #num_tracked_fields,
155153
generate_debug_impl: #generate_debug_impl,
156154
unused_names: [
157155
#zalsa,

src/tracked_struct.rs

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ pub trait Configuration: Sized + 'static {
3131
/// The debug names of any fields.
3232
const FIELD_DEBUG_NAMES: &'static [&'static str];
3333

34-
/// The absolute indices of any tracked fields.
34+
/// The relative indices of any tracked fields.
3535
const TRACKED_FIELD_INDICES: &'static [usize];
3636

3737
/// A (possibly empty) tuple of the fields for this struct.
3838
type Fields<'db>: Send + Sync;
3939

40-
/// A array of [`Revision`][] values, one per each of the value fields.
40+
/// A array of [`Revision`][] values, one per each of the tracked value fields.
4141
/// When a struct is re-recreated in a new revision, the corresponding
4242
/// entries for each field are updated to the new revision if their
4343
/// values have changed (or if the field is marked as `#[no_eq]`).
@@ -62,7 +62,10 @@ pub trait Configuration: Sized + 'static {
6262
fn new_revisions(current_revision: Revision) -> Self::Revisions;
6363

6464
/// Update the field data and, if the value has changed,
65-
/// the appropriate entry in the `revisions` array.
65+
/// the appropriate entry in the `revisions` array (for tracked fields only).
66+
///
67+
/// Returns `true` if any untracked field was updated and
68+
/// the struct should be considered changed.
6669
///
6770
/// # Safety
6871
///
@@ -87,7 +90,7 @@ pub trait Configuration: Sized + 'static {
8790
revisions: &mut Self::Revisions,
8891
old_fields: *mut Self::Fields<'db>,
8992
new_fields: Self::Fields<'db>,
90-
);
93+
) -> bool;
9194
}
9295
// ANCHOR_END: Configuration
9396

@@ -114,14 +117,16 @@ impl<C: Configuration> Jar for JarImpl<C> {
114117
) -> Vec<Box<dyn Ingredient>> {
115118
let struct_ingredient = <IngredientImpl<C>>::new(struct_index);
116119

117-
let tracked_field_ingredients = C::TRACKED_FIELD_INDICES.iter().enumerate().map(
118-
|(relative_tracked_index, &field_index)| {
119-
Box::new(<FieldIngredientImpl<C>>::new(
120-
field_index,
121-
struct_index.successor(relative_tracked_index),
122-
)) as _
123-
},
124-
);
120+
let tracked_field_ingredients =
121+
C::TRACKED_FIELD_INDICES
122+
.iter()
123+
.copied()
124+
.map(|relative_tracked_index| {
125+
Box::new(<FieldIngredientImpl<C>>::new(
126+
relative_tracked_index,
127+
struct_index.successor(relative_tracked_index),
128+
)) as _
129+
});
125130

126131
std::iter::once(Box::new(struct_ingredient) as _)
127132
.chain(tracked_field_ingredients)
@@ -398,7 +403,7 @@ where
398403
Some(id) => {
399404
// The struct already exists in the intern map.
400405
zalsa_local.add_output(self.database_key_index(id).into());
401-
self.update(zalsa, current_revision, id, &current_deps, fields);
406+
self.update_fields(zalsa, current_revision, id, &current_deps, fields);
402407
C::struct_from_id(id)
403408
}
404409

@@ -457,7 +462,7 @@ where
457462
///
458463
/// * If the value is not present in the map.
459464
/// * If the value is already updated in this revision.
460-
fn update<'db>(
465+
fn update_fields<'db>(
461466
&'db self,
462467
zalsa: &'db Zalsa,
463468
current_revision: Revision,
@@ -535,15 +540,18 @@ where
535540
// its validity invariant and any owned content also continues
536541
// to meet its safety invariant.
537542
unsafe {
538-
C::update_fields(
543+
if C::update_fields(
539544
current_revision,
540545
&mut data.revisions,
541546
self.to_self_ptr(std::ptr::addr_of_mut!(data.fields)),
542547
fields,
543-
);
548+
) {
549+
data.created_at = current_revision;
550+
}
544551
}
545552
if current_deps.durability < data.durability {
546553
data.revisions = C::new_revisions(current_revision);
554+
data.created_at = current_revision;
547555
}
548556
data.durability = current_deps.durability;
549557
let swapped_out = data.updated_at.swap(Some(current_revision));
@@ -649,7 +657,6 @@ where
649657
&'db self,
650658
db: &'db dyn crate::Database,
651659
s: C::Struct<'db>,
652-
field_index: usize,
653660
relative_tracked_index: usize,
654661
) -> &'db C::Fields<'db> {
655662
let (zalsa, zalsa_local) = db.zalsas();
@@ -659,7 +666,7 @@ where
659666

660667
data.read_lock(zalsa.current_revision());
661668

662-
let field_changed_at = data.revisions[field_index];
669+
let field_changed_at = data.revisions[relative_tracked_index];
663670

664671
zalsa_local.report_tracked_read(
665672
InputDependencyIndex::new(field_ingredient_index, id),

0 commit comments

Comments
 (0)