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
C: Configuration,
{
fn memos(&self) -> Option<&crate::table::memo::MemoTable> {
Some(&self.memos)
fn memos(&self, _current_revision: Revision) -> &crate::table::memo::MemoTable {
&self.memos
}
}

View file

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

View file

@ -24,7 +24,7 @@ pub(crate) struct Table {
pub(crate) trait TablePage: Any + Send + Sync {
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> {
@ -51,7 +51,7 @@ pub(crate) struct Page<T: Slot> {
}
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> {}
@ -117,9 +117,13 @@ impl Table {
}
/// 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);
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>()
}
fn memos(&self, slot: SlotIndex) -> Option<&MemoTable> {
self.get(slot).memos()
fn memos(&self, slot: SlotIndex, current_revision: Revision) -> &MemoTable {
self.get(slot).memos(current_revision)
}
}

View file

@ -521,7 +521,7 @@ where
let field_ingredient_index = self.ingredient_index.successor(field_index);
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];
@ -536,29 +536,6 @@ where
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>
@ -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>
where
C: Configuration,
{
fn memos(&self) -> Option<&crate::table::memo::MemoTable> {
Some(&self.memos)
fn memos(&self, current_revision: Revision) -> &crate::table::memo::MemoTable {
self.read_lock(current_revision);
&self.memos
}
}