Skip to content

Commit 164ed5a

Browse files
committed
Drop unnecessary locking in Lru::for_each_evicted
1 parent f04552d commit 164ed5a

File tree

3 files changed

+46
-30
lines changed

3 files changed

+46
-30
lines changed

src/function.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,13 @@ where
231231
}
232232

233233
fn reset_for_new_revision(&mut self, table: &mut Table) {
234-
self.lru
235-
.for_each_evicted(|evict| self.evict_value_from_memo_for(table.memos_mut(evict)));
234+
self.lru.for_each_evicted(|evict| {
235+
Self::evict_value_from_memo_for(
236+
table.memos_mut(evict),
237+
self.memo_ingredient_index,
238+
&self.delete,
239+
)
240+
});
236241
}
237242

238243
fn fmt_index(&self, index: Option<crate::Id>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {

src/function/lru.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ impl Lru {
2626
self.capacity.store(capacity);
2727
}
2828

29-
pub(super) fn for_each_evicted(&self, mut cb: impl FnMut(Id)) {
30-
let mut set = self.set.lock();
29+
pub(super) fn for_each_evicted(&mut self, mut cb: impl FnMut(Id)) {
30+
let set = self.set.get_mut();
3131
let cap = self.capacity.load();
3232
if set.len() <= cap || cap == 0 {
3333
return;

src/function/memo.rs

+37-26
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use std::sync::Arc;
77
use crossbeam::atomic::AtomicCell;
88

99
use crate::accumulator::accumulated_map::InputAccumulatedValues;
10+
use crate::plumbing::MemoDropSender;
1011
use crate::table::memo::MemoTable;
12+
use crate::zalsa::MemoIngredientIndex;
1113
use crate::zalsa_local::QueryOrigin;
1214
use crate::{
1315
key::DatabaseKeyIndex, zalsa::Zalsa, zalsa_local::QueryRevisions, Event, EventKind, Id,
@@ -68,7 +70,11 @@ impl<C: Configuration> IngredientImpl<C> {
6870
/// Evicts the existing memo for the given key, replacing it
6971
/// with an equivalent memo that has no value. If the memo is untracked, BaseInput,
7072
/// or has values assigned as output of another query, this has no effect.
71-
pub(super) fn evict_value_from_memo_for(&self, table: &mut MemoTable) {
73+
pub(super) fn evict_value_from_memo_for(
74+
table: &mut MemoTable,
75+
memo_ingredient_index: MemoIngredientIndex,
76+
memo_drop: &MemoDropSender,
77+
) {
7278
let map = |memo: ArcMemo<'static, C>| -> ArcMemo<'static, C> {
7379
match &memo.revisions.origin {
7480
QueryOrigin::Assigned(_)
@@ -82,37 +88,17 @@ impl<C: Configuration> IngredientImpl<C> {
8288
}
8389
QueryOrigin::Derived(_) => {
8490
// Note that we cannot use `Arc::get_mut` here as the use of `ArcSwap` makes it
85-
// impossible to get unique access to the interior Arc
86-
// QueryRevisions: !Clone to discourage cloning, we need it here though
87-
let &QueryRevisions {
88-
changed_at,
89-
durability,
90-
ref origin,
91-
ref tracked_struct_ids,
92-
ref accumulated,
93-
ref accumulated_inputs,
94-
} = &memo.revisions;
95-
// Re-assemble the memo but with the value set to `None`
96-
Arc::new(Memo::new(
97-
None,
98-
memo.verified_at.load(),
99-
QueryRevisions {
100-
changed_at,
101-
durability,
102-
origin: origin.clone(),
103-
tracked_struct_ids: tracked_struct_ids.clone(),
104-
accumulated: accumulated.clone(),
105-
accumulated_inputs: AtomicCell::new(accumulated_inputs.load()),
106-
},
107-
))
91+
// impossible to get unique access to the interior Arc so we need to construct
92+
// a new allocation
93+
Arc::new(memo.without_value())
10894
}
10995
}
11096
};
11197
// SAFETY: We queue the old value for deletion, delaying its drop until the next revision
11298
// bump.
113-
let old_memo = unsafe { table.map_memo(self.memo_ingredient_index, map) };
99+
let old_memo = unsafe { table.map_memo(memo_ingredient_index, map) };
114100
if let Some(old_memo) = old_memo {
115-
self.delete.delay(ManuallyDrop::into_inner(old_memo));
101+
memo_drop.delay(ManuallyDrop::into_inner(old_memo));
116102
}
117103
}
118104
}
@@ -143,6 +129,31 @@ impl<V> Memo<V> {
143129
revisions,
144130
}
145131
}
132+
133+
pub(super) fn without_value(&self) -> Self {
134+
let &QueryRevisions {
135+
changed_at,
136+
durability,
137+
ref origin,
138+
ref tracked_struct_ids,
139+
ref accumulated,
140+
ref accumulated_inputs,
141+
} = &self.revisions;
142+
// Re-assemble the memo but with the value set to `None`
143+
Memo::new(
144+
None,
145+
self.verified_at.load(),
146+
QueryRevisions {
147+
changed_at,
148+
durability,
149+
origin: origin.clone(),
150+
tracked_struct_ids: tracked_struct_ids.clone(),
151+
accumulated: accumulated.clone(),
152+
accumulated_inputs: AtomicCell::new(accumulated_inputs.load()),
153+
},
154+
)
155+
}
156+
146157
/// True if this memo is known not to have changed based on its durability.
147158
pub(super) fn check_durability(&self, zalsa: &Zalsa) -> bool {
148159
let last_changed = zalsa.last_changed_revision(self.revisions.durability);

0 commit comments

Comments
 (0)