This commit is contained in:
Lukas Wirth 2024-02-07 16:30:00 +01:00
parent 159a03ad7b
commit 0a6197df97
21 changed files with 128 additions and 365 deletions

View File

@ -108,9 +108,7 @@ fn slot(&self, key: &Q::Key) -> Arc<Slot<Q, MP>> {
query_index: Q::QUERY_INDEX,
key_index,
};
entry
.or_insert_with(|| Arc::new(Slot::new(key.clone(), database_key_index)))
.clone()
entry.or_insert_with(|| Arc::new(Slot::new(key.clone(), database_key_index))).clone()
}
}
@ -152,13 +150,7 @@ fn maybe_changed_after(
assert_eq!(input.group_index, self.group_index);
assert_eq!(input.query_index, Q::QUERY_INDEX);
debug_assert!(revision < db.salsa_runtime().current_revision());
let slot = self
.slot_map
.read()
.get_index(input.key_index as usize)
.unwrap()
.1
.clone();
let slot = self.slot_map.read().get_index(input.key_index as usize).unwrap().1.clone();
slot.maybe_changed_after(db, revision)
}
@ -166,22 +158,17 @@ fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
db.unwind_if_cancelled();
let slot = self.slot(key);
let StampedValue {
value,
durability,
changed_at,
} = slot.read(db);
let StampedValue { value, durability, changed_at } = slot.read(db);
if let Some(evicted) = self.lru_list.record_use(&slot) {
evicted.evict();
}
db.salsa_runtime()
.report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index(),
durability,
changed_at,
);
db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index(),
durability,
changed_at,
);
value
}
@ -195,10 +182,7 @@ fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
{
let slot_map = self.slot_map.read();
slot_map
.values()
.filter_map(|slot| slot.as_table_entry())
.collect()
slot_map.values().filter_map(|slot| slot.as_table_entry()).collect()
}
}

View File

@ -209,14 +209,7 @@ fn read_upgrade(
}
}
self.execute(
db,
runtime,
revision_now,
active_query,
panic_guard,
old_memo,
)
self.execute(db, runtime, revision_now, active_query, panic_guard, old_memo)
}
fn execute(
@ -232,9 +225,7 @@ fn execute(
db.salsa_event(Event {
runtime_id: db.salsa_runtime().id(),
kind: EventKind::WillExecute {
database_key: self.database_key_index,
},
kind: EventKind::WillExecute { database_key: self.database_key_index },
});
// Query was not previously executed, or value is potentially
@ -310,22 +301,12 @@ fn execute(
changed_at: revisions.changed_at,
};
let memo_value = if self.should_memoize_value(&self.key) {
Some(new_value.value.clone())
} else {
None
};
let memo_value =
if self.should_memoize_value(&self.key) { Some(new_value.value.clone()) } else { None };
debug!(
"read_upgrade({:?}): result.revisions = {:#?}",
self, revisions,
);
debug!("read_upgrade({:?}): result.revisions = {:#?}", self, revisions,);
panic_guard.proceed(Some(Memo {
value: memo_value,
verified_at: revision_now,
revisions,
}));
panic_guard.proceed(Some(Memo { value: memo_value, verified_at: revision_now, revisions }));
new_value
}
@ -388,10 +369,7 @@ fn probe<StateGuard>(
value: value.clone(),
};
info!(
"{:?}: returning memoized value changed at {:?}",
self, value.changed_at
);
info!("{:?}: returning memoized value changed at {:?}", self, value.changed_at);
ProbeState::UpToDate(value)
} else {
@ -503,11 +481,9 @@ fn maybe_changed_after_probe<StateGuard>(
// If we know when value last changed, we can return right away.
// Note that we don't need the actual value to be available.
ProbeState::NoValue(_, changed_at)
| ProbeState::UpToDate(StampedValue {
value: _,
durability: _,
changed_at,
}) => MaybeChangedSinceProbeState::ChangedAt(changed_at),
| ProbeState::UpToDate(StampedValue { value: _, durability: _, changed_at }) => {
MaybeChangedSinceProbeState::ChangedAt(changed_at)
}
// If we have nothing cached, then value may have changed.
ProbeState::NotComputed(_) => MaybeChangedSinceProbeState::ChangedAt(revision_now),
@ -561,14 +537,8 @@ fn maybe_changed_after_upgrade(
// We found that this memoized value may have changed
// but we have an old value. We can re-run the code and
// actually *check* if it has changed.
let StampedValue { changed_at, .. } = self.execute(
db,
runtime,
revision_now,
active_query,
panic_guard,
Some(old_memo),
);
let StampedValue { changed_at, .. } =
self.execute(db, runtime, revision_now, active_query, panic_guard, Some(old_memo));
changed_at > revision
} else {
// We found that inputs to this memoized value may have chanced
@ -605,10 +575,7 @@ impl<Q> QueryState<Q>
Q: QueryFunction,
{
fn in_progress(id: RuntimeId) -> Self {
QueryState::InProgress {
id,
anyone_waiting: Default::default(),
}
QueryState::InProgress { id, anyone_waiting: Default::default() }
}
}
@ -632,11 +599,7 @@ fn new(
slot: &'me Slot<Q, MP>,
runtime: &'me Runtime,
) -> Self {
Self {
database_key_index,
slot,
runtime,
}
Self { database_key_index, slot, runtime }
}
/// Indicates that we have concluded normally (without panicking).
@ -674,8 +637,7 @@ fn overwrite_placeholder(&mut self, wait_result: WaitResult, opt_memo: Option<Me
// acquire a mutex; the mutex will guarantee that all writes
// we are interested in are visible.
if anyone_waiting.load(Ordering::Relaxed) {
self.runtime
.unblock_queries_blocked_on(self.database_key_index, wait_result);
self.runtime.unblock_queries_blocked_on(self.database_key_index, wait_result);
}
}
_ => panic!(
@ -784,9 +746,8 @@ fn verify_revisions(
// are only interested in finding out whether the
// input changed *again*.
QueryInputs::Tracked { inputs } => {
let changed_input = inputs
.iter()
.find(|&&input| db.maybe_changed_after(input, verified_at));
let changed_input =
inputs.iter().find(|&&input| db.maybe_changed_after(input, verified_at));
if let Some(input) = changed_input {
debug!("validate_memoized_value: `{:?}` may have changed", input);

View File

@ -50,10 +50,7 @@ impl<Q> QueryStorageOps<Q> for InputStorage<Q>
const CYCLE_STRATEGY: crate::plumbing::CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
fn new(group_index: u16) -> Self {
InputStorage {
group_index,
slots: Default::default(),
}
InputStorage { group_index, slots: Default::default() }
}
fn fmt_index(
@ -91,18 +88,13 @@ fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
.get(key)
.unwrap_or_else(|| panic!("no value set for {:?}({:?})", Q::default(), key));
let StampedValue {
value,
let StampedValue { value, durability, changed_at } = slot.stamped_value.read().clone();
db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index,
durability,
changed_at,
} = slot.stamped_value.read().clone();
db.salsa_runtime()
.report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index,
durability,
changed_at,
);
);
value
}
@ -133,10 +125,7 @@ impl<Q> Slot<Q>
Q: Query,
{
fn maybe_changed_after(&self, _db: &<Q as QueryDb<'_>>::DynDb, revision: Revision) -> bool {
debug!(
"maybe_changed_after(slot={:?}, revision={:?})",
self, revision,
);
debug!("maybe_changed_after(slot={:?}, revision={:?})", self, revision,);
let changed_at = self.stamped_value.read().changed_at;
@ -160,13 +149,7 @@ impl<Q> InputQueryStorageOps<Q> for InputStorage<Q>
Q: Query,
{
fn set(&self, runtime: &mut Runtime, key: &Q::Key, value: Q::Value, durability: Durability) {
tracing::debug!(
"{:?}({:?}) = {:?} ({:?})",
Q::default(),
key,
value,
durability
);
tracing::debug!("{:?}({:?}) = {:?} ({:?})", Q::default(), key, value, durability);
// The value is changing, so we need a new revision (*). We also
// need to update the 'last changed' revision by invoking
@ -190,11 +173,7 @@ fn set(&self, runtime: &mut Runtime, key: &Q::Key, value: Q::Value, durability:
// racing with somebody else to modify this same cell.
// (Otherwise, someone else might write a *newer* revision
// into the same cell while we block on the lock.)
let stamped_value = StampedValue {
value,
durability,
changed_at: next_revision,
};
let stamped_value = StampedValue { value, durability, changed_at: next_revision };
match slots.entry(key.clone()) {
Entry::Occupied(entry) => {

View File

@ -63,9 +63,7 @@ impl InternId {
/// `value` must be less than `MAX`
pub const unsafe fn new_unchecked(value: u32) -> Self {
debug_assert!(value < InternId::MAX);
InternId {
value: NonZeroU32::new_unchecked(value + 1),
}
InternId { value: NonZeroU32::new_unchecked(value + 1) }
}
/// Convert this raw-id into a u32 value.

View File

@ -110,10 +110,7 @@ impl<K> Default for InternTables<K>
K: Eq + Hash,
{
fn default() -> Self {
Self {
map: Default::default(),
values: Default::default(),
}
Self { map: Default::default(), values: Default::default() }
}
}
@ -159,11 +156,7 @@ fn intern_index(
query_index: Q::QUERY_INDEX,
key_index: index.as_u32(),
};
Arc::new(Slot {
database_key_index,
value: owned_key2,
interned_at: revision_now,
})
Arc::new(Slot { database_key_index, value: owned_key2, interned_at: revision_now })
};
let (slot, index);
@ -194,10 +187,7 @@ impl<Q> QueryStorageOps<Q> for InternedStorage<Q>
const CYCLE_STRATEGY: crate::plumbing::CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
fn new(group_index: u16) -> Self {
InternedStorage {
group_index,
tables: RwLock::new(InternTables::default()),
}
InternedStorage { group_index, tables: RwLock::new(InternTables::default()) }
}
fn fmt_index(
@ -231,12 +221,11 @@ fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
db.unwind_if_cancelled();
let (slot, index) = self.intern_index(db, key);
let changed_at = slot.interned_at;
db.salsa_runtime()
.report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index,
INTERN_DURABILITY,
changed_at,
);
db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index,
INTERN_DURABILITY,
changed_at,
);
<Q::Value>::from_intern_id(index)
}
@ -313,9 +302,7 @@ impl<Q, IQ> QueryStorageOps<Q> for LookupInternedStorage<Q, IQ>
const CYCLE_STRATEGY: CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
fn new(_group_index: u16) -> Self {
LookupInternedStorage {
phantom: std::marker::PhantomData,
}
LookupInternedStorage { phantom: std::marker::PhantomData }
}
fn fmt_index(
@ -350,12 +337,11 @@ fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
let slot = interned_storage.lookup_value(index);
let value = slot.value.clone();
let interned_at = slot.interned_at;
db.salsa_runtime()
.report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index,
INTERN_DURABILITY,
interned_at,
);
db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
slot.database_key_index,
INTERN_DURABILITY,
interned_at,
);
value
}

View File

@ -216,18 +216,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
.debug_struct("DidValidateMemoizedValue")
.field("database_key", database_key)
.finish(),
EventKind::WillBlockOn {
other_runtime_id,
database_key,
} => fmt
EventKind::WillBlockOn { other_runtime_id, database_key } => fmt
.debug_struct("WillBlockOn")
.field("other_runtime_id", other_runtime_id)
.field("database_key", database_key)
.finish(),
EventKind::WillExecute { database_key } => fmt
.debug_struct("WillExecute")
.field("database_key", database_key)
.finish(),
EventKind::WillExecute { database_key } => {
fmt.debug_struct("WillExecute").field("database_key", database_key).finish()
}
EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(),
}
}
@ -251,10 +247,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
.debug_struct("DidValidateMemoizedValue")
.field("database_key", &database_key.debug(self.db))
.finish(),
EventKind::WillBlockOn {
other_runtime_id,
database_key,
} => fmt
EventKind::WillBlockOn { other_runtime_id, database_key } => fmt
.debug_struct("WillBlockOn")
.field("other_runtime_id", &other_runtime_id)
.field("database_key", &database_key.debug(self.db))
@ -707,9 +700,7 @@ pub fn participant_keys(&self) -> impl Iterator<Item = DatabaseKeyIndex> + '_ {
/// Returns a vector with the debug information for
/// all the participants in the cycle.
pub fn all_participants<DB: ?Sized + Database>(&self, db: &DB) -> Vec<String> {
self.participant_keys()
.map(|d| format!("{:?}", d.debug(db)))
.collect()
self.participant_keys().map(|d| format!("{:?}", d.debug(db))).collect()
}
/// Returns a vector with the debug information for
@ -733,18 +724,12 @@ impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fmt.debug_struct("UnexpectedCycle")
.field("all_participants", &self.c.all_participants(self.db))
.field(
"unexpected_participants",
&self.c.unexpected_participants(self.db),
)
.field("unexpected_participants", &self.c.unexpected_participants(self.db))
.finish()
}
}
UnexpectedCycleDebug {
c: self,
db: db.ops_database(),
}
UnexpectedCycleDebug { c: self, db: db.ops_database() }
}
}

View File

@ -68,10 +68,7 @@ pub fn new() -> Self {
#[cfg_attr(not(test), allow(dead_code))]
fn with_seed(seed: &str) -> Self {
Lru {
green_zone: AtomicUsize::new(0),
data: Mutex::new(LruData::with_seed(seed)),
}
Lru { green_zone: AtomicUsize::new(0), data: Mutex::new(LruData::with_seed(seed)) }
}
/// Adjust the total number of nodes permitted to have a value at
@ -143,13 +140,7 @@ fn with_seed(seed_str: &str) -> Self {
}
fn with_rng(rng: Rand64) -> Self {
LruData {
end_yellow_zone: 0,
end_green_zone: 0,
end_red_zone: 0,
entries: Vec::new(),
rng,
}
LruData { end_yellow_zone: 0, end_green_zone: 0, end_red_zone: 0, entries: Vec::new(), rng }
}
fn green_zone(&self) -> std::ops::Range<usize> {
@ -294,9 +285,7 @@ fn pick_index(&mut self, zone: std::ops::Range<usize>) -> usize {
impl Default for LruIndex {
fn default() -> Self {
Self {
index: AtomicUsize::new(std::usize::MAX),
}
Self { index: AtomicUsize::new(std::usize::MAX) }
}
}

View File

@ -78,10 +78,7 @@ fn cycle_fallback(
key: &Self::Key,
) -> Self::Value {
let _ = (db, cycle, key);
panic!(
"query `{:?}` doesn't support cycle fallback",
Self::default()
)
panic!("query `{:?}` doesn't support cycle fallback", Self::default())
}
}

View File

@ -21,9 +21,7 @@ pub(crate) fn start() -> Self {
}
pub(crate) fn from(g: u32) -> Self {
Self {
generation: NonZeroU32::new(g).unwrap(),
}
Self { generation: NonZeroU32::new(g).unwrap() }
}
pub(crate) fn next(self) -> Revision {
@ -48,9 +46,7 @@ pub(crate) struct AtomicRevision {
impl AtomicRevision {
pub(crate) fn start() -> Self {
Self {
data: AtomicU32::new(START),
}
Self { data: AtomicU32::new(START) }
}
pub(crate) fn load(&self) -> Revision {

View File

@ -85,9 +85,7 @@ pub(crate) fn snapshot(&self) -> Self {
let revision_guard = RevisionGuard::new(&self.shared_state);
let id = RuntimeId {
counter: self.shared_state.next_id.fetch_add(1, Ordering::SeqCst),
};
let id = RuntimeId { counter: self.shared_state.next_id.fetch_add(1, Ordering::SeqCst) };
Runtime {
id,
@ -242,8 +240,7 @@ pub(crate) fn report_query_read_and_unwind_if_cycle_resulted(
/// Queries which report untracked reads will be re-executed in the next
/// revision.
pub fn report_untracked_read(&self) {
self.local_state
.report_untracked_read(self.current_revision());
self.local_state.report_untracked_read(self.current_revision());
}
/// Acts as though the current query had read an input with the given durability; this will force the current query's durability to be at most `durability`.
@ -251,8 +248,7 @@ pub fn report_untracked_read(&self) {
/// This is mostly useful to control the durability level for [on-demand inputs](https://salsa-rs.github.io/salsa/common_patterns/on_demand_inputs.html).
pub fn report_synthetic_read(&self, durability: Durability) {
let changed_at = self.last_changed_revision(durability);
self.local_state
.report_synthetic_read(durability, changed_at);
self.local_state.report_synthetic_read(durability, changed_at);
}
/// Handles a cycle in the dependency graph that was detected when the
@ -270,10 +266,7 @@ fn unblock_cycle_and_maybe_throw(
database_key_index: DatabaseKeyIndex,
to_id: RuntimeId,
) {
debug!(
"unblock_cycle_and_maybe_throw(database_key={:?})",
database_key_index
);
debug!("unblock_cycle_and_maybe_throw(database_key={:?})", database_key_index);
let mut from_stack = self.local_state.take_query_stack();
let from_id = self.id();
@ -312,11 +305,7 @@ fn unblock_cycle_and_maybe_throw(
Cycle::new(Arc::new(v))
};
debug!(
"cycle {:?}, cycle_query {:#?}",
cycle.debug(db),
cycle_query,
);
debug!("cycle {:?}, cycle_query {:#?}", cycle.debug(db), cycle_query,);
// We can remove the cycle participants from the list of dependencies;
// they are a strongly connected component (SCC) and we only care about
@ -329,12 +318,10 @@ fn unblock_cycle_and_maybe_throw(
// are going to be unwound so that fallback can occur.
dg.for_each_cycle_participant(from_id, &mut from_stack, database_key_index, to_id, |aqs| {
aqs.iter_mut()
.skip_while(
|aq| match db.cycle_recovery_strategy(aq.database_key_index) {
CycleRecoveryStrategy::Panic => true,
CycleRecoveryStrategy::Fallback => false,
},
)
.skip_while(|aq| match db.cycle_recovery_strategy(aq.database_key_index) {
CycleRecoveryStrategy::Panic => true,
CycleRecoveryStrategy::Fallback => false,
})
.for_each(|aq| {
debug!("marking {:?} for fallback", aq.database_key_index.debug(db));
aq.take_inputs_from(&cycle_query);
@ -404,10 +391,7 @@ pub(crate) fn block_on_or_unwind<QueryMutexGuard>(
db.salsa_event(Event {
runtime_id: self.id(),
kind: EventKind::WillBlockOn {
other_runtime_id: other_id,
database_key,
},
kind: EventKind::WillBlockOn { other_runtime_id: other_id, database_key },
});
let stack = self.local_state.take_query_stack();
@ -585,18 +569,12 @@ pub(crate) fn revisions(&self) -> QueryRevisions {
if dependencies.is_empty() {
QueryInputs::NoInputs
} else {
QueryInputs::Tracked {
inputs: dependencies.iter().copied().collect(),
}
QueryInputs::Tracked { inputs: dependencies.iter().copied().collect() }
}
}
};
QueryRevisions {
changed_at: self.changed_at,
inputs,
durability: self.durability,
}
QueryRevisions { changed_at: self.changed_at, inputs, durability: self.durability }
}
/// Adds any dependencies from `other` into `self`.
@ -673,9 +651,7 @@ fn new(shared_state: &Arc<SharedState>) -> Self {
shared_state.query_lock.raw().lock_shared_recursive();
}
Self {
shared_state: shared_state.clone(),
}
Self { shared_state: shared_state.clone() }
}
}

View File

@ -103,21 +103,14 @@ pub(super) fn for_each_cycle_participant(
// load up the next thread (i.e., we start at B/QB2,
// and then load up the dependency on C/QC2).
let edge = self.edges.get_mut(&id).unwrap();
let prefix = edge
.stack
.iter_mut()
.take_while(|p| p.database_key_index != key)
.count();
let prefix = edge.stack.iter_mut().take_while(|p| p.database_key_index != key).count();
closure(&mut edge.stack[prefix..]);
id = edge.blocked_on_id;
key = edge.blocked_on_key;
}
// Finally, we copy in the results from `from_stack`.
let prefix = from_stack
.iter_mut()
.take_while(|p| p.database_key_index != key)
.count();
let prefix = from_stack.iter_mut().take_while(|p| p.database_key_index != key).count();
closure(&mut from_stack[prefix..]);
}
@ -141,24 +134,13 @@ pub(super) fn maybe_unblock_runtimes_in_cycle(
let mut others_unblocked = false;
while id != from_id {
let edge = self.edges.get(&id).unwrap();
let prefix = edge
.stack
.iter()
.take_while(|p| p.database_key_index != key)
.count();
let prefix = edge.stack.iter().take_while(|p| p.database_key_index != key).count();
let next_id = edge.blocked_on_id;
let next_key = edge.blocked_on_key;
if let Some(cycle) = edge.stack[prefix..]
.iter()
.rev()
.find_map(|aq| aq.cycle.clone())
{
if let Some(cycle) = edge.stack[prefix..].iter().rev().find_map(|aq| aq.cycle.clone()) {
// Remove `id` from the list of runtimes blocked on `next_key`:
self.query_dependents
.get_mut(&next_key)
.unwrap()
.retain(|r| *r != id);
self.query_dependents.get_mut(&next_key).unwrap().retain(|r| *r != id);
// Unblock runtime so that it can resume execution once lock is released:
self.unblock_runtime(id, WaitResult::Cycle(cycle));
@ -170,10 +152,7 @@ pub(super) fn maybe_unblock_runtimes_in_cycle(
key = next_key;
}
let prefix = from_stack
.iter()
.take_while(|p| p.database_key_index != key)
.count();
let prefix = from_stack.iter().take_while(|p| p.database_key_index != key).count();
let this_unblocked = from_stack[prefix..].iter().any(|aq| aq.cycle.is_some());
(this_unblocked, others_unblocked)
@ -239,10 +218,7 @@ fn add_edge(
condvar: condvar.clone(),
},
);
self.query_dependents
.entry(database_key)
.or_default()
.push(from_id);
self.query_dependents.entry(database_key).or_default().push(from_id);
condvar
}
@ -253,10 +229,7 @@ pub(super) fn unblock_runtimes_blocked_on(
database_key: DatabaseKeyIndex,
wait_result: WaitResult,
) {
let dependents = self
.query_dependents
.remove(&database_key)
.unwrap_or_default();
let dependents = self.query_dependents.remove(&database_key).unwrap_or_default();
for from_id in dependents {
self.unblock_runtime(from_id, wait_result.clone());

View File

@ -53,9 +53,7 @@ pub(crate) enum QueryInputs {
impl Default for LocalState {
fn default() -> Self {
LocalState {
query_stack: RefCell::new(Some(Vec::new())),
}
LocalState { query_stack: RefCell::new(Some(Vec::new())) }
}
}
@ -65,19 +63,11 @@ pub(super) fn push_query(&self, database_key_index: DatabaseKeyIndex) -> ActiveQ
let mut query_stack = self.query_stack.borrow_mut();
let query_stack = query_stack.as_mut().expect("local stack taken");
query_stack.push(ActiveQuery::new(database_key_index));
ActiveQueryGuard {
local_state: self,
database_key_index,
push_len: query_stack.len(),
}
ActiveQueryGuard { local_state: self, database_key_index, push_len: query_stack.len() }
}
fn with_query_stack<R>(&self, c: impl FnOnce(&mut Vec<ActiveQuery>) -> R) -> R {
c(self
.query_stack
.borrow_mut()
.as_mut()
.expect("query stack taken"))
c(self.query_stack.borrow_mut().as_mut().expect("query stack taken"))
}
pub(super) fn query_in_progress(&self) -> bool {
@ -86,9 +76,7 @@ pub(super) fn query_in_progress(&self) -> bool {
pub(super) fn active_query(&self) -> Option<DatabaseKeyIndex> {
self.with_query_stack(|stack| {
stack
.last()
.map(|active_query| active_query.database_key_index)
stack.last().map(|active_query| active_query.database_key_index)
})
}
@ -156,10 +144,7 @@ pub(super) fn report_synthetic_read(&self, durability: Durability, revision: Rev
/// the current thread is blocking. The stack must be restored
/// with [`Self::restore_query_stack`] when the thread unblocks.
pub(super) fn take_query_stack(&self) -> Vec<ActiveQuery> {
assert!(
self.query_stack.borrow().is_some(),
"query stack already taken"
);
assert!(self.query_stack.borrow().is_some(), "query stack already taken");
self.query_stack.take().unwrap()
}
@ -188,10 +173,7 @@ fn pop_helper(&self) -> ActiveQuery {
self.local_state.with_query_stack(|stack| {
// Sanity check: pushes and pops should be balanced.
assert_eq!(stack.len(), self.push_len);
debug_assert_eq!(
stack.last().unwrap().database_key_index,
self.database_key_index
);
debug_assert_eq!(stack.last().unwrap().database_key_index, self.database_key_index);
stack.pop().unwrap()
})
}
@ -220,8 +202,7 @@ pub(crate) fn pop(self) -> QueryRevisions {
/// If the active query is registered as a cycle participant, remove and
/// return that cycle.
pub(crate) fn take_cycle(&self) -> Option<Cycle> {
self.local_state
.with_query_stack(|stack| stack.last_mut()?.cycle.take())
self.local_state.with_query_stack(|stack| stack.last_mut()?.cycle.take())
}
}

View File

@ -12,10 +12,7 @@ pub struct Storage<DB: DatabaseStorageTypes> {
impl<DB: DatabaseStorageTypes> Default for Storage<DB> {
fn default() -> Self {
Self {
query_store: Default::default(),
runtime: Default::default(),
}
Self { query_store: Default::default(), runtime: Default::default() }
}
}
@ -51,9 +48,6 @@ pub fn query_store_mut(&mut self) -> (&DB::DatabaseStorage, &mut Runtime) {
/// thread. Using two database handles from the **same thread** can lead to
/// deadlock.
pub fn snapshot(&self) -> Self {
Storage {
query_store: self.query_store.clone(),
runtime: self.runtime.snapshot(),
}
Storage { query_store: self.query_store.clone(), runtime: self.runtime.snapshot() }
}
}

View File

@ -58,17 +58,13 @@ impl salsa::Database for DatabaseImpl {}
impl ParallelDatabase for DatabaseImpl {
fn snapshot(&self) -> Snapshot<Self> {
Snapshot::new(DatabaseImpl {
storage: self.storage.snapshot(),
})
Snapshot::new(DatabaseImpl { storage: self.storage.snapshot() })
}
}
impl Default for DatabaseImpl {
fn default() -> Self {
let res = DatabaseImpl {
storage: salsa::Storage::default(),
};
let res = DatabaseImpl { storage: salsa::Storage::default() };
res
}
@ -113,15 +109,11 @@ trait Database: salsa::Database {
}
fn recover_a(db: &dyn Database, cycle: &salsa::Cycle) -> Result<(), Error> {
Err(Error {
cycle: cycle.all_participants(db),
})
Err(Error { cycle: cycle.all_participants(db) })
}
fn recover_b(db: &dyn Database, cycle: &salsa::Cycle) -> Result<(), Error> {
Err(Error {
cycle: cycle.all_participants(db),
})
Err(Error { cycle: cycle.all_participants(db) })
}
fn memoized_a(db: &dyn Database) {

View File

@ -111,10 +111,7 @@ fn becomes_constant_with_change() {
db.set_input_with_durability('b', 45, Durability::MEDIUM);
assert_eq!(db.add('a', 'b'), 68);
assert_eq!(
Durability::MEDIUM,
AddQuery.in_db(&db).durability(('a', 'b'))
);
assert_eq!(Durability::MEDIUM, AddQuery.in_db(&db).durability(('a', 'b')));
}
// Test a subtle case in which an input changes from constant to

View File

@ -12,9 +12,7 @@ impl salsa::Database for Database {}
impl salsa::ParallelDatabase for Database {
fn snapshot(&self) -> salsa::Snapshot<Self> {
salsa::Snapshot::new(Database {
storage: self.storage.snapshot(),
})
salsa::Snapshot::new(Database { storage: self.storage.snapshot() })
}
}
@ -71,14 +69,8 @@ fn test_intern2() {
assert_eq!(bar0, bar1);
assert_ne!(foo0, bar0);
assert_eq!(
("x".to_string(), "foo".to_string()),
db.lookup_intern2(foo0)
);
assert_eq!(
("x".to_string(), "bar".to_string()),
db.lookup_intern2(bar0)
);
assert_eq!(("x".to_string(), "foo".to_string()), db.lookup_intern2(foo0));
assert_eq!(("x".to_string(), "bar".to_string()), db.lookup_intern2(bar0));
}
#[test]

View File

@ -16,11 +16,7 @@ trait QueryGroup: salsa::Database + AsRef<HashMap<u32, u32>> {
}
fn a(db: &dyn QueryGroup, x: u32) -> u32 {
let durability = if x % 2 == 0 {
Durability::LOW
} else {
Durability::HIGH
};
let durability = if x % 2 == 0 { Durability::LOW } else { Durability::HIGH };
db.salsa_runtime().report_synthetic_read(durability);
let external_state: &HashMap<u32, u32> = db.as_ref();
external_state[&x]

View File

@ -33,9 +33,7 @@ impl salsa::Database for DatabaseStruct {}
impl salsa::ParallelDatabase for DatabaseStruct {
fn snapshot(&self) -> Snapshot<Self> {
Snapshot::new(DatabaseStruct {
storage: self.storage.snapshot(),
})
Snapshot::new(DatabaseStruct { storage: self.storage.snapshot() })
}
}

View File

@ -37,11 +37,7 @@ fn parallel_cycle_none_recover() {
// We expect A to propagate a panic, which causes us to use the sentinel
// type `Canceled`.
assert!(thread_a
.join()
.unwrap_err()
.downcast_ref::<salsa::Cycle>()
.is_some());
assert!(thread_a.join().unwrap_err().downcast_ref::<salsa::Cycle>().is_some());
}
#[salsa::query_group(ParallelCycleNoneRecover)]

View File

@ -38,9 +38,7 @@ impl salsa::Database for StressDatabaseImpl {}
impl salsa::ParallelDatabase for StressDatabaseImpl {
fn snapshot(&self) -> Snapshot<StressDatabaseImpl> {
Snapshot::new(StressDatabaseImpl {
storage: self.storage.snapshot(),
})
Snapshot::new(StressDatabaseImpl { storage: self.storage.snapshot() })
}
}
@ -53,10 +51,7 @@ enum Query {
enum MutatorOp {
WriteOp(WriteOp),
LaunchReader {
ops: Vec<ReadOp>,
check_cancellation: bool,
},
LaunchReader { ops: Vec<ReadOp>, check_cancellation: bool },
}
#[derive(Debug)]
@ -158,13 +153,12 @@ fn stress_test() {
for op in write_ops {
match op {
MutatorOp::WriteOp(w) => w.execute(&mut db),
MutatorOp::LaunchReader {
ops,
check_cancellation,
} => all_threads.push(std::thread::spawn({
let db = db.snapshot();
move || Cancelled::catch(|| db_reader_thread(&db, ops, check_cancellation))
})),
MutatorOp::LaunchReader { ops, check_cancellation } => {
all_threads.push(std::thread::spawn({
let db = db.snapshot();
move || Cancelled::catch(|| db_reader_thread(&db, ops, check_cancellation))
}))
}
}
}

View File

@ -18,11 +18,10 @@ fn true_parallel_different_keys() {
let thread1 = std::thread::spawn({
let db = db.snapshot();
move || {
let v = db.knobs().sum_signal_on_entry.with_value(1, || {
db.knobs()
.sum_wait_for_on_exit
.with_value(2, || db.sum("a"))
});
let v = db
.knobs()
.sum_signal_on_entry
.with_value(1, || db.knobs().sum_wait_for_on_exit.with_value(2, || db.sum("a")));
v
}
});
@ -32,9 +31,10 @@ fn true_parallel_different_keys() {
let thread2 = std::thread::spawn({
let db = db.snapshot();
move || {
let v = db.knobs().sum_wait_for_on_entry.with_value(1, || {
db.knobs().sum_signal_on_exit.with_value(2, || db.sum("b"))
});
let v = db
.knobs()
.sum_wait_for_on_entry
.with_value(1, || db.knobs().sum_signal_on_exit.with_value(2, || db.sum("b")));
v
}
});
@ -58,11 +58,10 @@ fn true_parallel_same_keys() {
let thread1 = std::thread::spawn({
let db = db.snapshot();
move || {
let v = db.knobs().sum_signal_on_entry.with_value(1, || {
db.knobs()
.sum_wait_for_on_entry
.with_value(2, || db.sum("abc"))
});
let v = db
.knobs()
.sum_signal_on_entry
.with_value(1, || db.knobs().sum_wait_for_on_entry.with_value(2, || db.sum("abc")));
v
}
});
@ -99,9 +98,9 @@ fn true_parallel_propagate_panic() {
let db = db.snapshot();
move || {
let v = db.knobs().sum_signal_on_entry.with_value(1, || {
db.knobs().sum_wait_for_on_entry.with_value(2, || {
db.knobs().sum_should_panic.with_value(true, || db.sum("a"))
})
db.knobs()
.sum_wait_for_on_entry
.with_value(2, || db.knobs().sum_should_panic.with_value(true, || db.sum("a")))
});
v
}