refactor ChangedAt into a struct

There are really two orthogonal things going on here.
This commit is contained in:
Niko Matsakis 2018-10-22 04:41:57 -04:00
parent 03751d3d5c
commit 1ab8d1a64e
3 changed files with 68 additions and 55 deletions

View file

@ -319,8 +319,8 @@ where
if let Some(old_memo) = &old_memo {
if let Some(old_value) = &old_memo.value {
if MP::memoized_value_eq(&old_value, &stamped_value.value) {
assert!(old_memo.changed_at <= stamped_value.changed_at);
stamped_value.changed_at = old_memo.changed_at;
assert!(old_memo.changed_at.revision <= stamped_value.changed_at.revision);
stamped_value.changed_at.revision = old_memo.changed_at.revision;
}
}
}
@ -717,7 +717,10 @@ where
let mut map_write = self.map.write();
let current_revision = db.salsa_runtime().current_revision();
let changed_at = ChangedAt::Revision(current_revision);
let changed_at = ChangedAt {
is_constant: false,
revision: current_revision,
};
map_write.insert(
key,
@ -751,20 +754,13 @@ where
fn verify_inputs(&self, db: &DB) -> bool {
match &self.inputs {
QueryDescriptorSet::Constant => {
debug_assert!(match self.changed_at {
ChangedAt::Constant(_) => true,
ChangedAt::Revision(_) => false,
});
debug_assert!(self.changed_at.is_constant);
true
}
QueryDescriptorSet::Tracked { descriptors } => {
debug_assert!(!descriptors.is_empty());
debug_assert!(match self.changed_at {
ChangedAt::Constant(_) => false,
ChangedAt::Revision(_) => true,
});
debug_assert!(!self.changed_at.is_constant);
// Check whether any of our inputs changed since the
// **last point where we were verified** (not since we

View file

@ -61,7 +61,10 @@ where
Ok(StampedValue {
value: <Q::Value>::default(),
changed_at: ChangedAt::Revision(Revision::ZERO),
changed_at: ChangedAt {
is_constant: false,
revision: Revision::ZERO,
},
})
}
@ -80,8 +83,10 @@ where
if is_constant.0 && !old_value.changed_at.is_constant() {
let mut map = RwLockUpgradableReadGuard::upgrade(map);
let old_value = map.get_mut(key).unwrap();
old_value.changed_at =
ChangedAt::Constant(db.salsa_runtime().current_revision());
old_value.changed_at = ChangedAt {
is_constant: true,
revision: db.salsa_runtime().current_revision(),
};
}
return;
@ -106,10 +111,9 @@ where
// 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 changed_at = if is_constant.0 {
ChangedAt::Constant(next_revision)
} else {
ChangedAt::Revision(next_revision)
let changed_at = ChangedAt {
is_constant: is_constant.0,
revision: next_revision,
};
let stamped_value = StampedValue { value, changed_at };
@ -174,7 +178,10 @@ where
map_read
.get(key)
.map(|v| v.changed_at)
.unwrap_or(ChangedAt::Revision(Revision::ZERO))
.unwrap_or(ChangedAt {
is_constant: false,
revision: Revision::ZERO,
})
};
debug!(
@ -229,7 +236,10 @@ where
// Unlike with `set`, here we use the **current revision** and
// do not create a new one.
let changed_at = ChangedAt::Revision(db.salsa_runtime().current_revision());
let changed_at = ChangedAt {
is_constant: false,
revision: db.salsa_runtime().current_revision(),
};
map_write.insert(key, StampedValue { value, changed_at });
}

View file

@ -258,6 +258,11 @@ where
local_state.query_stack.pop().unwrap()
};
let is_constant = match &subqueries {
Some(set) => set.is_empty(),
None => false,
};
let query_descriptor_set = match subqueries {
None => QueryDescriptorSet::Untracked,
Some(set) => {
@ -271,7 +276,16 @@ where
}
};
(StampedValue { value, changed_at }, query_descriptor_set)
(
StampedValue {
value,
changed_at: ChangedAt {
is_constant,
revision: changed_at,
},
},
query_descriptor_set,
)
}
/// Reports that the currently active query read the result from
@ -294,8 +308,7 @@ where
pub(crate) fn report_untracked_read(&self) {
if let Some(top_query) = self.local_state.borrow_mut().query_stack.last_mut() {
let changed_at = ChangedAt::Revision(self.current_revision());
top_query.add_untracked_read(changed_at);
top_query.add_untracked_read(self.current_revision());
}
}
@ -462,7 +475,7 @@ struct ActiveQuery<DB: Database> {
descriptor: DB::QueryDescriptor,
/// Records the maximum revision where any subquery changed
changed_at: ChangedAt,
changed_at: Revision,
/// Each subquery
subqueries: Option<FxIndexSet<DB::QueryDescriptor>>,
@ -472,27 +485,29 @@ impl<DB: Database> ActiveQuery<DB> {
fn new(descriptor: DB::QueryDescriptor) -> Self {
ActiveQuery {
descriptor,
changed_at: ChangedAt::Constant(Revision::ZERO),
changed_at: Revision::ZERO,
subqueries: Some(FxIndexSet::default()),
}
}
fn add_read(&mut self, subquery: &DB::QueryDescriptor, changed_at: ChangedAt) {
match changed_at {
ChangedAt::Constant(_) => {
// When we read constant values, we don't need to
// track the source of the value.
}
ChangedAt::Revision(_) => {
if let Some(set) = &mut self.subqueries {
set.insert(subquery.clone());
}
self.changed_at = self.changed_at.max(changed_at);
let ChangedAt {
is_constant,
revision,
} = changed_at;
if is_constant {
// When we read constant values, we don't need to
// track the source of the value.
} else {
if let Some(set) = &mut self.subqueries {
set.insert(subquery.clone());
}
self.changed_at = self.changed_at.max(revision);
}
}
fn add_untracked_read(&mut self, changed_at: ChangedAt) {
fn add_untracked_read(&mut self, changed_at: Revision) {
self.subqueries = None;
self.changed_at = self.changed_at.max(changed_at);
}
@ -519,35 +534,27 @@ impl std::fmt::Debug for Revision {
}
/// Records when a stamped value changed.
///
/// Note: the order of variants is significant. We sometimes use `max`
/// for example to find the "most recent revision" when something
/// changed.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum ChangedAt {
/// Will never change again (and the revision in which we became a
/// constant).
Constant(Revision),
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ChangedAt {
// Will this value ever change again?
pub(crate) is_constant: bool,
/// Last changed in the given revision. May change in the future.
Revision(Revision),
// At which revision did this value last change? (If this value is
// the value of a constant input, this indicates when it became
// constant.)
pub(crate) revision: Revision,
}
impl ChangedAt {
pub fn is_constant(self) -> bool {
match self {
ChangedAt::Constant(_) => true,
ChangedAt::Revision(_) => false,
}
self.is_constant
}
/// True if a value is stored with this `ChangedAt` value has
/// changed after `revision`. This is invoked by query storage
/// when their dependents are asking them if they have changed.
pub fn changed_since(self, revision: Revision) -> bool {
match self {
ChangedAt::Constant(r) | ChangedAt::Revision(r) => r > revision,
}
self.revision > revision
}
}