Skip to content

Commit 7ab9dba

Browse files
committed
More flexible memo dropping via channels
1 parent e8ddb4d commit 7ab9dba

File tree

15 files changed

+485
-162
lines changed

15 files changed

+485
-162
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.24.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"
@@ -66,7 +67,6 @@ salsa-macros = { version = "=0.24.0", path = "components/salsa-macros" }
6667

6768
[dev-dependencies]
6869
# examples
69-
crossbeam-channel = "0.5.15"
7070
dashmap = { version = "6", features = ["raw-api"] }
7171
eyre = "0.6.12"
7272
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
@@ -2,21 +2,21 @@ pub(crate) use maybe_changed_after::{VerifyCycleHeads, VerifyResult};
22
pub(crate) use sync::{ClaimGuard, ClaimResult, Reentrancy, SyncGuard, SyncOwner, SyncTable};
33

44
use std::any::Any;
5-
use std::fmt;
5+
use std::marker::PhantomData;
66
use std::ptr::NonNull;
77
use std::sync::atomic::Ordering;
88
use std::sync::OnceLock;
9+
use std::{fmt, mem};
910

1011
use crate::cycle::{CycleRecoveryAction, CycleRecoveryStrategy, IterationCount, ProvisionalStatus};
1112
use crate::database::RawDatabase;
12-
use crate::function::delete::DeletedEntries;
1313
use crate::hash::{FxHashSet, FxIndexSet};
1414
use crate::ingredient::{Ingredient, WaitForResult};
1515
use crate::key::DatabaseKeyIndex;
1616
use crate::plumbing::{self, MemoIngredientMap};
1717
use crate::salsa_struct::SalsaStructInDb;
1818
use crate::sync::Arc;
19-
use crate::table::memo::MemoTableTypes;
19+
use crate::table::memo::{DeletedEntries, MemoTableTypes};
2020
use crate::table::Table;
2121
use crate::views::DatabaseDownCaster;
2222
use crate::zalsa::{IngredientIndex, JarKind, MemoIngredientIndex, Zalsa};
@@ -26,7 +26,6 @@ use crate::{Id, Revision};
2626
#[cfg(feature = "accumulator")]
2727
mod accumulated;
2828
mod backdate;
29-
mod delete;
3029
mod diff_outputs;
3130
mod execute;
3231
mod fetch;
@@ -183,7 +182,8 @@ pub struct IngredientImpl<C: Configuration> {
183182
/// current revision: you would be right, but we are being defensive, because
184183
/// we don't know that we can trust the database to give us the same runtime
185184
/// everytime and so forth.
186-
deleted_entries: DeletedEntries<C>,
185+
delete: DeletedEntries,
186+
config: PhantomData<fn(C) -> C>,
187187
}
188188

189189
impl<C> IngredientImpl<C>
@@ -198,10 +198,11 @@ where
198198
Self {
199199
index,
200200
memo_ingredient_indices,
201-
lru: lru::Lru::new(lru),
202-
deleted_entries: Default::default(),
203201
view_caster: OnceLock::new(),
202+
lru: lru::Lru::new(lru),
203+
delete: DeletedEntries::default(),
204204
sync_table: SyncTable::new(index),
205+
config: PhantomData,
205206
}
206207
}
207208

@@ -258,16 +259,7 @@ where
258259
// FIXME: Use `Box::into_non_null` once stable
259260
let memo = NonNull::from(Box::leak(Box::new(memo)));
260261

261-
if let Some(old_value) =
262-
self.insert_memo_into_table_for(zalsa, id, memo, memo_ingredient_index)
263-
{
264-
// In case there is a reference to the old memo out there, we have to store it
265-
// in the deleted entries. This will get cleared when a new revision starts.
266-
//
267-
// SAFETY: Once the revision starts, there will be no outstanding borrows to the
268-
// memo contents, and so it will be safe to free.
269-
unsafe { self.deleted_entries.push(old_value) };
270-
}
262+
self.insert_memo_into_table_for(zalsa, id, memo, memo_ingredient_index);
271263
// SAFETY: memo has been inserted into the table
272264
unsafe { self.extend_memo_lifetime(memo.as_ref()) }
273265
}
@@ -464,16 +456,19 @@ where
464456
true
465457
}
466458

467-
fn reset_for_new_revision(&mut self, table: &mut Table) {
459+
fn reset_for_new_revision(
460+
&mut self,
461+
table: &mut Table,
462+
new_buffer: DeletedEntries,
463+
) -> DeletedEntries {
468464
self.lru.for_each_evicted(|evict| {
469465
let ingredient_index = table.ingredient_index(evict);
470466
Self::evict_value_from_memo_for(
471467
table.memos_mut(evict),
472468
self.memo_ingredient_indices.get(ingredient_index),
473469
)
474470
});
475-
476-
self.deleted_entries.clear();
471+
mem::replace(&mut self.delete, new_buffer)
477472
}
478473

479474
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
@@ -20,24 +20,23 @@ use crate::{Event, EventKind, Id, Revision};
2020
impl<C: Configuration> IngredientImpl<C> {
2121
/// Inserts the memo for the given key; (atomically) overwrites and returns any previously existing memo
2222
pub(super) fn insert_memo_into_table_for<'db>(
23-
&self,
23+
&'db self,
2424
zalsa: &'db Zalsa,
2525
id: Id,
2626
memo: NonNull<Memo<'db, C>>,
2727
memo_ingredient_index: MemoIngredientIndex,
28-
) -> Option<NonNull<Memo<'db, C>>> {
28+
) {
2929
// SAFETY: The table stores 'static memos (to support `Any`), the memos are in fact valid
3030
// for `'db` though as we delay their dropping to the end of a revision.
3131
let static_memo =
3232
unsafe { transmute::<NonNull<Memo<'db, C>>, NonNull<Memo<'static, C>>>(memo) };
3333
let old_static_memo = zalsa
3434
.memo_table_for::<C::SalsaStruct<'_>>(id)
35-
.insert(memo_ingredient_index, static_memo)?;
36-
// SAFETY: The table stores 'static memos (to support `Any`), the memos are in fact valid
37-
// for `'db` though as we delay their dropping to the end of a revision.
38-
Some(unsafe {
39-
transmute::<NonNull<Memo<'static, C>>, NonNull<Memo<'db, C>>>(old_static_memo)
40-
})
35+
.insert(memo_ingredient_index, static_memo);
36+
if let Some(old_memo) = old_static_memo {
37+
// SAFETY: We delay clearing properly
38+
unsafe { self.delete.push(old_memo) };
39+
}
4140
}
4241

4342
/// Loads the current memo for `key_index`. This does not hold any sort of
@@ -63,9 +62,10 @@ impl<C: Configuration> IngredientImpl<C> {
6362
pub(super) fn evict_value_from_memo_for(
6463
table: MemoTableWithTypesMut<'_>,
6564
memo_ingredient_index: MemoIngredientIndex,
65+
//FIXME should provide a page to move the value into so we can delay the drop
6666
) {
67-
let map = |memo: &mut Memo<'static, C>| {
68-
match memo.revisions.origin.as_ref() {
67+
if let Some(memo) = table.fetch::<Memo<'static, C>>(memo_ingredient_index) {
68+
match &memo.revisions.origin.as_ref() {
6969
QueryOriginRef::Assigned(_)
7070
| QueryOriginRef::DerivedUntracked(_)
7171
| QueryOriginRef::FixpointInitial => {
@@ -74,14 +74,9 @@ impl<C: Configuration> IngredientImpl<C> {
7474
// or those with untracked inputs
7575
// as their values cannot be reconstructed.
7676
}
77-
QueryOriginRef::Derived(_) => {
78-
// Set the memo value to `None`.
79-
memo.value = None;
80-
}
77+
QueryOriginRef::Derived(_) => _ = memo.value.take(),
8178
}
82-
};
83-
84-
table.map_memo(memo_ingredient_index, map)
79+
}
8580
}
8681
}
8782

@@ -285,6 +280,10 @@ where
285280
},
286281
}
287282
}
283+
284+
fn clear_value(&mut self) {
285+
self.value = None;
286+
}
288287
}
289288

290289
#[cfg(feature = "persistence")]

src/ingredient.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::function::{VerifyCycleHeads, VerifyResult};
77
use crate::hash::{FxHashSet, FxIndexSet};
88
use crate::runtime::Running;
99
use crate::sync::Arc;
10-
use crate::table::memo::MemoTableTypes;
10+
use crate::table::memo::{DeletedEntries, MemoTableTypes};
1111
use crate::table::Table;
1212
use crate::zalsa::{transmute_data_mut_ptr, transmute_data_ptr, IngredientIndex, JarKind, Zalsa};
1313
use crate::zalsa_local::{QueryEdge, QueryOriginRef};
@@ -147,8 +147,12 @@ pub trait Ingredient: Any + std::fmt::Debug + Send + Sync {
147147
///
148148
/// **Important:** to actually receive resets, the ingredient must set
149149
/// [`IngredientRequiresReset::RESET_ON_NEW_REVISION`] to true.
150-
fn reset_for_new_revision(&mut self, table: &mut Table) {
151-
_ = table;
150+
fn reset_for_new_revision(
151+
&mut self,
152+
table: &mut Table,
153+
new_buffer: DeletedEntries,
154+
) -> DeletedEntries {
155+
_ = (table, new_buffer);
152156
panic!(
153157
"Ingredient `{}` set `Ingredient::requires_reset_for_new_revision` to true but does \
154158
not overwrite `Ingredient::reset_for_new_revision`",

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pub use self::revision::Revision;
6161
pub use self::runtime::Runtime;
6262
pub use self::storage::{Storage, StorageHandle};
6363
pub use self::update::Update;
64-
pub use self::zalsa::IngredientIndex;
64+
pub use self::zalsa::{DeletedEntriesDropper, DropChannelReceiver, IngredientIndex};
6565
pub use crate::attach::{attach, attach_allow_change, with_attached_database};
6666

6767
pub mod prelude {

src/runtime.rs

Lines changed: 11 additions & 0 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, SyncOwner};
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};
@@ -245,6 +247,7 @@ impl Runtime {
245247
&self.table
246248
}
247249

250+
#[inline]
248251
pub(crate) fn table_mut(&mut self) -> &mut Table {
249252
&mut self.table
250253
}
@@ -401,4 +404,12 @@ impl Runtime {
401404
// The only field that is serialized is `revisions`.
402405
self.revisions = other.revisions;
403406
}
407+
408+
pub(crate) fn reset_ingredient_for_new_revision(
409+
&mut self,
410+
ingredient: &mut (dyn Ingredient + 'static),
411+
new_buffer: DeletedEntries,
412+
) -> DeletedEntries {
413+
ingredient.reset_for_new_revision(&mut self.table, new_buffer)
414+
}
404415
}

0 commit comments

Comments
 (0)