Skip to content

Commit fd4a392

Browse files
committed
Per ingredient sync table
1 parent 638a094 commit fd4a392

File tree

10 files changed

+46
-118
lines changed

10 files changed

+46
-118
lines changed

src/function.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{any::Any, fmt, sync::Arc};
33
use crate::{
44
accumulator::accumulated_map::AccumulatedMap,
55
cycle::CycleRecoveryStrategy,
6+
function::sync::SyncTable,
67
ingredient::fmt_index,
78
key::DatabaseKeyIndex,
89
plumbing::JarAux,
@@ -27,6 +28,7 @@ mod lru;
2728
mod maybe_changed_after;
2829
mod memo;
2930
mod specify;
31+
mod sync;
3032

3133
pub trait Configuration: Any {
3234
const DEBUG_NAME: &'static str;
@@ -100,6 +102,8 @@ pub struct IngredientImpl<C: Configuration> {
100102
/// Used to find memos to throw out when we have too many memoized values.
101103
lru: lru::Lru,
102104

105+
sync_table: SyncTable,
106+
103107
/// When `fetch` and friends executes, they return a reference to the
104108
/// value stored in the memo that is extended to live as long as the `&self`
105109
/// reference we start with. This means that whenever we remove something
@@ -132,6 +136,7 @@ where
132136
memo_ingredient_index: aux.next_memo_ingredient_index(struct_index, index),
133137
lru: Default::default(),
134138
deleted_entries: Default::default(),
139+
sync_table: Default::default(),
135140
}
136141
}
137142

src/function/fetch.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,18 @@ where
6565
let database_key_index = self.database_key_index(id);
6666

6767
// Try to claim this query: if someone else has claimed it already, go back and start again.
68-
let _claim_guard = zalsa.sync_table_for(id).claim(
68+
let _claim_guard = self.sync_table.try_claim(
6969
db.as_dyn_database(),
7070
zalsa_local,
71+
zalsa,
7172
database_key_index,
72-
self.memo_ingredient_index,
73+
id,
7374
)?;
7475

7576
// Push the query on the stack.
7677
let active_query = zalsa_local.push_query(database_key_index);
7778

7879
// Now that we've claimed the item, check again to see if there's a "hot" value.
79-
let zalsa = db.zalsa();
8080
let opt_old_memo = self.get_memo_from_table_for(zalsa, id);
8181
if let Some(old_memo) = &opt_old_memo {
8282
if old_memo.value.is_some() && self.deep_verify_memo(db, old_memo, &active_query) {

src/function/maybe_changed_after.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ where
5353
let (zalsa, zalsa_local) = db.zalsas();
5454
let database_key_index = self.database_key_index(key_index);
5555

56-
let _claim_guard = zalsa.sync_table_for(key_index).claim(
56+
let _claim_guard = self.sync_table.try_claim(
5757
db.as_dyn_database(),
5858
zalsa_local,
59+
zalsa,
5960
database_key_index,
60-
self.memo_ingredient_index,
61+
key_index,
6162
)?;
6263
let active_query = zalsa_local.push_query(database_key_index);
6364

src/table/sync.rs renamed to src/function/sync.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,18 @@ use std::{
33
thread::ThreadId,
44
};
55

6-
use parking_lot::RwLock;
6+
use parking_lot::Mutex;
7+
use rustc_hash::FxHashMap;
78

89
use crate::{
9-
key::DatabaseKeyIndex,
10-
runtime::WaitResult,
11-
zalsa::{MemoIngredientIndex, Zalsa},
12-
zalsa_local::ZalsaLocal,
13-
Database,
10+
key::DatabaseKeyIndex, runtime::WaitResult, zalsa::Zalsa, zalsa_local::ZalsaLocal, Database, Id,
1411
};
1512

16-
use super::util;
17-
1813
/// Tracks the keys that are currently being processed; used to coordinate between
1914
/// worker threads.
2015
#[derive(Default)]
2116
pub(crate) struct SyncTable {
22-
syncs: RwLock<Vec<Option<SyncState>>>,
17+
syncs: Mutex<FxHashMap<Id, SyncState>>,
2318
}
2419

2520
struct SyncState {
@@ -31,46 +26,43 @@ struct SyncState {
3126
}
3227

3328
impl SyncTable {
34-
pub(crate) fn claim<'me>(
29+
pub(crate) fn try_claim<'me>(
3530
&'me self,
3631
db: &'me dyn Database,
3732
zalsa_local: &ZalsaLocal,
33+
zalsa: &'me Zalsa,
3834
database_key_index: DatabaseKeyIndex,
39-
memo_ingredient_index: MemoIngredientIndex,
35+
id: Id,
4036
) -> Option<ClaimGuard<'me>> {
41-
let mut syncs = self.syncs.write();
42-
let zalsa = db.zalsa();
43-
let thread_id = std::thread::current().id();
44-
45-
util::ensure_vec_len(&mut syncs, memo_ingredient_index.as_usize() + 1);
46-
47-
match &syncs[memo_ingredient_index.as_usize()] {
48-
None => {
49-
syncs[memo_ingredient_index.as_usize()] = Some(SyncState {
50-
id: thread_id,
51-
anyone_waiting: AtomicBool::new(false),
52-
});
53-
Some(ClaimGuard {
54-
database_key_index,
55-
memo_ingredient_index,
56-
zalsa,
57-
sync_table: self,
58-
})
59-
}
60-
Some(SyncState {
61-
id: other_id,
62-
anyone_waiting,
63-
}) => {
37+
let mut write = self.syncs.lock();
38+
match write.entry(id) {
39+
std::collections::hash_map::Entry::Occupied(occupied_entry) => {
40+
let &mut SyncState {
41+
id,
42+
ref anyone_waiting,
43+
} = occupied_entry.into_mut();
6444
// NB: `Ordering::Relaxed` is sufficient here,
6545
// as there are no loads that are "gated" on this
6646
// value. Everything that is written is also protected
6747
// by a lock that must be acquired. The role of this
6848
// boolean is to decide *whether* to acquire the lock,
6949
// not to gate future atomic reads.
7050
anyone_waiting.store(true, Ordering::Relaxed);
71-
zalsa.block_on_or_unwind(db, zalsa_local, database_key_index, *other_id, syncs);
51+
zalsa.block_on_or_unwind(db, zalsa_local, database_key_index, id, write);
7252
None
7353
}
54+
std::collections::hash_map::Entry::Vacant(vacant_entry) => {
55+
vacant_entry.insert(SyncState {
56+
id: std::thread::current().id(),
57+
anyone_waiting: AtomicBool::new(false),
58+
});
59+
Some(ClaimGuard {
60+
database_key_index,
61+
id,
62+
zalsa,
63+
sync_table: self,
64+
})
65+
}
7466
}
7567
}
7668
}
@@ -80,17 +72,18 @@ impl SyncTable {
8072
#[must_use]
8173
pub(crate) struct ClaimGuard<'me> {
8274
database_key_index: DatabaseKeyIndex,
83-
memo_ingredient_index: MemoIngredientIndex,
75+
id: Id,
8476
zalsa: &'me Zalsa,
8577
sync_table: &'me SyncTable,
8678
}
8779

8880
impl ClaimGuard<'_> {
8981
fn remove_from_map_and_unblock_queries(&self, wait_result: WaitResult) {
90-
let mut syncs = self.sync_table.syncs.write();
82+
let mut syncs = self.sync_table.syncs.lock();
83+
84+
let SyncState { anyone_waiting, .. } = syncs.remove(&self.id).unwrap();
9185

92-
let SyncState { anyone_waiting, .. } =
93-
syncs[self.memo_ingredient_index.as_usize()].take().unwrap();
86+
drop(syncs);
9487

9588
// NB: `Ordering::Relaxed` is sufficient here,
9689
// see `store` above for explanation.

src/input.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{
1818
ingredient::{fmt_index, Ingredient},
1919
key::{DatabaseKeyIndex, InputDependencyIndex},
2020
plumbing::{Jar, JarAux, Stamp},
21-
table::{memo::MemoTable, sync::SyncTable, Slot, Table},
21+
table::{memo::MemoTable, Slot, Table},
2222
zalsa::{IngredientIndex, Zalsa},
2323
zalsa_local::QueryOrigin,
2424
Database, Durability, Id, Revision, Runtime,
@@ -121,7 +121,6 @@ impl<C: Configuration> IngredientImpl<C> {
121121
fields,
122122
stamps,
123123
memos: Default::default(),
124-
syncs: Default::default(),
125124
});
126125

127126
if C::IS_SINGLETON {
@@ -299,9 +298,6 @@ where
299298

300299
/// Memos
301300
memos: MemoTable,
302-
303-
/// Syncs
304-
syncs: SyncTable,
305301
}
306302

307303
pub trait HasBuilder {
@@ -315,8 +311,4 @@ where
315311
unsafe fn memos(&self, _current_revision: Revision) -> &crate::table::memo::MemoTable {
316312
&self.memos
317313
}
318-
319-
unsafe fn syncs(&self, _current_revision: Revision) -> &SyncTable {
320-
&self.syncs
321-
}
322314
}

src/interned.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::ingredient::fmt_index;
55
use crate::key::InputDependencyIndex;
66
use crate::plumbing::{Jar, JarAux};
77
use crate::table::memo::MemoTable;
8-
use crate::table::sync::SyncTable;
98
use crate::table::Slot;
109
use crate::zalsa::IngredientIndex;
1110
use crate::zalsa_local::QueryOrigin;
@@ -75,7 +74,6 @@ where
7574
{
7675
data: C::Data<'static>,
7776
memos: MemoTable,
78-
syncs: SyncTable,
7977
}
8078

8179
impl<C: Configuration> Default for JarImpl<C> {
@@ -183,7 +181,6 @@ where
183181
let next_id = zalsa_local.allocate(table, self.ingredient_index, || Value::<C> {
184182
data: internal_data,
185183
memos: Default::default(),
186-
syncs: Default::default(),
187184
});
188185
entry.insert(next_id);
189186
C::struct_from_id(next_id)
@@ -302,10 +299,6 @@ where
302299
unsafe fn memos(&self, _current_revision: Revision) -> &MemoTable {
303300
&self.memos
304301
}
305-
306-
unsafe fn syncs(&self, _current_revision: Revision) -> &crate::table::sync::SyncTable {
307-
&self.syncs
308-
}
309302
}
310303

311304
/// The `Lookup` trait is a more flexible variant on [`std::borrow::Borrow`]

src/table.rs

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,10 @@ use std::{
1010
use append_only_vec::AppendOnlyVec;
1111
use memo::MemoTable;
1212
use parking_lot::Mutex;
13-
use sync::SyncTable;
1413

1514
use crate::{zalsa::transmute_data_ptr, Id, IngredientIndex, Revision};
1615

1716
pub(crate) mod memo;
18-
pub(crate) mod sync;
19-
mod util;
2017

2118
const PAGE_LEN_BITS: usize = 10;
2219
const PAGE_LEN_MASK: usize = PAGE_LEN - 1;
@@ -36,13 +33,6 @@ pub(crate) trait TablePage: Any + Send + Sync {
3633
///
3734
/// The `current_revision` MUST be the current revision of the database owning this table page.
3835
unsafe fn memos(&self, slot: SlotIndex, current_revision: Revision) -> &MemoTable;
39-
40-
/// Access the syncs attached to `slot`.
41-
///
42-
/// # Safety condition
43-
///
44-
/// The `current_revision` MUST be the current revision of the database owning this table page.
45-
unsafe fn syncs(&self, slot: SlotIndex, current_revision: Revision) -> &SyncTable;
4636
}
4737

4838
pub(crate) struct Page<T: Slot> {
@@ -74,13 +64,6 @@ pub(crate) trait Slot: Any + Send + Sync {
7464
///
7565
/// The current revision MUST be the current revision of the database containing this slot.
7666
unsafe fn memos(&self, current_revision: Revision) -> &MemoTable;
77-
78-
/// Access the [`SyncTable`][] for this slot.
79-
///
80-
/// # Safety condition
81-
///
82-
/// The current revision MUST be the current revision of the database containing this slot.
83-
unsafe fn syncs(&self, current_revision: Revision) -> &SyncTable;
8467
}
8568

8669
unsafe impl<T: Slot> Send for Page<T> {}
@@ -169,17 +152,6 @@ impl Table {
169152
let (page, slot) = split_id(id);
170153
self.pages[page.0].memos(slot, current_revision)
171154
}
172-
173-
/// Get the sync table associated with `id`
174-
///
175-
/// # Safety condition
176-
///
177-
/// The parameter `current_revision` MUST be the current revision
178-
/// of the owner of database owning this table.
179-
pub unsafe fn syncs(&self, id: Id, current_revision: Revision) -> &SyncTable {
180-
let (page, slot) = split_id(id);
181-
self.pages[page.0].syncs(slot, current_revision)
182-
}
183155
}
184156

185157
impl<T: Slot> Page<T> {
@@ -256,10 +228,6 @@ impl<T: Slot> TablePage for Page<T> {
256228
unsafe fn memos(&self, slot: SlotIndex, current_revision: Revision) -> &MemoTable {
257229
self.get(slot).memos(current_revision)
258230
}
259-
260-
unsafe fn syncs(&self, slot: SlotIndex, current_revision: Revision) -> &SyncTable {
261-
self.get(slot).syncs(current_revision)
262-
}
263231
}
264232

265233
impl<T: Slot> Drop for Page<T> {

src/table/util.rs

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

src/tracked_struct.rs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
plumbing::ZalsaLocal,
1212
runtime::StampedValue,
1313
salsa_struct::SalsaStructInDb,
14-
table::{memo::MemoTable, sync::SyncTable, Slot, Table},
14+
table::{memo::MemoTable, Slot, Table},
1515
zalsa::{IngredientIndex, Zalsa},
1616
zalsa_local::QueryOrigin,
1717
Database, Durability, Event, EventKind, Id, Revision,
@@ -225,9 +225,6 @@ where
225225

226226
/// Memo table storing the results of query functions etc.
227227
memos: MemoTable,
228-
229-
/// Sync table storing the results of query functions etc.
230-
syncs: SyncTable,
231228
}
232229
// ANCHOR_END: ValueStruct
233230

@@ -326,7 +323,6 @@ where
326323
fields: unsafe { self.to_static(fields) },
327324
revisions: C::new_revisions(current_deps.changed_at),
328325
memos: Default::default(),
329-
syncs: Default::default(),
330326
};
331327

332328
if let Some(id) = self.free_list.pop() {
@@ -695,12 +691,4 @@ where
695691
self.read_lock(current_revision);
696692
&self.memos
697693
}
698-
699-
unsafe fn syncs(&self, current_revision: Revision) -> &crate::table::sync::SyncTable {
700-
// Acquiring the read lock here with the current revision
701-
// ensures that there is no danger of a race
702-
// when deleting a tracked struct.
703-
self.read_lock(current_revision);
704-
&self.syncs
705-
}
706694
}

0 commit comments

Comments
 (0)