mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-08-04 19:08:32 +00:00
Make interned's last_interned_at
equal Revision::MAX
if they are interned outside a query (#804)
There is an assert that `last_interned_at >= last_changed_revision`, and it can fail without this, see the added test.
This commit is contained in:
parent
05b4faddb5
commit
cf9efae0da
3 changed files with 48 additions and 5 deletions
|
@ -282,11 +282,12 @@ where
|
|||
let table = zalsa.table();
|
||||
|
||||
// Record the durability of the current query on the interned value.
|
||||
let durability = zalsa_local
|
||||
let (durability, last_interned_at) = zalsa_local
|
||||
.active_query()
|
||||
.map(|(_, stamp)| stamp.durability)
|
||||
.map(|(_, stamp)| (stamp.durability, current_revision))
|
||||
// If there is no active query this durability does not actually matter.
|
||||
.unwrap_or(Durability::MAX);
|
||||
// `last_interned_at` needs to be `Revision::MAX`, see the intern_access_in_different_revision test.
|
||||
.unwrap_or((Durability::MAX, Revision::max()));
|
||||
|
||||
let id = zalsa_local.allocate(table, self.ingredient_index, |id| Value::<C> {
|
||||
fields: unsafe { self.to_internal_data(assemble(id, key)) },
|
||||
|
@ -295,7 +296,7 @@ where
|
|||
durability: AtomicU8::new(durability.as_u8()),
|
||||
// Record the revision we are interning in.
|
||||
first_interned_at: current_revision,
|
||||
last_interned_at: AtomicRevision::from(current_revision),
|
||||
last_interned_at: AtomicRevision::from(last_interned_at),
|
||||
});
|
||||
|
||||
let value = table.get::<Value<C>>(id);
|
||||
|
@ -391,7 +392,11 @@ where
|
|||
|
||||
// The slot is valid in this revision but we have to sync the value's revision.
|
||||
let current_revision = zalsa.current_revision();
|
||||
value.last_interned_at.store(current_revision);
|
||||
// No `if` to be branchless.
|
||||
value.last_interned_at.store(std::cmp::max(
|
||||
current_revision,
|
||||
value.last_interned_at.load(),
|
||||
));
|
||||
|
||||
db.salsa_event(&|| {
|
||||
Event::new(EventKind::DidReinternValue {
|
||||
|
|
|
@ -17,24 +17,34 @@ pub struct Revision {
|
|||
}
|
||||
|
||||
impl Revision {
|
||||
#[inline]
|
||||
pub(crate) fn max() -> Self {
|
||||
Self::from(usize::MAX)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn start() -> Self {
|
||||
Self::from(START)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from(g: usize) -> Self {
|
||||
Self {
|
||||
generation: NonZeroUsize::new(g).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn from_opt(g: usize) -> Option<Self> {
|
||||
NonZeroUsize::new(g).map(|generation| Self { generation })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn next(self) -> Revision {
|
||||
Self::from(self.generation.get() + 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn as_usize(self) -> usize {
|
||||
self.generation.get()
|
||||
}
|
||||
|
|
28
tests/intern_access_in_different_revision.rs
Normal file
28
tests/intern_access_in_different_revision.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use salsa::{Durability, Setter};
|
||||
|
||||
#[salsa::interned(no_lifetime)]
|
||||
struct Interned {
|
||||
field: u32,
|
||||
}
|
||||
|
||||
#[salsa::input]
|
||||
struct Input {
|
||||
field: i32,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_test() {
|
||||
let mut db = salsa::DatabaseImpl::default();
|
||||
let input = Input::builder(-123456)
|
||||
.field_durability(Durability::HIGH)
|
||||
.new(&db);
|
||||
// Create an intern in an early revision.
|
||||
let interned = Interned::new(&db, 0xDEADBEEF);
|
||||
// Trigger a new revision.
|
||||
input
|
||||
.set_field(&mut db)
|
||||
.with_durability(Durability::HIGH)
|
||||
.to(123456);
|
||||
// Read the interned value
|
||||
let _ = interned.field(&db);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue