move to QueryType.in_db(&db) instead of db.query(QueryType)

This will be more compatible once we move to having queries have an
associated `DynDb` type. It also reads nicely.
This commit is contained in:
Niko Matsakis 2020-07-02 21:29:25 +00:00
parent 7a5b515279
commit 0e5366df5d
12 changed files with 91 additions and 99 deletions

View file

@ -350,6 +350,56 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
#[derive(Default, Debug)]
#trait_vis struct #qt;
impl #qt {
/// Get access to extra methods pertaining to this query. For
/// example, you can use this to run the GC (`sweep`) across a
/// single input. You can also use it to invoke this query, though
/// it's more common to use the trait method on the database
/// itself.
#trait_vis fn in_db<DB>(self, db: &DB) -> salsa::QueryTable<'_, DB, Self>
where
Self: salsa::Query<DB>,
DB: salsa::plumbing::GetQueryTable<Self>,
{
<DB as salsa::plumbing::GetQueryTable<Self>>::get_query_table(db)
}
/// Like `in_db`, but gives access to methods for setting the
/// value of an input. Not applicable to derived queries.
///
/// # Threads, cancellation, and blocking
///
/// Mutating the value of a query cannot be done while there are
/// still other queries executing. If you are using your database
/// within a single thread, this is not a problem: you only have
/// `&self` access to the database, but this method requires `&mut
/// self`.
///
/// However, if you have used `snapshot` to create other threads,
/// then attempts to `set` will **block the current thread** until
/// those snapshots are dropped (usually when those threads
/// complete). This also implies that if you create a snapshot but
/// do not send it to another thread, then invoking `set` will
/// deadlock.
///
/// Before blocking, the thread that is attempting to `set` will
/// also set a cancellation flag. In the threads operating on
/// snapshots, you can use the [`is_current_revision_canceled`]
/// method to check for this flag and bring those operations to a
/// close, thus allowing the `set` to succeed. Ignoring this flag
/// may lead to "starvation", meaning that the thread attempting
/// to `set` has to wait a long, long time. =)
///
/// [`is_current_revision_canceled`]: struct.Runtime.html#method.is_current_revision_canceled
#trait_vis fn in_db_mut<DB>(self, db: &mut DB) -> salsa::QueryTableMut<'_, DB, Self>
where
Self: salsa::Query<DB>,
DB: salsa::plumbing::GetQueryTable<Self>,
{
<DB as salsa::plumbing::GetQueryTable<Self>>::get_query_table_mut(db)
}
}
// Unsafe proof obligation: that our key/value are a part
// of the `GroupData`.
impl<#db> salsa::Query<#db> for #qt

View file

@ -86,61 +86,6 @@ pub trait Database: plumbing::DatabaseOps {
}
}
/// Extension trait that gives access to the `query` and `query_mut` methods.
pub trait DatabaseQueryExt: Database {
/// Get access to extra methods pertaining to a given query. For
/// example, you can use this to run the GC (`sweep`) across a
/// single input. You can also use it to invoke a query, though
/// it's more common to use the trait method on the database
/// itself.
#[allow(unused_variables)]
fn query<Q>(&self, query: Q) -> QueryTable<'_, Self, Q>
where
Q: Query<Self>,
Self: plumbing::GetQueryTable<Q>,
{
<Self as plumbing::GetQueryTable<Q>>::get_query_table(self)
}
/// Like `query`, but gives access to methods for setting the
/// value of an input.
///
/// # Threads, cancellation, and blocking
///
/// Mutating the value of a query cannot be done while there are
/// still other queries executing. If you are using your database
/// within a single thread, this is not a problem: you only have
/// `&self` access to the database, but this method requires `&mut
/// self`.
///
/// However, if you have used `snapshot` to create other threads,
/// then attempts to `set` will **block the current thread** until
/// those snapshots are dropped (usually when those threads
/// complete). This also implies that if you create a snapshot but
/// do not send it to another thread, then invoking `set` will
/// deadlock.
///
/// Before blocking, the thread that is attempting to `set` will
/// also set a cancellation flag. In the threads operating on
/// snapshots, you can use the [`is_current_revision_canceled`]
/// method to check for this flag and bring those operations to a
/// close, thus allowing the `set` to succeed. Ignoring this flag
/// may lead to "starvation", meaning that the thread attempting
/// to `set` has to wait a long, long time. =)
///
/// [`is_current_revision_canceled`]: struct.Runtime.html#method.is_current_revision_canceled
#[allow(unused_variables)]
fn query_mut<Q>(&mut self, query: Q) -> QueryTableMut<'_, Self, Q>
where
Q: Query<Self>,
Self: plumbing::GetQueryTable<Q>,
{
<Self as plumbing::GetQueryTable<Q>>::get_query_table_mut(self)
}
}
impl<DB: Database> DatabaseQueryExt for DB {}
/// The `Event` struct identifies various notable things that can
/// occur during salsa execution. Instances of this struct are given
/// to `salsa_event`.

View file

@ -1,7 +1,7 @@
use crate::db;
use crate::group::*;
use salsa::debug::DebugQueryTable;
use salsa::{Database, DatabaseQueryExt, Durability, SweepStrategy};
use salsa::{Database, Durability, SweepStrategy};
#[test]
fn compute_one_write_low() {

View file

@ -1,7 +1,7 @@
use crate::db;
use crate::group::{FibonacciQuery, GcDatabase};
use salsa::debug::DebugQueryTable;
use salsa::{Database, DatabaseQueryExt, Durability, SweepStrategy};
use salsa::{Database, Durability, SweepStrategy};
#[test]
fn sweep_default() {
@ -9,7 +9,7 @@ fn sweep_default() {
db.fibonacci(5);
let k: Vec<_> = db.query(FibonacciQuery).entries();
let k: Vec<_> = FibonacciQuery.in_db(&db).entries();
assert_eq!(k.len(), 6);
db.salsa_runtime_mut().synthetic_write(Durability::LOW);

View file

@ -1,6 +1,6 @@
use crate::db;
use salsa::debug::DebugQueryTable;
use salsa::{Database, DatabaseQueryExt, Durability, InternId, SweepStrategy};
use salsa::{Database, Durability, InternId, SweepStrategy};
/// Query group for tests for how interned keys interact with GC.
#[salsa::query_group(Intern)]
@ -44,7 +44,7 @@ fn discard_during_same_revision() {
// If we are not careful, this would remove the interned key for
// "foo".
db.query(InternStrQuery).sweep(
InternStrQuery.in_db(&db).sweep(
SweepStrategy::default()
.discard_everything()
.sweep_all_revisions(),
@ -123,7 +123,7 @@ fn discard_durability_after_synthetic_write_low() {
let foo1a = db.repeat_intern1("foo");
assert_eq!(
Durability::HIGH,
db.query(RepeatIntern1Query).durability("foo")
RepeatIntern1Query.in_db(&db).durability("foo")
);
// Trigger a new revision.
@ -131,7 +131,7 @@ fn discard_durability_after_synthetic_write_low() {
// If we are not careful, this would remove the interned key for
// "foo".
db.query(InternStrQuery).sweep(
InternStrQuery.in_db(&db).sweep(
SweepStrategy::default()
.discard_everything()
.sweep_all_revisions(),
@ -163,14 +163,14 @@ fn discard_durability_after_synthetic_write_high() {
let foo1a = db.repeat_intern1("foo");
assert_eq!(
Durability::HIGH,
db.query(RepeatIntern1Query).durability("foo")
RepeatIntern1Query.in_db(&db).durability("foo")
);
// Trigger a new revision -- marking even high things as having changed.
db.salsa_runtime_mut().synthetic_write(Durability::HIGH);
// We are now able to collect "collect".
db.query(InternStrQuery).sweep(
InternStrQuery.in_db(&db).sweep(
SweepStrategy::default()
.discard_everything()
.sweep_all_revisions(),

View file

@ -1,7 +1,7 @@
macro_rules! assert_keys {
($db:expr, $($query:expr => ($($key:expr),*),)*) => {
$(
let entries = $db.query($query).entries::<Vec<_>>();
let entries = $query.in_db(&$db).entries::<Vec<_>>();
let mut keys = entries.into_iter().map(|e| e.key).collect::<Vec<_>>();
keys.sort();
assert_eq!(keys, vec![$($key),*], "query {:?} had wrong keys", $query);

View file

@ -1,7 +1,7 @@
use crate::db;
use crate::group::{FibonacciQuery, GcDatabase};
use salsa::debug::DebugQueryTable;
use salsa::{Database, DatabaseQueryExt, Durability, SweepStrategy};
use salsa::{Database, Durability, SweepStrategy};
// For constant values (like `fibonacci`), we only keep the values
// that were used in the latest revision, not the sub-values that
@ -13,7 +13,7 @@ fn one_rev() {
db.fibonacci(5);
let k: Vec<_> = db.query(FibonacciQuery).entries();
let k: Vec<_> = FibonacciQuery.in_db(&db).entries();
assert_eq!(k.len(), 6);
// Everything was used in this revision, so
@ -28,7 +28,7 @@ fn two_rev_nothing() {
db.fibonacci(5);
let k: Vec<_> = db.query(FibonacciQuery).entries();
let k: Vec<_> = FibonacciQuery.in_db(&db).entries();
assert_eq!(k.len(), 6);
db.salsa_runtime_mut().synthetic_write(Durability::LOW);
@ -37,7 +37,7 @@ fn two_rev_nothing() {
// everything gets collected.
db.sweep_all(SweepStrategy::discard_outdated());
let k: Vec<_> = db.query(FibonacciQuery).entries();
let k: Vec<_> = FibonacciQuery.in_db(&db).entries();
assert_eq!(k.len(), 0);
}
@ -47,7 +47,7 @@ fn two_rev_one_use() {
db.fibonacci(5);
let k: Vec<_> = db.query(FibonacciQuery).entries();
let k: Vec<_> = FibonacciQuery.in_db(&db).entries();
assert_eq!(k.len(), 6);
db.salsa_runtime_mut().synthetic_write(Durability::LOW);
@ -70,7 +70,7 @@ fn two_rev_two_uses() {
db.fibonacci(5);
let k: Vec<_> = db.query(FibonacciQuery).entries();
let k: Vec<_> = FibonacciQuery.in_db(&db).entries();
assert_eq!(k.len(), 6);
db.salsa_runtime_mut().synthetic_write(Durability::LOW);

View file

@ -1,5 +1,5 @@
use crate::db;
use salsa::{Database, DatabaseQueryExt, SweepStrategy};
use salsa::{Database, SweepStrategy};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
@ -60,7 +60,7 @@ fn consistency_with_gc() {
let v1 = db.repeat1();
cell.store(23, Ordering::SeqCst);
db.query(VolatileQuery).sweep(
VolatileQuery.in_db(&db).sweep(
SweepStrategy::default()
.discard_everything()
.sweep_all_revisions(),

View file

@ -1,6 +1,6 @@
use crate::implementation::{TestContext, TestContextImpl};
use salsa::debug::DebugQueryTable;
use salsa::{DatabaseQueryExt, Durability};
use salsa::Durability;
#[salsa::query_group(Constants)]
pub(crate) trait ConstantsDatabase: TestContext {
@ -64,56 +64,56 @@ fn set_after_constant_same_value() {
#[test]
fn not_constant() {
let db = &mut TestContextImpl::default();
let mut db = TestContextImpl::default();
db.set_input('a', 22);
db.set_input('b', 44);
assert_eq!(db.add('a', 'b'), 66);
assert_eq!(Durability::LOW, db.query(AddQuery).durability(('a', 'b')));
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
}
#[test]
fn durability() {
let db = &mut TestContextImpl::default();
let mut db = TestContextImpl::default();
db.set_input_with_durability('a', 22, Durability::HIGH);
db.set_input_with_durability('b', 44, Durability::HIGH);
assert_eq!(db.add('a', 'b'), 66);
assert_eq!(Durability::HIGH, db.query(AddQuery).durability(('a', 'b')));
assert_eq!(Durability::HIGH, AddQuery.in_db(&db).durability(('a', 'b')));
}
#[test]
fn mixed_constant() {
let db = &mut TestContextImpl::default();
let mut db = TestContextImpl::default();
db.set_input_with_durability('a', 22, Durability::HIGH);
db.set_input('b', 44);
assert_eq!(db.add('a', 'b'), 66);
assert_eq!(Durability::LOW, db.query(AddQuery).durability(('a', 'b')));
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
}
#[test]
fn becomes_constant_with_change() {
let db = &mut TestContextImpl::default();
let mut db = TestContextImpl::default();
db.set_input('a', 22);
db.set_input('b', 44);
assert_eq!(db.add('a', 'b'), 66);
assert_eq!(Durability::LOW, db.query(AddQuery).durability(('a', 'b')));
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
db.set_input_with_durability('a', 23, Durability::HIGH);
assert_eq!(db.add('a', 'b'), 67);
assert_eq!(Durability::LOW, db.query(AddQuery).durability(('a', 'b')));
assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
db.set_input_with_durability('b', 45, Durability::HIGH);
assert_eq!(db.add('a', 'b'), 68);
assert_eq!(Durability::HIGH, db.query(AddQuery).durability(('a', 'b')));
assert_eq!(Durability::HIGH, AddQuery.in_db(&db).durability(('a', 'b')));
db.set_input_with_durability('b', 45, Durability::MEDIUM);
assert_eq!(db.add('a', 'b'), 68);
assert_eq!(
Durability::MEDIUM,
db.query(AddQuery).durability(('a', 'b'))
AddQuery.in_db(&db).durability(('a', 'b'))
);
}
@ -123,7 +123,7 @@ fn becomes_constant_with_change() {
// being constant.
#[test]
fn constant_to_non_constant() {
let db = &mut TestContextImpl::default();
let mut db = TestContextImpl::default();
db.set_input_with_durability('a', 11, Durability::HIGH);
db.set_input_with_durability('b', 22, Durability::HIGH);

View file

@ -4,8 +4,6 @@ use std::sync::{
Arc,
};
use salsa::DatabaseQueryExt as _;
#[derive(Debug, PartialEq, Eq)]
struct HotPotato(u32);
@ -51,7 +49,7 @@ impl salsa::Database for Database {}
#[test]
fn lru_works() {
let mut db = Database::default();
db.query_mut(GetQuery).set_lru_capacity(32);
GetQuery.in_db_mut(&mut db).set_lru_capacity(32);
assert_eq!(N_POTATOES.load(Ordering::SeqCst), 0);
for i in 0..128u32 {
@ -66,10 +64,10 @@ fn lru_works() {
}
assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
db.query_mut(GetQuery).set_lru_capacity(32);
GetQuery.in_db_mut(&mut db).set_lru_capacity(32);
assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
db.query_mut(GetQuery).set_lru_capacity(64);
GetQuery.in_db_mut(&mut db).set_lru_capacity(64);
assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
for i in 0..128u32 {
let p = db.get(i);
@ -78,7 +76,7 @@ fn lru_works() {
assert_eq!(N_POTATOES.load(Ordering::SeqCst), 64);
// Special case: setting capacity to zero disables LRU
db.query_mut(GetQuery).set_lru_capacity(0);
GetQuery.in_db_mut(&mut db).set_lru_capacity(0);
assert_eq!(N_POTATOES.load(Ordering::SeqCst), 64);
for i in 0..128u32 {
let p = db.get(i);
@ -93,7 +91,7 @@ fn lru_works() {
#[test]
fn lru_doesnt_break_volatile_queries() {
let mut db = Database::default();
db.query_mut(GetVolatileQuery).set_lru_capacity(32);
GetVolatileQuery.in_db_mut(&mut db).set_lru_capacity(32);
// Here, we check that we execute each volatile query at most once, despite
// LRU. That does mean that we have more values in DB than the LRU capacity,
// but it's much better than inconsistent results from volatile queries!

View file

@ -6,7 +6,7 @@
use std::{cell::Cell, collections::HashMap, rc::Rc};
use salsa::{Database as _, DatabaseQueryExt as _, Durability};
use salsa::{Database as _, Durability};
#[salsa::query_group(QueryGroupStorage)]
trait QueryGroup: salsa::Database + AsRef<HashMap<u32, u32>> {
@ -70,7 +70,7 @@ fn on_demand_input_works() {
assert_eq!(db.b(1), 10);
assert_eq!(db.a(1), 10);
db.query_mut(AQuery).invalidate(&1);
AQuery.in_db_mut(&mut db).invalidate(&1);
assert_eq!(db.b(1), 92);
assert_eq!(db.a(1), 92);
}

View file

@ -2,7 +2,6 @@ use rand::seq::SliceRandom;
use rand::Rng;
use salsa::Database;
use salsa::DatabaseQueryExt;
use salsa::ParallelDatabase;
use salsa::Snapshot;
use salsa::SweepStrategy;
@ -162,13 +161,13 @@ impl ReadOp {
},
ReadOp::Gc(query, strategy) => match query {
Query::A => {
db.query(AQuery).sweep(strategy);
AQuery.in_db(db).sweep(strategy);
}
Query::B => {
db.query(BQuery).sweep(strategy);
BQuery.in_db(db).sweep(strategy);
}
Query::C => {
db.query(CQuery).sweep(strategy);
CQuery.in_db(db).sweep(strategy);
}
},
ReadOp::GcAll(strategy) => {