mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-07-24 05:36:31 +00:00
introduce SweepStrategy
This commit is contained in:
parent
74cecb6ea5
commit
c21ea47cfc
7 changed files with 55 additions and 21 deletions
|
@ -11,6 +11,7 @@ use crate::runtime::Runtime;
|
|||
use crate::runtime::RuntimeId;
|
||||
use crate::runtime::StampedValue;
|
||||
use crate::Database;
|
||||
use crate::SweepStrategy;
|
||||
use log::{debug, info};
|
||||
use parking_lot::Mutex;
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
|
@ -790,7 +791,7 @@ where
|
|||
DB: Database,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
{
|
||||
fn sweep(&self, db: &DB) {
|
||||
fn sweep(&self, db: &DB, strategy: SweepStrategy) {
|
||||
let mut map_write = self.map.write();
|
||||
let revision_now = db.salsa_runtime().current_revision();
|
||||
map_write.retain(|key, query_state| {
|
||||
|
@ -820,6 +821,10 @@ where
|
|||
// when we read `revision_now`.
|
||||
assert!(memo.verified_at <= revision_now);
|
||||
|
||||
if !strategy.keep_values {
|
||||
memo.value = None;
|
||||
}
|
||||
|
||||
memo.verified_at == revision_now
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ use crate::runtime::Revision;
|
|||
use crate::runtime::StampedValue;
|
||||
use crate::Database;
|
||||
use crate::Query;
|
||||
use crate::SweepStrategy;
|
||||
use log::debug;
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
@ -215,7 +216,7 @@ where
|
|||
DB: Database,
|
||||
Q::Value: Default,
|
||||
{
|
||||
fn sweep(&self, _db: &DB) {}
|
||||
fn sweep(&self, _db: &DB, _strategy: SweepStrategy) {}
|
||||
}
|
||||
|
||||
impl<DB, Q> InputQueryStorageOps<DB, Q> for InputStorage<DB, Q>
|
||||
|
|
35
src/lib.rs
35
src/lib.rs
|
@ -47,8 +47,8 @@ pub trait Database: plumbing::DatabaseStorageTypes + plumbing::DatabaseOps {
|
|||
/// threads that would be performing a `set`).
|
||||
///
|
||||
/// [`lock_revision`]: struct.Runtime.html#method.lock_revision
|
||||
fn sweep_all(&self) {
|
||||
self.salsa_runtime().sweep_all(self);
|
||||
fn sweep_all(&self, strategy: SweepStrategy) {
|
||||
self.salsa_runtime().sweep_all(self, strategy);
|
||||
}
|
||||
|
||||
/// Get access to extra methods pertaining to a given query,
|
||||
|
@ -63,6 +63,33 @@ pub trait Database: plumbing::DatabaseStorageTypes + plumbing::DatabaseOps {
|
|||
}
|
||||
}
|
||||
|
||||
/// The sweep strategy controls what data we will keep/discard when we
|
||||
/// do a GC-sweep. The default (`SweepStrategy::default`) is to keep
|
||||
/// all memoized values used in the current revision.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SweepStrategy {
|
||||
keep_values: bool,
|
||||
}
|
||||
|
||||
impl SweepStrategy {
|
||||
/// Causes us to discard memoized *values* but keep the
|
||||
/// *dependencies*. This means you will have to recompute the
|
||||
/// results from any queries you execute but does permit you to
|
||||
/// quickly determine if a value is still up to date.
|
||||
pub fn discard_values(self) -> SweepStrategy {
|
||||
SweepStrategy {
|
||||
keep_values: false,
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SweepStrategy {
|
||||
fn default() -> Self {
|
||||
SweepStrategy { keep_values: true }
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates a database that also supports parallel query
|
||||
/// evaluation. All of Salsa's base query support is capable of
|
||||
/// parallel execution, but for it to work, your query key/value types
|
||||
|
@ -108,11 +135,11 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
pub fn sweep(&self)
|
||||
pub fn sweep(&self, strategy: SweepStrategy)
|
||||
where
|
||||
Q::Storage: plumbing::QueryStorageMassOps<DB>,
|
||||
{
|
||||
self.storage.sweep(self.db);
|
||||
self.storage.sweep(self.db, strategy);
|
||||
}
|
||||
|
||||
/// Assign a value to an "input query". Must be used outside of
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use crate::Database;
|
||||
use crate::Query;
|
||||
use crate::QueryTable;
|
||||
use crate::SweepStrategy;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
|
||||
|
@ -41,7 +42,7 @@ pub trait DatabaseOps: Sized {
|
|||
/// query, unlike `QueryStorageOps`).
|
||||
pub trait QueryStorageMassOps<DB: Database> {
|
||||
/// Discards memoized values that are not up to date with the current revision.
|
||||
fn sweep(&self, db: &DB);
|
||||
fn sweep(&self, db: &DB, strategy: SweepStrategy);
|
||||
}
|
||||
|
||||
pub trait QueryDescriptor<DB>: Clone + Debug + Eq + Hash + Send + Sync {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::Database;
|
||||
use crate::{Database, SweepStrategy};
|
||||
use lock_api::RawRwLock;
|
||||
use log::debug;
|
||||
use parking_lot::{Mutex, RwLock, RwLockReadGuard, RwLockUpgradableReadGuard};
|
||||
|
@ -94,13 +94,13 @@ where
|
|||
}
|
||||
|
||||
/// Default implementation for `Database::sweep_all`.
|
||||
pub fn sweep_all(&self, db: &DB) {
|
||||
pub fn sweep_all(&self, db: &DB, strategy: SweepStrategy) {
|
||||
// Note that we do not acquire the query lock (or any locks)
|
||||
// here. Each table is capable of sweeping itself atomically
|
||||
// and there is no need to bring things to a halt. That said,
|
||||
// users may wish to guarantee atomicity.
|
||||
|
||||
db.for_each_query(|query_storage| query_storage.sweep(db));
|
||||
db.for_each_query(|query_storage| query_storage.sweep(db, strategy));
|
||||
}
|
||||
|
||||
/// Indicates that a derived query has begun to execute; if this is the
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::db;
|
||||
use crate::group::*;
|
||||
use salsa::debug::DebugQueryTable;
|
||||
use salsa::Database;
|
||||
use salsa::{Database, SweepStrategy};
|
||||
|
||||
macro_rules! assert_keys {
|
||||
($db:expr, $($query:expr => ($($key:expr),*),)*) => {
|
||||
|
@ -34,7 +34,7 @@ fn compute_one() {
|
|||
|
||||
// Memoized, but will compute fibonacci(5) again
|
||||
db.compute(5);
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
assert_keys! {
|
||||
db,
|
||||
|
@ -72,7 +72,7 @@ fn compute_switch() {
|
|||
Max => (),
|
||||
}
|
||||
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
// Now we just have `Triangular` and not `Fibonacci`
|
||||
assert_keys! {
|
||||
|
@ -88,7 +88,7 @@ fn compute_switch() {
|
|||
// Now run `compute` *again* in next revision.
|
||||
db.salsa_runtime().next_revision();
|
||||
assert_eq!(db.compute(5), 15);
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
// We keep triangular, but just the outermost one.
|
||||
assert_keys! {
|
||||
|
@ -117,7 +117,7 @@ fn compute_all() {
|
|||
db.compute_all();
|
||||
db.salsa_runtime().next_revision();
|
||||
db.compute_all();
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
assert_keys! {
|
||||
db,
|
||||
|
@ -145,7 +145,7 @@ fn compute_all() {
|
|||
Max => (()),
|
||||
}
|
||||
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
// We no longer used `Compute(5)` and `Triangular(5)`; note that
|
||||
// `UseTriangular(5)` is not collected, as it is an input.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::db;
|
||||
use crate::group::{Fibonacci, GcDatabase};
|
||||
use salsa::debug::DebugQueryTable;
|
||||
use salsa::Database;
|
||||
use salsa::{Database, SweepStrategy};
|
||||
|
||||
// For constant values (like `fibonacci`), we only keep the values
|
||||
// that were used in the latest revision, not the sub-values that
|
||||
|
@ -18,7 +18,7 @@ fn one_rev() {
|
|||
|
||||
// Everything was used in this revision, so
|
||||
// nothing gets collected.
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
assert_eq!(k.len(), 6);
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ fn two_rev_nothing() {
|
|||
|
||||
// Nothing was used in this revision, so
|
||||
// everything gets collected.
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
let k: Vec<_> = db.query(Fibonacci).keys();
|
||||
assert_eq!(k.len(), 0);
|
||||
|
@ -56,7 +56,7 @@ fn two_rev_one_use() {
|
|||
|
||||
// fibonacci is a constant, so it will not be invalidated,
|
||||
// hence we keep `fibonacci(5)` but remove 0..=4.
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
let k: Vec<_> = db.query(Fibonacci).keys();
|
||||
assert_eq!(k, vec![5]);
|
||||
|
@ -78,7 +78,7 @@ fn two_rev_two_uses() {
|
|||
|
||||
// fibonacci is a constant, so it will not be invalidated,
|
||||
// hence we keep 3 and 5 but remove the rest.
|
||||
db.sweep_all();
|
||||
db.sweep_all(SweepStrategy::default());
|
||||
|
||||
let mut k: Vec<_> = db.query(Fibonacci).keys();
|
||||
k.sort();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue