Skip to content

Commit d5b58fb

Browse files
committed
More flexible memo dropping via channels
1 parent c3f86b8 commit d5b58fb

File tree

15 files changed

+465
-167
lines changed

15 files changed

+465
-167
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.12"
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.15"
5959
dashmap = { version = "6", features = ["raw-api"] }
6060
eyre = "0.6.12"
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,24 +1,24 @@
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, CycleHeadKeys, CycleHeads, CycleRecoveryAction, CycleRecoveryStrategy,
1112
ProvisionalStatus,
1213
};
1314
use crate::database::RawDatabase;
14-
use crate::function::delete::DeletedEntries;
1515
use crate::function::sync::{ClaimResult, SyncTable};
1616
use crate::ingredient::{Ingredient, WaitForResult};
1717
use crate::key::DatabaseKeyIndex;
1818
use crate::plumbing::MemoIngredientMap;
1919
use crate::salsa_struct::SalsaStructInDb;
2020
use crate::sync::Arc;
21-
use crate::table::memo::MemoTableTypes;
21+
use crate::table::memo::{DeletedEntries, MemoTableTypes};
2222
use crate::table::Table;
2323
use crate::views::DatabaseDownCaster;
2424
use crate::zalsa::{IngredientIndex, MemoIngredientIndex, Zalsa};
@@ -28,7 +28,6 @@ use crate::{Id, Revision};
2828
#[cfg(feature = "accumulator")]
2929
mod accumulated;
3030
mod backdate;
31-
mod delete;
3231
mod diff_outputs;
3332
mod execute;
3433
mod fetch;
@@ -147,7 +146,8 @@ pub struct IngredientImpl<C: Configuration> {
147146
/// current revision: you would be right, but we are being defensive, because
148147
/// we don't know that we can trust the database to give us the same runtime
149148
/// everytime and so forth.
150-
deleted_entries: DeletedEntries<C>,
149+
delete: DeletedEntries,
150+
config: PhantomData<fn(C) -> C>,
151151
}
152152

153153
impl<C> IngredientImpl<C>
@@ -162,10 +162,11 @@ where
162162
Self {
163163
index,
164164
memo_ingredient_indices,
165-
lru: lru::Lru::new(lru),
166-
deleted_entries: Default::default(),
167165
view_caster: OnceLock::new(),
166+
lru: lru::Lru::new(lru),
167+
delete: DeletedEntries::default(),
168168
sync_table: SyncTable::new(index),
169+
config: PhantomData,
169170
}
170171
}
171172

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

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

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

359354
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: 16 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,10 @@ 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(memo) = table.fetch::<Memo<'static, C>>(memo_ingredient_index) {
67+
match &memo.revisions.origin.as_ref() {
6868
QueryOriginRef::Assigned(_)
6969
| QueryOriginRef::DerivedUntracked(_)
7070
| QueryOriginRef::FixpointInitial => {
@@ -73,14 +73,9 @@ impl<C: Configuration> IngredientImpl<C> {
7373
// or those with untracked inputs
7474
// as their values cannot be reconstructed.
7575
}
76-
QueryOriginRef::Derived(_) => {
77-
// Set the memo value to `None`.
78-
memo.value = None;
79-
}
76+
QueryOriginRef::Derived(_) => _ = memo.value.take(),
8077
}
81-
};
82-
83-
table.map_memo(memo_ingredient_index, map)
78+
}
8479
}
8580
}
8681

@@ -333,6 +328,10 @@ where
333328
},
334329
}
335330
}
331+
332+
fn clear_value(&mut self) {
333+
self.value = None;
334+
}
336335
}
337336

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

src/ingredient.rs

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