Skip to content

Commit d76db1d

Browse files
committed
review feedback from Micha
1 parent b30e9a7 commit d76db1d

File tree

2 files changed

+47
-12
lines changed

2 files changed

+47
-12
lines changed

src/tracked_struct/struct_map.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,13 @@ where
9999
unsafe { C::struct_from_raw(pointer) }
100100
}
101101

102+
/// Mark the given tracked struct as valid in the current revision.
102103
pub fn validate<'db>(&'db self, runtime: &'db Runtime, id: Id) {
103104
Self::validate_in_map(&self.map, runtime, id)
104105
}
105106

106-
pub fn validate_in_map<'db>(
107+
/// Internal helper to provide shared functionality for [`StructMapView`].
108+
fn validate_in_map<'db>(
107109
map: &'db FxDashMap<Id, Alloc<Value<C>>>,
108110
runtime: &'db Runtime,
109111
id: Id,
@@ -209,6 +211,18 @@ where
209211
unsafe { C::struct_from_raw(data.as_raw()) }
210212
}
211213

214+
/// Lookup an existing tracked struct from the map, maybe validating it to current revision.
215+
///
216+
/// Validates to current revision if the struct was last created/validated in a revision that
217+
/// is still current for the struct's durability. That is, if the struct is HIGH durability
218+
/// (created by a HIGH durability query) and was created in R2, and we are now at R3 but no
219+
/// HIGH durability input has changed since R2, the struct is still valid and we can validate
220+
/// it to R3.
221+
///
222+
/// # Panics
223+
///
224+
/// * If the value is not present in the map.
225+
/// * If the value has not been updated in the last-changed revision for its durability.
212226
fn get_and_validate_last_changed<'db>(
213227
map: &'db FxDashMap<Id, Alloc<Value<C>>>,
214228
runtime: &'db Runtime,
@@ -217,20 +231,13 @@ where
217231
let data = map.get(&id).unwrap();
218232

219233
// UNSAFE: We permit `&`-access in the current revision once data.created_at
220-
// has been updated to the current revision (which we check below).
234+
// has been updated to the current revision (which we ensure below).
221235
let data_ref: &Value<C> = unsafe { data.as_ref() };
222236

223-
// Before we drop the lock, check that the value has
224-
// been updated in the most recent version in which the query that created it could have
225-
// changed (based on durability), and validate to the current revision if so.
237+
// Before we drop the lock, check that the value has been updated in the most recent
238+
// version in which the query that created it could have changed (based on durability).
226239
let created_at = data_ref.created_at;
227240
let last_changed = runtime.last_changed_revision(data_ref.durability);
228-
dbg!(
229-
runtime.current_revision(),
230-
created_at,
231-
last_changed,
232-
data_ref.durability
233-
);
234241
assert!(
235242
created_at >= last_changed,
236243
"access to tracked struct from obsolete revision"
@@ -287,7 +294,15 @@ where
287294
StructMap::get_from_map(&self.map, current_revision, id)
288295
}
289296

290-
pub fn get_and_validate_last_changed<'db>(
297+
/// Lookup an existing tracked struct from the map, maybe validating it to current revision.
298+
///
299+
/// See [`StructMap::get_and_validate_last_changed`].
300+
///
301+
/// # Panics
302+
///
303+
/// * If the value is not present in the map.
304+
/// * If the value has not been updated in the last-changed revision for its durability.
305+
pub(super) fn get_and_validate_last_changed<'db>(
291306
&'db self,
292307
runtime: &'db Runtime,
293308
id: Id,

tests/tracked_struct_not_validated_due_to_durability.rs

+20
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
/// Test that high durabilities can't cause "access tracked struct from previous revision" panic.
2+
///
3+
/// The test models a situation where we have two File inputs (0, 1), where `File(0)` has LOW
4+
/// durability and `File(1)` has HIGH durability. We can query an `index` for each file, and a
5+
/// `definitions` from that index (just a sub-part of the index), and we can `infer` each file. The
6+
/// `index` and `definitions` queries depend only on the `File` they operate on, but the `infer`
7+
/// query has some other dependencies: `infer(0)` depends on `infer(1)`, and `infer(1)` also
8+
/// depends directly on `File(0)`.
9+
///
10+
/// The panic occurs (in versions of Salsa without a fix) because `definitions(1)` is high
11+
/// durability, and depends on `index(1)` which is also high durability. `index(1)` creates the
12+
/// tracked struct `Definition(1)`, and `infer(1)` (which is low durability) depends on
13+
/// `Definition.file(1)`.
14+
///
15+
/// After a change to `File(0)` (low durability), we only shallowly verify `definitions(1)` -- it
16+
/// passes shallow verification due to durability. We take care to mark-validated the outputs of
17+
/// `definitions(1)`, but we never verify `index(1)` at all (deeply or shallowly), which means we
18+
/// never mark `Definition(1)` validated. So when we deep-verify `infer(1)`, we try to access its
19+
/// dependency `Definition.file(1)`, and hit the panic because we are accessing a tracked struct
20+
/// that has never been re-validated or re-recreated in R2.
121
use salsa::{Durability, Setter};
222

323
#[salsa::db]

0 commit comments

Comments
 (0)