Skip to content

Commit ba28ff2

Browse files
committed
More flexible memo dropping via channels
1 parent 679d82c commit ba28ff2

File tree

13 files changed

+335
-151
lines changed

13 files changed

+335
-151
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ salsa-macros = { version = "0.23.0", path = "components/salsa-macros", optional
1515
boxcar = "0.2.13"
1616
crossbeam-queue = "0.3.11"
1717
crossbeam-utils = "0.8.21"
18+
crossbeam-channel = "0.5.15"
1819
hashbrown = "0.15"
1920
hashlink = "0.10"
2021
indexmap = "2"
@@ -55,7 +56,6 @@ salsa-macros = { version = "=0.23.0", path = "components/salsa-macros" }
5556

5657
[dev-dependencies]
5758
# examples
58-
crossbeam-channel = "0.5.14"
5959
dashmap = { version = "6", features = ["raw-api"] }
6060
eyre = "0.6.8"
6161
notify-debouncer-mini = "0.4.1"

src/database.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ pub trait Database: Send + ZalsaDatabase + AsDynDatabase {
4242
/// is owned by the current thread, this could trigger deadlock.
4343
fn trigger_lru_eviction(&mut self) {
4444
let zalsa_mut = self.zalsa_mut();
45-
zalsa_mut.evict_lru();
45+
zalsa_mut.reset_for_new_revision();
4646
}
4747

4848
/// A "synthetic write" causes the system to act *as though* some

src/function.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
pub(crate) use maybe_changed_after::VerifyResult;
22
use std::any::Any;
3-
use std::fmt;
3+
use std::marker::PhantomData;
44
use std::ptr::NonNull;
55
use std::sync::atomic::Ordering;
66
use std::sync::OnceLock;
7+
use std::{fmt, mem};
78
pub(crate) use sync::SyncGuard;
89

910
use crate::cycle::{
1011
empty_cycle_heads, CycleHeads, CycleRecoveryAction, CycleRecoveryStrategy, ProvisionalStatus,
1112
};
1213
use crate::database::RawDatabase;
13-
use crate::function::delete::DeletedEntries;
1414
use crate::function::sync::{ClaimResult, SyncTable};
1515
use crate::ingredient::{Ingredient, WaitForResult};
1616
use crate::key::DatabaseKeyIndex;
1717
use crate::plumbing::MemoIngredientMap;
1818
use crate::salsa_struct::SalsaStructInDb;
1919
use crate::sync::Arc;
20-
use crate::table::memo::MemoTableTypes;
20+
use crate::table::memo::{DeletedEntries, MemoTableTypes};
2121
use crate::table::Table;
2222
use crate::views::DatabaseDownCaster;
2323
use crate::zalsa::{IngredientIndex, MemoIngredientIndex, Zalsa};
@@ -27,7 +27,6 @@ use crate::{Id, Revision};
2727
#[cfg(feature = "accumulator")]
2828
mod accumulated;
2929
mod backdate;
30-
mod delete;
3130
mod diff_outputs;
3231
mod execute;
3332
mod fetch;
@@ -146,7 +145,8 @@ pub struct IngredientImpl<C: Configuration> {
146145
/// current revision: you would be right, but we are being defensive, because
147146
/// we don't know that we can trust the database to give us the same runtime
148147
/// everytime and so forth.
149-
deleted_entries: DeletedEntries<C>,
148+
delete: DeletedEntries,
149+
config: PhantomData<fn(C) -> C>,
150150
}
151151

152152
impl<C> IngredientImpl<C>
@@ -161,10 +161,11 @@ where
161161
Self {
162162
index,
163163
memo_ingredient_indices,
164-
lru: lru::Lru::new(lru),
165-
deleted_entries: Default::default(),
166164
view_caster: OnceLock::new(),
165+
lru: lru::Lru::new(lru),
166+
delete: DeletedEntries::default(),
167167
sync_table: SyncTable::new(index),
168+
config: PhantomData,
168169
}
169170
}
170171

@@ -221,16 +222,7 @@ where
221222
// FIXME: Use `Box::into_non_null` once stable
222223
let memo = NonNull::from(Box::leak(Box::new(memo)));
223224

224-
if let Some(old_value) =
225-
self.insert_memo_into_table_for(zalsa, id, memo, memo_ingredient_index)
226-
{
227-
// In case there is a reference to the old memo out there, we have to store it
228-
// in the deleted entries. This will get cleared when a new revision starts.
229-
//
230-
// SAFETY: Once the revision starts, there will be no outstanding borrows to the
231-
// memo contents, and so it will be safe to free.
232-
unsafe { self.deleted_entries.push(old_value) };
233-
}
225+
self.insert_memo_into_table_for(zalsa, id, memo, memo_ingredient_index);
234226
// SAFETY: memo has been inserted into the table
235227
unsafe { self.extend_memo_lifetime(memo.as_ref()) }
236228
}
@@ -343,16 +335,19 @@ where
343335
true
344336
}
345337

346-
fn reset_for_new_revision(&mut self, table: &mut Table) {
338+
fn reset_for_new_revision(
339+
&mut self,
340+
table: &mut Table,
341+
new_buffer: DeletedEntries,
342+
) -> DeletedEntries {
347343
self.lru.for_each_evicted(|evict| {
348344
let ingredient_index = table.ingredient_index(evict);
349345
Self::evict_value_from_memo_for(
350346
table.memos_mut(evict),
351347
self.memo_ingredient_indices.get(ingredient_index),
352348
)
353349
});
354-
355-
self.deleted_entries.clear();
350+
mem::replace(&mut self.delete, new_buffer)
356351
}
357352

358353
fn debug_name(&self) -> &'static str {

src/function/delete.rs

Lines changed: 0 additions & 52 deletions
This file was deleted.

src/function/memo.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,24 +19,23 @@ use crate::{Event, EventKind, Id, Revision};
1919
impl<C: Configuration> IngredientImpl<C> {
2020
/// Inserts the memo for the given key; (atomically) overwrites and returns any previously existing memo
2121
pub(super) fn insert_memo_into_table_for<'db>(
22-
&self,
22+
&'db self,
2323
zalsa: &'db Zalsa,
2424
id: Id,
2525
memo: NonNull<Memo<'db, C>>,
2626
memo_ingredient_index: MemoIngredientIndex,
27-
) -> Option<NonNull<Memo<'db, C>>> {
27+
) {
2828
// SAFETY: The table stores 'static memos (to support `Any`), the memos are in fact valid
2929
// for `'db` though as we delay their dropping to the end of a revision.
3030
let static_memo =
3131
unsafe { transmute::<NonNull<Memo<'db, C>>, NonNull<Memo<'static, C>>>(memo) };
3232
let old_static_memo = zalsa
3333
.memo_table_for::<C::SalsaStruct<'_>>(id)
34-
.insert(memo_ingredient_index, static_memo)?;
35-
// SAFETY: The table stores 'static memos (to support `Any`), the memos are in fact valid
36-
// for `'db` though as we delay their dropping to the end of a revision.
37-
Some(unsafe {
38-
transmute::<NonNull<Memo<'static, C>>, NonNull<Memo<'db, C>>>(old_static_memo)
39-
})
34+
.insert(memo_ingredient_index, static_memo);
35+
if let Some(old_memo) = old_static_memo {
36+
// SAFETY: We delay clearing properly
37+
unsafe { self.delete.push(old_memo) };
38+
}
4039
}
4140

4241
/// Loads the current memo for `key_index`. This does not hold any sort of
@@ -62,9 +61,12 @@ impl<C: Configuration> IngredientImpl<C> {
6261
pub(super) fn evict_value_from_memo_for(
6362
table: MemoTableWithTypesMut<'_>,
6463
memo_ingredient_index: MemoIngredientIndex,
64+
//FIXME should provide a page to move the value into so we can delay the drop
6565
) {
66-
let map = |memo: &mut Memo<'static, C>| {
67-
match memo.revisions.origin.as_ref() {
66+
if let Some(mut memo) = table.fetch_raw::<Memo<'static, C>>(memo_ingredient_index) {
67+
// SAFETY: The memo is live and we have unique mutable access to the table
68+
let memo = unsafe { memo.as_mut() };
69+
match &memo.revisions.origin.as_ref() {
6870
QueryOriginRef::Assigned(_)
6971
| QueryOriginRef::DerivedUntracked(_)
7072
| QueryOriginRef::FixpointInitial => {
@@ -73,14 +75,9 @@ impl<C: Configuration> IngredientImpl<C> {
7375
// or those with untracked inputs
7476
// as their values cannot be reconstructed.
7577
}
76-
QueryOriginRef::Derived(_) => {
77-
// Set the memo value to `None`.
78-
memo.value = None;
79-
}
78+
QueryOriginRef::Derived(_) => _ = memo.value.take(),
8079
}
81-
};
82-
83-
table.map_memo(memo_ingredient_index, map)
80+
}
8481
}
8582
}
8683

@@ -333,6 +330,10 @@ where
333330
},
334331
}
335332
}
333+
334+
fn clear_value(&mut self) {
335+
self.value = None;
336+
}
336337
}
337338

338339
pub(super) enum TryClaimHeadsResult<'me> {

src/ingredient.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::database::RawDatabase;
88
use crate::function::VerifyResult;
99
use crate::runtime::Running;
1010
use crate::sync::Arc;
11-
use crate::table::memo::MemoTableTypes;
11+
use crate::table::memo::{DeletedEntries, MemoTableTypes};
1212
use crate::table::Table;
1313
use crate::zalsa::{transmute_data_mut_ptr, transmute_data_ptr, IngredientIndex, Zalsa};
1414
use crate::zalsa_local::QueryOriginRef;
@@ -127,8 +127,12 @@ pub trait Ingredient: Any + std::fmt::Debug + Send + Sync {
127127
///
128128
/// **Important:** to actually receive resets, the ingredient must set
129129
/// [`IngredientRequiresReset::RESET_ON_NEW_REVISION`] to true.
130-
fn reset_for_new_revision(&mut self, table: &mut Table) {
131-
_ = table;
130+
fn reset_for_new_revision(
131+
&mut self,
132+
table: &mut Table,
133+
new_buffer: DeletedEntries,
134+
) -> DeletedEntries {
135+
_ = (table, new_buffer);
132136
panic!(
133137
"Ingredient `{}` set `Ingredient::requires_reset_for_new_revision` to true but does \
134138
not overwrite `Ingredient::reset_for_new_revision`",

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pub use self::revision::Revision;
6666
pub use self::runtime::Runtime;
6767
pub use self::storage::{Storage, StorageHandle};
6868
pub use self::update::Update;
69-
pub use self::zalsa::IngredientIndex;
69+
pub use self::zalsa::{DeletedEntriesDropper, DropChannelReceiver, IngredientIndex};
7070
pub use crate::attach::{attach, with_attached_database};
7171

7272
pub mod prelude {

src/runtime.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ use self::dependency_graph::DependencyGraph;
22
use crate::durability::Durability;
33
use crate::function::SyncGuard;
44
use crate::key::DatabaseKeyIndex;
5+
use crate::plumbing::Ingredient;
56
use crate::sync::atomic::{AtomicBool, Ordering};
67
use crate::sync::thread::{self, ThreadId};
78
use crate::sync::Mutex;
9+
use crate::table::memo::DeletedEntries;
810
use crate::table::Table;
911
use crate::zalsa::Zalsa;
1012
use crate::{Cancelled, Event, EventKind, Revision};
@@ -194,10 +196,6 @@ impl Runtime {
194196
&self.table
195197
}
196198

197-
pub(crate) fn table_mut(&mut self) -> &mut Table {
198-
&mut self.table
199-
}
200-
201199
/// Increments the "current revision" counter and clears
202200
/// the cancellation flag.
203201
///
@@ -263,4 +261,12 @@ impl Runtime {
263261
.lock()
264262
.unblock_runtimes_blocked_on(database_key, wait_result);
265263
}
264+
265+
pub(crate) fn reset_ingredient_for_new_revision(
266+
&mut self,
267+
ingredient: &mut (dyn Ingredient + 'static),
268+
new_buffer: DeletedEntries,
269+
) -> DeletedEntries {
270+
ingredient.reset_for_new_revision(&mut self.table, new_buffer)
271+
}
266272
}

0 commit comments

Comments
 (0)