Skip to content

Commit 506a57c

Browse files
committed
record durabilities on interned values
1 parent 6505453 commit 506a57c

File tree

3 files changed

+77
-13
lines changed

3 files changed

+77
-13
lines changed

src/durability.rs

+10
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,16 @@ impl Durability {
4747
pub(crate) fn index(self) -> usize {
4848
self.0 as usize
4949
}
50+
51+
pub(crate) fn as_u8(self) -> u8 {
52+
self.0
53+
}
54+
55+
pub(crate) fn from_u8(value: u8) -> Self {
56+
assert!((value as usize) < Self::LEN, "invalid durability");
57+
58+
Self(value)
59+
}
5060
}
5161

5262
impl Default for Durability {

src/interned.rs

+63-8
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use std::fmt;
1313
use std::hash::{BuildHasher, Hash, Hasher};
1414
use std::marker::PhantomData;
1515
use std::path::{Path, PathBuf};
16+
use std::sync::atomic::{AtomicU8, Ordering};
1617

1718
use super::hash::FxDashMap;
1819
use super::ingredient::Ingredient;
@@ -68,10 +69,27 @@ where
6869
data: C::Data<'static>,
6970
memos: MemoTable,
7071
syncs: SyncTable,
72+
7173
/// The revision the value was first interned in.
7274
first_interned_at: Revision,
75+
7376
/// The most recent interned revision.
7477
last_interned_at: AtomicRevision,
78+
79+
/// The minimum durability of all inputs consumed by the creator
80+
/// query prior to creating this tracked struct. If any of those
81+
/// inputs changes, then the creator query may create this struct
82+
/// with different values.
83+
durability: AtomicU8,
84+
}
85+
86+
impl<C> Value<C>
87+
where
88+
C: Configuration,
89+
{
90+
fn durability(&self) -> Durability {
91+
Durability::from_u8(self.durability.load(Ordering::Acquire))
92+
}
7593
}
7694

7795
impl<C: Configuration> Default for JarImpl<C> {
@@ -148,13 +166,25 @@ where
148166
// SAFETY: Read lock on map is held during this block
149167
let id = unsafe { *bucket.as_ref().1.get() };
150168

151-
// Sync the value's revision.
152169
let value = zalsa.table().get::<Value<C>>(id);
170+
171+
// Sync the value's revision.
153172
value.last_interned_at.store(current_revision);
154173

174+
let durability = if let Some((_, stamp)) = zalsa_local.active_query() {
175+
// Record the maximum durability across all queries that intern this value.
176+
let previous_durability = value
177+
.durability
178+
.fetch_max(stamp.durability.as_u8(), Ordering::AcqRel);
179+
180+
Durability::from_u8(previous_durability).max(stamp.durability)
181+
} else {
182+
value.durability()
183+
};
184+
155185
// Record a dependency on this value.
156186
let index = self.database_key_index(id);
157-
zalsa_local.report_tracked_read(index, Durability::MAX, current_revision);
187+
zalsa_local.report_tracked_read(index, durability, current_revision);
158188

159189
return C::struct_from_id(id);
160190
}
@@ -170,13 +200,25 @@ where
170200
let id = *entry.get();
171201
drop(entry);
172202

173-
// Sync the value's revision.
174203
let value = zalsa.table().get::<Value<C>>(id);
204+
205+
// Sync the value's revision.
175206
value.last_interned_at.store(current_revision);
176207

208+
let durability = if let Some((_, stamp)) = zalsa_local.active_query() {
209+
// Record the maximum durability across all queries that intern this value.
210+
let previous_durability = value
211+
.durability
212+
.fetch_max(stamp.durability.as_u8(), Ordering::AcqRel);
213+
214+
Durability::from_u8(previous_durability).max(stamp.durability)
215+
} else {
216+
value.durability()
217+
};
218+
177219
// Record a dependency on this value.
178220
let index = self.database_key_index(id);
179-
zalsa_local.report_tracked_read(index, Durability::MAX, current_revision);
221+
zalsa_local.report_tracked_read(index, durability, current_revision);
180222

181223
C::struct_from_id(id)
182224
}
@@ -186,18 +228,30 @@ where
186228
let zalsa = db.zalsa();
187229
let table = zalsa.table();
188230

231+
let (durability, last_interned_at) = match zalsa_local.active_query() {
232+
// Record the durability of the current query, along with the revision
233+
// we are interning in.
234+
Some((_, stamp)) => (stamp.durability, current_revision),
235+
236+
// An interned value created outside of a query is considered immortal.
237+
// The durability in this case doesn't really matter.
238+
None => (Durability::MAX, Revision::from(usize::MAX)),
239+
};
240+
189241
let next_id = zalsa_local.allocate(table, self.ingredient_index, || Value::<C> {
190242
data: internal_data,
191243
memos: Default::default(),
192244
syncs: Default::default(),
193245
first_interned_at: current_revision,
194-
last_interned_at: AtomicRevision::from(current_revision),
246+
durability: AtomicU8::new(durability.as_u8()),
247+
last_interned_at: AtomicRevision::from(last_interned_at),
195248
});
249+
196250
entry.insert(next_id);
197251

198252
// Record a dependency on this value.
199253
let index = self.database_key_index(next_id);
200-
zalsa_local.report_tracked_read(index, Durability::MAX, current_revision);
254+
zalsa_local.report_tracked_read(index, durability, current_revision);
201255

202256
C::struct_from_id(next_id)
203257
}
@@ -217,9 +271,10 @@ where
217271
/// to the interned item.
218272
pub fn data<'db>(&'db self, db: &'db dyn Database, id: Id) -> &'db C::Data<'db> {
219273
let value = db.zalsa().table().get::<Value<C>>(id);
274+
let last_changed_revision = db.zalsa().last_changed_revision(value.durability());
220275
assert!(
221-
value.last_interned_at.load() >= db.zalsa().current_revision(),
222-
"Data was not interned in the current revision."
276+
value.last_interned_at.load() >= last_changed_revision,
277+
"Data was not interned in the latest revision for its durability."
223278
);
224279
unsafe { Self::from_internal_data(&value.data) }
225280
}

src/tracked_struct.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ pub struct Value<C>
182182
where
183183
C: Configuration,
184184
{
185-
/// The durability minimum durability of all inputs consumed
186-
/// by the creator query prior to creating this tracked struct.
187-
/// If any of those inputs changes, then the creator query may
188-
/// create this struct with different values.
185+
/// The minimum durability of all inputs consumed by the creator
186+
/// query prior to creating this tracked struct. If any of those
187+
/// inputs changes, then the creator query may create this struct
188+
/// with different values.
189189
durability: Durability,
190190

191191
/// The revision when this tracked struct was last updated.
@@ -283,7 +283,6 @@ where
283283

284284
let identity = Identity {
285285
identity_hash,
286-
287286
disambiguator,
288287
};
289288

0 commit comments

Comments
 (0)