make memos take read-lock (and infallible return)

We want to ensure that accessing the memos only occurs
in revision R after the struct is created.
This commit is contained in:
Niko Matsakis 2024-08-15 17:38:16 +03:00
parent 8833a7168b
commit 3dabb0ddc8
4 changed files with 46 additions and 36 deletions

View file

@ -308,7 +308,7 @@ impl<C> Slot for Value<C>
where where
C: Configuration, C: Configuration,
{ {
fn memos(&self) -> Option<&crate::table::memo::MemoTable> { fn memos(&self, _current_revision: Revision) -> &crate::table::memo::MemoTable {
Some(&self.memos) &self.memos
} }
} }

View file

@ -276,7 +276,7 @@ impl<C> Slot for Value<C>
where where
C: Configuration, C: Configuration,
{ {
fn memos(&self) -> Option<&MemoTable> { fn memos(&self, _current_revision: Revision) -> &MemoTable {
Some(&self.memos) &self.memos
} }
} }

View file

@ -24,7 +24,7 @@ pub(crate) struct Table {
pub(crate) trait TablePage: Any + Send + Sync { pub(crate) trait TablePage: Any + Send + Sync {
fn hidden_type_name(&self) -> &'static str; fn hidden_type_name(&self) -> &'static str;
fn memos(&self, slot: SlotIndex) -> Option<&MemoTable>; fn memos(&self, slot: SlotIndex, current_revision: Revision) -> &MemoTable;
} }
pub(crate) struct Page<T: Slot> { pub(crate) struct Page<T: Slot> {
@ -51,7 +51,7 @@ pub(crate) struct Page<T: Slot> {
} }
pub(crate) trait Slot: Any + Send + Sync { pub(crate) trait Slot: Any + Send + Sync {
fn memos(&self) -> Option<&MemoTable>; fn memos(&self, current_revision: Revision) -> &MemoTable;
} }
unsafe impl<T: Slot> Send for Page<T> {} unsafe impl<T: Slot> Send for Page<T> {}
@ -117,9 +117,13 @@ impl Table {
} }
/// Get the memo table associated with `id` (if any) /// Get the memo table associated with `id` (if any)
pub fn memos(&self, id: Id) -> Option<&MemoTable> { ///
/// # Panics
///
/// If the ingredient for `id` doesn't have associated memo-tables on its slots.
pub fn memos(&self, id: Id, current_revision: Revision) -> &MemoTable {
let (page, slot) = split_id(id); let (page, slot) = split_id(id);
self.pages[page.0].memos(slot) self.pages[page.0].memos(slot, current_revision)
} }
} }
@ -194,8 +198,8 @@ impl<T: Slot> TablePage for Page<T> {
std::any::type_name::<Self>() std::any::type_name::<Self>()
} }
fn memos(&self, slot: SlotIndex) -> Option<&MemoTable> { fn memos(&self, slot: SlotIndex, current_revision: Revision) -> &MemoTable {
self.get(slot).memos() self.get(slot).memos(current_revision)
} }
} }

View file

@ -521,7 +521,7 @@ where
let field_ingredient_index = self.ingredient_index.successor(field_index); let field_ingredient_index = self.ingredient_index.successor(field_index);
let data = Self::data(zalsa.table(), id); let data = Self::data(zalsa.table(), id);
self.read_lock(data, zalsa.current_revision()); data.read_lock(zalsa.current_revision());
let field_changed_at = data.revisions[field_index]; let field_changed_at = data.revisions[field_index];
@ -536,29 +536,6 @@ where
unsafe { self.to_self_ref(&data.fields) } unsafe { self.to_self_ref(&data.fields) }
} }
fn read_lock(&self, data: &Value<C>, current_revision: Revision) {
loop {
match data.updated_at.load() {
None => {
panic!("access to field whilst the value is being initialized");
}
Some(r) => {
if r == current_revision {
return;
}
if data
.updated_at
.compare_exchange(Some(r), Some(current_revision))
.is_ok()
{
break;
}
}
}
}
}
} }
impl<C> Ingredient for IngredientImpl<C> impl<C> Ingredient for IngredientImpl<C>
@ -640,11 +617,40 @@ where
} }
} }
impl<C> Value<C>
where
C: Configuration,
{
fn read_lock(&self, current_revision: Revision) {
loop {
match self.updated_at.load() {
None => {
panic!("access to field whilst the value is being initialized");
}
Some(r) => {
if r == current_revision {
return;
}
if self
.updated_at
.compare_exchange(Some(r), Some(current_revision))
.is_ok()
{
break;
}
}
}
}
}
}
impl<C> Slot for Value<C> impl<C> Slot for Value<C>
where where
C: Configuration, C: Configuration,
{ {
fn memos(&self) -> Option<&crate::table::memo::MemoTable> { fn memos(&self, current_revision: Revision) -> &crate::table::memo::MemoTable {
Some(&self.memos) self.read_lock(current_revision);
&self.memos
} }
} }