mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-08-04 11:00:05 +00:00
remove the DB
parameter
This had two unexpected consequences, one unfortunate, one "medium": * All `salsa::Database` must be `'static`. This falls out from `Q::DynDb` not having access to any lifetimes, but also the defaulting rules for `dyn QueryGroup` that make it `dyn QueryGroup + 'static`. We don't really support generic databases anyway yet so this isn't a big deal, and we can add workarounds later (ideally via GATs). * It is now statically impossible to invoke `snapshot` from a query, and so we don't need to test that it panics. This is because the signature of `snapshot` returns a `Snapshot<Self>` and that is not accessible to a `dyn QueryGroup` type. Similarly, invoking `Runtime::snapshot` directly is not possible becaues it is crate-private. So I removed the test. This seems ok, but eventually I would like to expose ways for queries to do parallel execution (matklad and I had talked about a "speculation" primitive for enabling that). * This commit is 99% boilerplate I did with search-and-replace. I also rolled in a few other changes I might have preferred to factor out, most notably removing the `GetQueryTable` plumbing trait in favor of free-methods, but it was awkward to factor them out and get all the generics right (so much simpler in this version).
This commit is contained in:
parent
d64dfa1727
commit
fad97eeb6a
36 changed files with 410 additions and 455 deletions
|
@ -25,7 +25,7 @@ trait FileWatcher {
|
|||
fn did_change_file(&mut self, path: &Path);
|
||||
}
|
||||
|
||||
fn read(db: &impl salsa::Database, path: PathBuf) -> String {
|
||||
fn read(db: &dyn salsa::Database, path: PathBuf) -> String {
|
||||
db.salsa_runtime()
|
||||
.report_synthetic_read(salsa::Durability::LOW);
|
||||
db.watch(&path);
|
||||
|
|
|
@ -30,7 +30,7 @@ pub(crate) fn database(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
.iter()
|
||||
.map(|QueryGroup { group_path }| {
|
||||
quote! {
|
||||
<#group_path as salsa::plumbing::QueryGroup<#database_name>>::GroupStorage
|
||||
<#group_path as salsa::plumbing::QueryGroup>::GroupStorage
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -63,8 +63,8 @@ pub(crate) fn database(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
// ANCHOR:HasQueryGroup
|
||||
has_group_impls.extend(quote! {
|
||||
impl salsa::plumbing::HasQueryGroup<#group_path> for #database_name {
|
||||
fn group_storage(db: &Self) -> &#group_storage {
|
||||
&db.#db_storage_field.query_store().#group_name_snake
|
||||
fn group_storage(&self) -> &#group_storage {
|
||||
&self.#db_storage_field.query_store().#group_name_snake
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -91,7 +91,7 @@ pub(crate) fn database(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
let mut database_data = vec![];
|
||||
for QueryGroup { group_path } in query_groups {
|
||||
database_data.push(quote! {
|
||||
<#group_path as salsa::plumbing::QueryGroup<#database_name>>::GroupData
|
||||
<#group_path as salsa::plumbing::QueryGroup>::GroupData
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
let trait_vis = input.vis;
|
||||
let trait_name = input.ident;
|
||||
let _generics = input.generics.clone();
|
||||
let dyn_db = quote! { dyn #trait_name };
|
||||
|
||||
// Decompose the trait into the corresponding queries.
|
||||
let mut queries = vec![];
|
||||
|
@ -212,7 +213,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
|
||||
query_fn_definitions.extend(quote! {
|
||||
fn #fn_name(&self, #(#key_names: #keys),*) -> #value {
|
||||
<Self as salsa::plumbing::GetQueryTable<#qt>>::get_query_table(self).get((#(#key_names),*))
|
||||
salsa::plumbing::get_query_table::<#qt>(self).get((#(#key_names),*))
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -260,11 +261,11 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
|
||||
query_fn_definitions.extend(quote! {
|
||||
fn #set_fn_name(&mut self, #(#key_names: #keys,)* value__: #value) {
|
||||
<Self as salsa::plumbing::GetQueryTable<#qt>>::get_query_table_mut(self).set((#(#key_names),*), value__)
|
||||
salsa::plumbing::get_query_table_mut::<#qt>(self).set((#(#key_names),*), value__)
|
||||
}
|
||||
|
||||
fn #set_with_durability_fn_name(&mut self, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability) {
|
||||
<Self as salsa::plumbing::GetQueryTable<#qt>>::get_query_table_mut(self).set_with_durability((#(#key_names),*), value__, durability__)
|
||||
salsa::plumbing::get_query_table_mut::<#qt>(self).set_with_durability((#(#key_names),*), value__, durability__)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -273,7 +274,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
//
|
||||
// FIXME(#120): the pub should not be necessary once we complete the transition
|
||||
storage_fields.extend(quote! {
|
||||
pub #fn_name: std::sync::Arc<<#qt as salsa::Query<DB__>>::Storage>,
|
||||
pub #fn_name: std::sync::Arc<<#qt as salsa::Query>::Storage>,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -282,7 +283,11 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
let bounds = &input.supertraits;
|
||||
quote! {
|
||||
#(#trait_attrs)*
|
||||
#trait_vis trait #trait_name : #bounds {
|
||||
#trait_vis trait #trait_name :
|
||||
salsa::Database +
|
||||
salsa::plumbing::HasQueryGroup<#group_struct> +
|
||||
#bounds
|
||||
{
|
||||
#query_fn_declarations
|
||||
}
|
||||
}
|
||||
|
@ -293,13 +298,10 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
/// Representative struct for the query group.
|
||||
#trait_vis struct #group_struct { }
|
||||
|
||||
impl<DB__> salsa::plumbing::QueryGroup<DB__> for #group_struct
|
||||
where
|
||||
DB__: #trait_name,
|
||||
DB__: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
DB__: salsa::Database,
|
||||
impl salsa::plumbing::QueryGroup for #group_struct
|
||||
{
|
||||
type GroupStorage = #group_storage<DB__>;
|
||||
type DynDb = #dyn_db;
|
||||
type GroupStorage = #group_storage;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -307,10 +309,11 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
output.extend({
|
||||
let bounds = input.supertraits.clone();
|
||||
quote! {
|
||||
impl<T> #trait_name for T
|
||||
impl<DB> #trait_name for DB
|
||||
where
|
||||
T: #bounds,
|
||||
T: salsa::plumbing::HasQueryGroup<#group_struct>
|
||||
DB: #bounds,
|
||||
DB: salsa::Database,
|
||||
DB: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
{
|
||||
#query_fn_definitions
|
||||
}
|
||||
|
@ -329,15 +332,13 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
let fn_name = &query.fn_name;
|
||||
let qt = &query.query_type;
|
||||
|
||||
let db = quote! {DB};
|
||||
|
||||
let storage = match &query.storage {
|
||||
QueryStorage::Memoized => quote!(salsa::plumbing::MemoizedStorage<#db, Self>),
|
||||
QueryStorage::Dependencies => quote!(salsa::plumbing::DependencyStorage<#db, Self>),
|
||||
QueryStorage::Input => quote!(salsa::plumbing::InputStorage<#db, Self>),
|
||||
QueryStorage::Interned => quote!(salsa::plumbing::InternedStorage<#db, Self>),
|
||||
QueryStorage::Memoized => quote!(salsa::plumbing::MemoizedStorage<Self>),
|
||||
QueryStorage::Dependencies => quote!(salsa::plumbing::DependencyStorage<Self>),
|
||||
QueryStorage::Input => quote!(salsa::plumbing::InputStorage<Self>),
|
||||
QueryStorage::Interned => quote!(salsa::plumbing::InternedStorage<Self>),
|
||||
QueryStorage::InternedLookup { intern_query_type } => {
|
||||
quote!(salsa::plumbing::LookupInternedStorage<#db, Self, #intern_query_type>)
|
||||
quote!(salsa::plumbing::LookupInternedStorage<Self, #intern_query_type>)
|
||||
}
|
||||
QueryStorage::Transparent => panic!("should have been filtered"),
|
||||
};
|
||||
|
@ -356,12 +357,9 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
/// 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>,
|
||||
#trait_vis fn in_db(self, db: &#dyn_db) -> salsa::QueryTable<'_, Self>
|
||||
{
|
||||
<DB as salsa::plumbing::GetQueryTable<Self>>::get_query_table(db)
|
||||
salsa::plumbing::get_query_table::<#qt>(db)
|
||||
}
|
||||
|
||||
/// Like `in_db`, but gives access to methods for setting the
|
||||
|
@ -391,28 +389,22 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
/// 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>,
|
||||
#trait_vis fn in_db_mut(self, db: &mut #dyn_db) -> salsa::QueryTableMut<'_, Self>
|
||||
{
|
||||
<DB as salsa::plumbing::GetQueryTable<Self>>::get_query_table_mut(db)
|
||||
salsa::plumbing::get_query_table_mut::<#qt>(db)
|
||||
}
|
||||
}
|
||||
|
||||
// Unsafe proof obligation: that our key/value are a part
|
||||
// of the `GroupData`.
|
||||
impl<#db> salsa::Query<#db> for #qt
|
||||
where
|
||||
DB: #trait_name,
|
||||
DB: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
DB: salsa::Database,
|
||||
impl salsa::Query for #qt
|
||||
{
|
||||
type Key = (#(#keys),*);
|
||||
type Value = #value;
|
||||
type Storage = #storage;
|
||||
type Group = #group_struct;
|
||||
type GroupStorage = #group_storage<#db>;
|
||||
type GroupStorage = #group_storage;
|
||||
type DynDb = #dyn_db;
|
||||
|
||||
const QUERY_INDEX: u16 = #query_index;
|
||||
|
||||
|
@ -441,8 +433,8 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
|
||||
let recover = if let Some(cycle_recovery_fn) = &query.cycle {
|
||||
quote! {
|
||||
fn recover(db: &DB, cycle: &[salsa::DatabaseKeyIndex], #key_pattern: &<Self as salsa::Query<DB>>::Key)
|
||||
-> Option<<Self as salsa::Query<DB>>::Value> {
|
||||
fn recover(db: &Self::DynDb, cycle: &[salsa::DatabaseKeyIndex], #key_pattern: &<Self as salsa::Query>::Key)
|
||||
-> Option<<Self as salsa::Query>::Value> {
|
||||
Some(#cycle_recovery_fn(
|
||||
db,
|
||||
&cycle.iter().map(|k| format!("{:?}", k.debug(db))).collect::<Vec<String>>(),
|
||||
|
@ -455,14 +447,10 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
};
|
||||
|
||||
output.extend(quote_spanned! {span=>
|
||||
impl<DB> salsa::plumbing::QueryFunction<DB> for #qt
|
||||
where
|
||||
DB: #trait_name,
|
||||
DB: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
DB: salsa::Database,
|
||||
impl salsa::plumbing::QueryFunction for #qt
|
||||
{
|
||||
fn execute(db: &DB, #key_pattern: <Self as salsa::Query<DB>>::Key)
|
||||
-> <Self as salsa::Query<DB>>::Value {
|
||||
fn execute(db: &Self::DynDb, #key_pattern: <Self as salsa::Query>::Key)
|
||||
-> <Self as salsa::Query>::Value {
|
||||
#invoke(db, #(#key_names),*)
|
||||
}
|
||||
|
||||
|
@ -503,21 +491,11 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
|
||||
// Emit query group storage struct
|
||||
output.extend(quote! {
|
||||
#trait_vis struct #group_storage<DB__>
|
||||
where
|
||||
DB__: #trait_name,
|
||||
DB__: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
DB__: salsa::Database,
|
||||
{
|
||||
#trait_vis struct #group_storage {
|
||||
#storage_fields
|
||||
}
|
||||
|
||||
impl<DB__> #group_storage<DB__>
|
||||
where
|
||||
DB__: #trait_name,
|
||||
DB__: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
DB__: salsa::Database,
|
||||
{
|
||||
impl #group_storage {
|
||||
#trait_vis fn new(group_index: u16) -> Self {
|
||||
#group_storage {
|
||||
#(
|
||||
|
@ -528,14 +506,10 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB__> #group_storage<DB__>
|
||||
where
|
||||
DB__: #trait_name,
|
||||
DB__: salsa::plumbing::HasQueryGroup<#group_struct>,
|
||||
{
|
||||
impl #group_storage {
|
||||
#trait_vis fn fmt_index(
|
||||
&self,
|
||||
db: &DB__,
|
||||
db: &#dyn_db,
|
||||
input: salsa::DatabaseKeyIndex,
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
|
@ -547,7 +521,7 @@ pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream
|
|||
|
||||
#trait_vis fn maybe_changed_since(
|
||||
&self,
|
||||
db: &DB__,
|
||||
db: &#dyn_db,
|
||||
input: salsa::DatabaseKeyIndex,
|
||||
revision: salsa::Revision,
|
||||
) -> bool {
|
||||
|
|
|
@ -28,7 +28,7 @@ pub trait Compiler: Interner {
|
|||
/// dolor,sit,amet,
|
||||
/// consectetur,adipiscing,elit
|
||||
/// ```
|
||||
fn all_classes(db: &impl Compiler) -> Arc<Vec<Class>> {
|
||||
fn all_classes(db: &dyn Compiler) -> Arc<Vec<Class>> {
|
||||
let string = db.input_string();
|
||||
|
||||
let rows = string.split('\n');
|
||||
|
@ -53,13 +53,13 @@ fn all_classes(db: &impl Compiler) -> Arc<Vec<Class>> {
|
|||
Arc::new(classes)
|
||||
}
|
||||
|
||||
fn fields(db: &impl Compiler, class: Class) -> Arc<Vec<Field>> {
|
||||
fn fields(db: &dyn Compiler, class: Class) -> Arc<Vec<Field>> {
|
||||
let class = db.lookup_intern_class(class);
|
||||
let fields = class.fields.clone();
|
||||
Arc::new(fields)
|
||||
}
|
||||
|
||||
fn all_fields(db: &impl Compiler) -> Arc<Vec<Field>> {
|
||||
fn all_fields(db: &dyn Compiler) -> Arc<Vec<Field>> {
|
||||
Arc::new(
|
||||
db.all_classes()
|
||||
.iter()
|
||||
|
|
|
@ -51,7 +51,7 @@ trait HelloWorld: salsa::Database {
|
|||
// all of the queries in the system -- we never know the concrete type
|
||||
// here, we only know the subset of methods we care about (defined by
|
||||
// the `HelloWorld` trait we specified above).
|
||||
fn length(db: &impl HelloWorld, (): ()) -> usize {
|
||||
fn length(db: &dyn HelloWorld, (): ()) -> usize {
|
||||
// Read the input string:
|
||||
let input_string = db.input_string(());
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ trait RequestParser {
|
|||
}
|
||||
// ANCHOR_END: request
|
||||
|
||||
fn parse(_db: &impl RequestParser) -> ParsedResult {
|
||||
fn parse(_db: &dyn RequestParser) -> ParsedResult {
|
||||
panic!()
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ trait RequestUtil: RequestParser {
|
|||
fn content_type(&self) -> Option<String>;
|
||||
}
|
||||
|
||||
fn content_type(db: &impl RequestUtil) -> Option<String> {
|
||||
fn content_type(db: &dyn RequestUtil) -> Option<String> {
|
||||
db.parse()
|
||||
.header
|
||||
.iter()
|
||||
|
|
|
@ -7,11 +7,11 @@ trait RequestUtil: RequestParser {
|
|||
fn content_type(&self) -> Option<String>;
|
||||
}
|
||||
|
||||
fn header(db: &impl RequestUtil) -> Vec<ParsedHeader> {
|
||||
fn header(db: &dyn RequestUtil) -> Vec<ParsedHeader> {
|
||||
db.parse().header.clone()
|
||||
}
|
||||
|
||||
fn content_type(db: &impl RequestUtil) -> Option<String> {
|
||||
fn content_type(db: &dyn RequestUtil) -> Option<String> {
|
||||
db.header()
|
||||
.iter()
|
||||
.find(|header| header.key == "content-type")
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
//! debugging your application but aren't ordinarily needed.
|
||||
|
||||
use crate::durability::Durability;
|
||||
use crate::plumbing;
|
||||
use crate::plumbing::QueryStorageOps;
|
||||
use crate::Query;
|
||||
use crate::QueryTable;
|
||||
|
@ -50,10 +49,9 @@ impl<K, V> TableEntry<K, V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> DebugQueryTable for QueryTable<'_, DB, Q>
|
||||
impl<Q> DebugQueryTable for QueryTable<'_, Q>
|
||||
where
|
||||
DB: plumbing::GetQueryTable<Q>,
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
{
|
||||
type Key = Q::Key;
|
||||
type Value = Q::Value;
|
||||
|
|
|
@ -2,7 +2,6 @@ use crate::debug::TableEntry;
|
|||
use crate::durability::Durability;
|
||||
use crate::lru::Lru;
|
||||
use crate::plumbing::DerivedQueryStorageOps;
|
||||
use crate::plumbing::HasQueryGroup;
|
||||
use crate::plumbing::LruQueryStorageOps;
|
||||
use crate::plumbing::QueryFunction;
|
||||
use crate::plumbing::QueryStorageMassOps;
|
||||
|
@ -20,41 +19,38 @@ use slot::Slot;
|
|||
/// Memoized queries store the result plus a list of the other queries
|
||||
/// that they invoked. This means we can avoid recomputing them when
|
||||
/// none of those inputs have changed.
|
||||
pub type MemoizedStorage<DB, Q> = DerivedStorage<DB, Q, AlwaysMemoizeValue>;
|
||||
pub type MemoizedStorage<Q> = DerivedStorage<Q, AlwaysMemoizeValue>;
|
||||
|
||||
/// "Dependency" queries just track their dependencies and not the
|
||||
/// actual value (which they produce on demand). This lessens the
|
||||
/// storage requirements.
|
||||
pub type DependencyStorage<DB, Q> = DerivedStorage<DB, Q, NeverMemoizeValue>;
|
||||
pub type DependencyStorage<Q> = DerivedStorage<Q, NeverMemoizeValue>;
|
||||
|
||||
/// Handles storage where the value is 'derived' by executing a
|
||||
/// function (in contrast to "inputs").
|
||||
pub struct DerivedStorage<DB, Q, MP>
|
||||
pub struct DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
group_index: u16,
|
||||
lru_list: Lru<Slot<DB, Q, MP>>,
|
||||
slot_map: RwLock<FxIndexMap<Q::Key, Arc<Slot<DB, Q, MP>>>>,
|
||||
lru_list: Lru<Slot<Q, MP>>,
|
||||
slot_map: RwLock<FxIndexMap<Q::Key, Arc<Slot<Q, MP>>>>,
|
||||
policy: PhantomData<MP>,
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> std::panic::RefUnwindSafe for DerivedStorage<DB, Q, MP>
|
||||
impl<Q, MP> std::panic::RefUnwindSafe for DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
Q::Key: std::panic::RefUnwindSafe,
|
||||
Q::Value: std::panic::RefUnwindSafe,
|
||||
{
|
||||
}
|
||||
|
||||
pub trait MemoizationPolicy<DB, Q>: Send + Sync + 'static
|
||||
pub trait MemoizationPolicy<Q>: Send + Sync + 'static
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database,
|
||||
Q: QueryFunction,
|
||||
{
|
||||
fn should_memoize_value(key: &Q::Key) -> bool;
|
||||
|
||||
|
@ -62,11 +58,10 @@ where
|
|||
}
|
||||
|
||||
pub enum AlwaysMemoizeValue {}
|
||||
impl<DB, Q> MemoizationPolicy<DB, Q> for AlwaysMemoizeValue
|
||||
impl<Q> MemoizationPolicy<Q> for AlwaysMemoizeValue
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
Q: QueryFunction,
|
||||
Q::Value: Eq,
|
||||
DB: Database,
|
||||
{
|
||||
fn should_memoize_value(_key: &Q::Key) -> bool {
|
||||
true
|
||||
|
@ -78,10 +73,9 @@ where
|
|||
}
|
||||
|
||||
pub enum NeverMemoizeValue {}
|
||||
impl<DB, Q> MemoizationPolicy<DB, Q> for NeverMemoizeValue
|
||||
impl<Q> MemoizationPolicy<Q> for NeverMemoizeValue
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database,
|
||||
Q: QueryFunction,
|
||||
{
|
||||
fn should_memoize_value(_key: &Q::Key) -> bool {
|
||||
false
|
||||
|
@ -92,13 +86,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> DerivedStorage<DB, Q, MP>
|
||||
impl<Q, MP> DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn slot(&self, key: &Q::Key) -> Arc<Slot<DB, Q, MP>> {
|
||||
fn slot(&self, key: &Q::Key) -> Arc<Slot<Q, MP>> {
|
||||
if let Some(v) = self.slot_map.read().get(key) {
|
||||
return v.clone();
|
||||
}
|
||||
|
@ -117,11 +110,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> QueryStorageOps<DB, Q> for DerivedStorage<DB, Q, MP>
|
||||
impl<Q, MP> QueryStorageOps<Q> for DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn new(group_index: u16) -> Self {
|
||||
DerivedStorage {
|
||||
|
@ -134,7 +126,7 @@ where
|
|||
|
||||
fn fmt_index(
|
||||
&self,
|
||||
_db: &DB,
|
||||
_db: &Q::DynDb,
|
||||
index: DatabaseKeyIndex,
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
|
@ -145,7 +137,12 @@ where
|
|||
write!(fmt, "{}({:?})", Q::QUERY_NAME, key)
|
||||
}
|
||||
|
||||
fn maybe_changed_since(&self, db: &DB, input: DatabaseKeyIndex, revision: Revision) -> bool {
|
||||
fn maybe_changed_since(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
input: DatabaseKeyIndex,
|
||||
revision: Revision,
|
||||
) -> bool {
|
||||
assert_eq!(input.group_index, self.group_index);
|
||||
assert_eq!(input.query_index, Q::QUERY_INDEX);
|
||||
let slot = self
|
||||
|
@ -158,7 +155,11 @@ where
|
|||
slot.maybe_changed_since(db, revision)
|
||||
}
|
||||
|
||||
fn try_fetch(&self, db: &DB, key: &Q::Key) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
fn try_fetch(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
key: &Q::Key,
|
||||
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
let slot = self.slot(key);
|
||||
let StampedValue {
|
||||
value,
|
||||
|
@ -176,11 +177,11 @@ where
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
fn durability(&self, db: &DB, key: &Q::Key) -> Durability {
|
||||
fn durability(&self, db: &Q::DynDb, key: &Q::Key) -> Durability {
|
||||
self.slot(key).durability(db)
|
||||
}
|
||||
|
||||
fn entries<C>(&self, _db: &DB) -> C
|
||||
fn entries<C>(&self, _db: &Q::DynDb) -> C
|
||||
where
|
||||
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
|
||||
{
|
||||
|
@ -192,11 +193,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> QueryStorageMassOps for DerivedStorage<DB, Q, MP>
|
||||
impl<Q, MP> QueryStorageMassOps for DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn sweep(&self, runtime: &Runtime, strategy: SweepStrategy) {
|
||||
let map_read = self.slot_map.read();
|
||||
|
@ -207,24 +207,22 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> LruQueryStorageOps for DerivedStorage<DB, Q, MP>
|
||||
impl<Q, MP> LruQueryStorageOps for DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn set_lru_capacity(&self, new_capacity: usize) {
|
||||
self.lru_list.set_lru_capacity(new_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> DerivedQueryStorageOps<DB, Q> for DerivedStorage<DB, Q, MP>
|
||||
impl<Q, MP> DerivedQueryStorageOps<Q> for DerivedStorage<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn invalidate(&self, db: &mut DB, key: &Q::Key) {
|
||||
fn invalidate(&self, db: &mut Q::DynDb, key: &Q::Key) {
|
||||
db.salsa_runtime_mut()
|
||||
.with_incremented_revision(&mut |_new_revision| {
|
||||
let map_read = self.slot_map.read();
|
||||
|
|
|
@ -5,8 +5,7 @@ use crate::durability::Durability;
|
|||
use crate::lru::LruIndex;
|
||||
use crate::lru::LruNode;
|
||||
use crate::plumbing::CycleDetected;
|
||||
use crate::plumbing::HasQueryGroup;
|
||||
use crate::plumbing::QueryFunction;
|
||||
use crate::plumbing::{DatabaseOps, QueryFunction};
|
||||
use crate::revision::Revision;
|
||||
use crate::runtime::Runtime;
|
||||
use crate::runtime::RuntimeId;
|
||||
|
@ -22,15 +21,14 @@ use std::marker::PhantomData;
|
|||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub(super) struct Slot<DB, Q, MP>
|
||||
pub(super) struct Slot<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
key: Q::Key,
|
||||
database_key_index: DatabaseKeyIndex,
|
||||
state: RwLock<QueryState<DB, Q>>,
|
||||
state: RwLock<QueryState<Q>>,
|
||||
policy: PhantomData<MP>,
|
||||
lru_index: LruIndex,
|
||||
}
|
||||
|
@ -42,10 +40,9 @@ struct WaitResult<V, K> {
|
|||
}
|
||||
|
||||
/// Defines the "current state" of query's memoized results.
|
||||
enum QueryState<DB, Q>
|
||||
enum QueryState<Q>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction,
|
||||
{
|
||||
NotComputed,
|
||||
|
||||
|
@ -58,13 +55,12 @@ where
|
|||
},
|
||||
|
||||
/// We have computed the query already, and here is the result.
|
||||
Memoized(Memo<DB, Q>),
|
||||
Memoized(Memo<Q>),
|
||||
}
|
||||
|
||||
struct Memo<DB, Q>
|
||||
struct Memo<Q>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction,
|
||||
{
|
||||
/// The result of the query, if we decide to memoize it.
|
||||
value: Option<Q::Value>,
|
||||
|
@ -103,11 +99,10 @@ enum ProbeState<V, K, G> {
|
|||
StaleOrAbsent(G),
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> Slot<DB, Q, MP>
|
||||
impl<Q, MP> Slot<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
pub(super) fn new(key: Q::Key, database_key_index: DatabaseKeyIndex) -> Self {
|
||||
Self {
|
||||
|
@ -125,7 +120,7 @@ where
|
|||
|
||||
pub(super) fn read(
|
||||
&self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
) -> Result<StampedValue<Q::Value>, CycleError<DatabaseKeyIndex>> {
|
||||
let runtime = db.salsa_runtime();
|
||||
|
||||
|
@ -153,7 +148,7 @@ where
|
|||
/// shows a potentially out of date value.
|
||||
fn read_upgrade(
|
||||
&self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
revision_now: Revision,
|
||||
) -> Result<StampedValue<Q::Value>, CycleError<DatabaseKeyIndex>> {
|
||||
let runtime = db.salsa_runtime();
|
||||
|
@ -324,13 +319,13 @@ where
|
|||
/// Note that in case `ProbeState::UpToDate`, the lock will have been released.
|
||||
fn probe<StateGuard>(
|
||||
&self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
state: StateGuard,
|
||||
runtime: &Runtime,
|
||||
revision_now: Revision,
|
||||
) -> ProbeState<StampedValue<Q::Value>, DatabaseKeyIndex, StateGuard>
|
||||
where
|
||||
StateGuard: Deref<Target = QueryState<DB, Q>>,
|
||||
StateGuard: Deref<Target = QueryState<Q>>,
|
||||
{
|
||||
match &*state {
|
||||
QueryState::NotComputed => { /* fall through */ }
|
||||
|
@ -417,7 +412,7 @@ where
|
|||
ProbeState::StaleOrAbsent(state)
|
||||
}
|
||||
|
||||
pub(super) fn durability(&self, db: &DB) -> Durability {
|
||||
pub(super) fn durability(&self, db: &Q::DynDb) -> Durability {
|
||||
match &*self.state.read() {
|
||||
QueryState::NotComputed => Durability::LOW,
|
||||
QueryState::InProgress { .. } => panic!("query in progress"),
|
||||
|
@ -530,7 +525,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn maybe_changed_since(&self, db: &DB, revision: Revision) -> bool {
|
||||
pub(super) fn maybe_changed_since(&self, db: &Q::DynDb, revision: Revision) -> bool {
|
||||
let runtime = db.salsa_runtime();
|
||||
let revision_now = runtime.current_revision();
|
||||
|
||||
|
@ -719,7 +714,7 @@ where
|
|||
/// computed (but first drop the lock on the map).
|
||||
fn register_with_in_progress_thread(
|
||||
&self,
|
||||
_db: &DB,
|
||||
_db: &Q::DynDb,
|
||||
runtime: &Runtime,
|
||||
other_id: RuntimeId,
|
||||
waiting: &Mutex<SmallVec<[Promise<WaitResult<Q::Value, DatabaseKeyIndex>>; 2]>>,
|
||||
|
@ -750,10 +745,9 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> QueryState<DB, Q>
|
||||
impl<Q> QueryState<Q>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction,
|
||||
{
|
||||
fn in_progress(id: RuntimeId) -> Self {
|
||||
QueryState::InProgress {
|
||||
|
@ -763,28 +757,26 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct PanicGuard<'me, DB, Q, MP>
|
||||
struct PanicGuard<'me, Q, MP>
|
||||
where
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction<DB>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
database_key_index: DatabaseKeyIndex,
|
||||
slot: &'me Slot<DB, Q, MP>,
|
||||
memo: Option<Memo<DB, Q>>,
|
||||
slot: &'me Slot<Q, MP>,
|
||||
memo: Option<Memo<Q>>,
|
||||
runtime: &'me Runtime,
|
||||
}
|
||||
|
||||
impl<'me, DB, Q, MP> PanicGuard<'me, DB, Q, MP>
|
||||
impl<'me, Q, MP> PanicGuard<'me, Q, MP>
|
||||
where
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction<DB>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn new(
|
||||
database_key_index: DatabaseKeyIndex,
|
||||
slot: &'me Slot<DB, Q, MP>,
|
||||
memo: Option<Memo<DB, Q>>,
|
||||
slot: &'me Slot<Q, MP>,
|
||||
memo: Option<Memo<Q>>,
|
||||
runtime: &'me Runtime,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -864,11 +856,10 @@ Please report this bug to https://github.com/salsa-rs/salsa/issues."
|
|||
}
|
||||
}
|
||||
|
||||
impl<'me, DB, Q, MP> Drop for PanicGuard<'me, DB, Q, MP>
|
||||
impl<'me, Q, MP> Drop for PanicGuard<'me, Q, MP>
|
||||
where
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction<DB>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn drop(&mut self) {
|
||||
if std::thread::panicking() {
|
||||
|
@ -882,13 +873,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> Memo<DB, Q>
|
||||
impl<Q> Memo<Q>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
Q: QueryFunction,
|
||||
{
|
||||
/// True if this memo is known not to have changed based on its durability.
|
||||
fn check_durability(&self, db: &DB) -> bool {
|
||||
fn check_durability(&self, db: &Q::DynDb) -> bool {
|
||||
let last_changed = db.salsa_runtime().last_changed_revision(self.durability);
|
||||
debug!(
|
||||
"check_durability(last_changed={:?} <= verified_at={:?}) = {:?}",
|
||||
|
@ -901,7 +891,7 @@ where
|
|||
|
||||
fn validate_memoized_value(
|
||||
&mut self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
revision_now: Revision,
|
||||
) -> Option<StampedValue<Q::Value>> {
|
||||
// If we don't have a memoized value, nothing to validate.
|
||||
|
@ -983,11 +973,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> std::fmt::Debug for Slot<DB, Q, MP>
|
||||
impl<Q, MP> std::fmt::Debug for Slot<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(fmt, "{:?}({:?})", Q::default(), self.key)
|
||||
|
@ -1006,46 +995,42 @@ impl std::fmt::Debug for MemoInputs {
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, MP> LruNode for Slot<DB, Q, MP>
|
||||
impl<Q, MP> LruNode for Slot<Q, MP>
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
{
|
||||
fn lru_index(&self) -> &LruIndex {
|
||||
&self.lru_index
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that `Slot<DB, Q, MP>: Send + Sync` as long as
|
||||
/// Check that `Slot<Q, MP>: Send + Sync` as long as
|
||||
/// `DB::DatabaseData: Send + Sync`, which in turn implies that
|
||||
/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
|
||||
#[allow(dead_code)]
|
||||
fn check_send_sync<DB, Q, MP>()
|
||||
fn check_send_sync<Q, MP>()
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
Q::Key: Send + Sync,
|
||||
Q::Value: Send + Sync,
|
||||
{
|
||||
fn is_send_sync<T: Send + Sync>() {}
|
||||
is_send_sync::<Slot<DB, Q, MP>>();
|
||||
is_send_sync::<Slot<Q, MP>>();
|
||||
}
|
||||
|
||||
/// Check that `Slot<DB, Q, MP>: 'static` as long as
|
||||
/// Check that `Slot<Q, MP>: 'static` as long as
|
||||
/// `DB::DatabaseData: 'static`, which in turn implies that
|
||||
/// `Q::Key: 'static`, `Q::Value: 'static`.
|
||||
#[allow(dead_code)]
|
||||
fn check_static<DB, Q, MP>()
|
||||
fn check_static<Q, MP>()
|
||||
where
|
||||
Q: QueryFunction<DB>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
MP: MemoizationPolicy<DB, Q>,
|
||||
DB: 'static,
|
||||
Q: QueryFunction,
|
||||
MP: MemoizationPolicy<Q>,
|
||||
Q::Key: 'static,
|
||||
Q::Value: 'static,
|
||||
{
|
||||
fn is_static<T: 'static>() {}
|
||||
is_static::<Slot<DB, Q, MP>>();
|
||||
is_static::<Slot<Q, MP>>();
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
/// fn no_send_sync_key(&self, key: Rc<bool>) -> bool;
|
||||
/// }
|
||||
///
|
||||
/// fn no_send_sync_value(_db: &impl NoSendSyncDatabase, key: bool) -> Rc<bool> {
|
||||
/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Rc<bool> {
|
||||
/// Rc::new(key)
|
||||
/// }
|
||||
///
|
||||
/// fn no_send_sync_key(_db: &impl NoSendSyncDatabase, key: Rc<bool>) -> bool {
|
||||
/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Rc<bool>) -> bool {
|
||||
/// *key
|
||||
/// }
|
||||
///
|
||||
|
@ -57,11 +57,11 @@ fn test_key_not_send_db_not_send() {}
|
|||
/// fn no_send_sync_key(&self, key: Cell<bool>) -> bool;
|
||||
/// }
|
||||
///
|
||||
/// fn no_send_sync_value(_db: &impl NoSendSyncDatabase, key: bool) -> Cell<bool> {
|
||||
/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Cell<bool> {
|
||||
/// Cell::new(key)
|
||||
/// }
|
||||
///
|
||||
/// fn no_send_sync_key(_db: &impl NoSendSyncDatabase, key: Cell<bool>) -> bool {
|
||||
/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Cell<bool>) -> bool {
|
||||
/// *key
|
||||
/// }
|
||||
///
|
||||
|
@ -102,11 +102,11 @@ fn test_key_not_sync_db_not_send() {}
|
|||
/// fn no_send_sync_key(&self, key: Cell<bool>) -> bool;
|
||||
/// }
|
||||
///
|
||||
/// fn no_send_sync_value(_db: &impl NoSendSyncDatabase, key: bool) -> Cell<bool> {
|
||||
/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Cell<bool> {
|
||||
/// Cell::new(key)
|
||||
/// }
|
||||
///
|
||||
/// fn no_send_sync_key(_db: &impl NoSendSyncDatabase, key: Cell<bool>) -> bool {
|
||||
/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Cell<bool>) -> bool {
|
||||
/// *key
|
||||
/// }
|
||||
///
|
||||
|
|
91
src/input.rs
91
src/input.rs
|
@ -18,48 +18,43 @@ use std::sync::Arc;
|
|||
/// Input queries store the result plus a list of the other queries
|
||||
/// that they invoked. This means we can avoid recomputing them when
|
||||
/// none of those inputs have changed.
|
||||
pub struct InputStorage<DB, Q>
|
||||
pub struct InputStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
group_index: u16,
|
||||
slots: RwLock<FxIndexMap<Q::Key, Arc<Slot<DB, Q>>>>,
|
||||
slots: RwLock<FxIndexMap<Q::Key, Arc<Slot<Q>>>>,
|
||||
}
|
||||
|
||||
struct Slot<DB, Q>
|
||||
struct Slot<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
key: Q::Key,
|
||||
database_key_index: DatabaseKeyIndex,
|
||||
stamped_value: RwLock<StampedValue<Q::Value>>,
|
||||
}
|
||||
|
||||
impl<DB, Q> std::panic::RefUnwindSafe for InputStorage<DB, Q>
|
||||
impl<Q> std::panic::RefUnwindSafe for InputStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
Q::Key: std::panic::RefUnwindSafe,
|
||||
Q::Value: std::panic::RefUnwindSafe,
|
||||
{
|
||||
}
|
||||
|
||||
impl<DB, Q> InputStorage<DB, Q>
|
||||
impl<Q> InputStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
fn slot(&self, key: &Q::Key) -> Option<Arc<Slot<DB, Q>>> {
|
||||
fn slot(&self, key: &Q::Key) -> Option<Arc<Slot<Q>>> {
|
||||
self.slots.read().get(key).cloned()
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> QueryStorageOps<DB, Q> for InputStorage<DB, Q>
|
||||
impl<Q> QueryStorageOps<Q> for InputStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
fn new(group_index: u16) -> Self {
|
||||
InputStorage {
|
||||
|
@ -70,7 +65,7 @@ where
|
|||
|
||||
fn fmt_index(
|
||||
&self,
|
||||
_db: &DB,
|
||||
_db: &Q::DynDb,
|
||||
index: DatabaseKeyIndex,
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
|
@ -81,7 +76,12 @@ where
|
|||
write!(fmt, "{}({:?})", Q::QUERY_NAME, key)
|
||||
}
|
||||
|
||||
fn maybe_changed_since(&self, db: &DB, input: DatabaseKeyIndex, revision: Revision) -> bool {
|
||||
fn maybe_changed_since(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
input: DatabaseKeyIndex,
|
||||
revision: Revision,
|
||||
) -> bool {
|
||||
assert_eq!(input.group_index, self.group_index);
|
||||
assert_eq!(input.query_index, Q::QUERY_INDEX);
|
||||
let slot = self
|
||||
|
@ -94,7 +94,11 @@ where
|
|||
slot.maybe_changed_since(db, revision)
|
||||
}
|
||||
|
||||
fn try_fetch(&self, db: &DB, key: &Q::Key) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
fn try_fetch(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
key: &Q::Key,
|
||||
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
let slot = self
|
||||
.slot(key)
|
||||
.unwrap_or_else(|| panic!("no value set for {:?}({:?})", Q::default(), key));
|
||||
|
@ -111,14 +115,14 @@ where
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
fn durability(&self, _db: &DB, key: &Q::Key) -> Durability {
|
||||
fn durability(&self, _db: &Q::DynDb, key: &Q::Key) -> Durability {
|
||||
match self.slot(key) {
|
||||
Some(slot) => slot.stamped_value.read().durability,
|
||||
None => panic!("no value set for {:?}({:?})", Q::default(), key),
|
||||
}
|
||||
}
|
||||
|
||||
fn entries<C>(&self, _db: &DB) -> C
|
||||
fn entries<C>(&self, _db: &Q::DynDb) -> C
|
||||
where
|
||||
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
|
||||
{
|
||||
|
@ -135,12 +139,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> Slot<DB, Q>
|
||||
impl<Q> Slot<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
fn maybe_changed_since(&self, _db: &DB, revision: Revision) -> bool {
|
||||
fn maybe_changed_since(&self, _db: &Q::DynDb, revision: Revision) -> bool {
|
||||
debug!(
|
||||
"maybe_changed_since(slot={:?}, revision={:?})",
|
||||
self, revision,
|
||||
|
@ -154,20 +157,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> QueryStorageMassOps for InputStorage<DB, Q>
|
||||
impl<Q> QueryStorageMassOps for InputStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
fn sweep(&self, _runtime: &Runtime, _strategy: SweepStrategy) {}
|
||||
}
|
||||
|
||||
impl<DB, Q> InputQueryStorageOps<DB, Q> for InputStorage<DB, Q>
|
||||
impl<Q> InputQueryStorageOps<Q> for InputStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
fn set(&self, db: &mut DB, key: &Q::Key, value: Q::Value, durability: Durability) {
|
||||
fn set(&self, db: &mut Q::DynDb, key: &Q::Key, value: Q::Value, durability: Durability) {
|
||||
log::debug!(
|
||||
"{:?}({:?}) = {:?} ({:?})",
|
||||
Q::default(),
|
||||
|
@ -233,41 +234,37 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Check that `Slot<DB, Q, MP>: Send + Sync` as long as
|
||||
/// Check that `Slot<Q, MP>: Send + Sync` as long as
|
||||
/// `DB::DatabaseData: Send + Sync`, which in turn implies that
|
||||
/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
|
||||
#[allow(dead_code)]
|
||||
fn check_send_sync<DB, Q>()
|
||||
fn check_send_sync<Q>()
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
Q::Key: Send + Sync,
|
||||
Q::Value: Send + Sync,
|
||||
{
|
||||
fn is_send_sync<T: Send + Sync>() {}
|
||||
is_send_sync::<Slot<DB, Q>>();
|
||||
is_send_sync::<Slot<Q>>();
|
||||
}
|
||||
|
||||
/// Check that `Slot<DB, Q, MP>: 'static` as long as
|
||||
/// Check that `Slot<Q, MP>: 'static` as long as
|
||||
/// `DB::DatabaseData: 'static`, which in turn implies that
|
||||
/// `Q::Key: 'static`, `Q::Value: 'static`.
|
||||
#[allow(dead_code)]
|
||||
fn check_static<DB, Q>()
|
||||
fn check_static<Q>()
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
DB: 'static,
|
||||
Q: Query,
|
||||
Q::Key: 'static,
|
||||
Q::Value: 'static,
|
||||
{
|
||||
fn is_static<T: 'static>() {}
|
||||
is_static::<Slot<DB, Q>>();
|
||||
is_static::<Slot<Q>>();
|
||||
}
|
||||
|
||||
impl<DB, Q> std::fmt::Debug for Slot<DB, Q>
|
||||
impl<Q> std::fmt::Debug for Slot<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(fmt, "{:?}({:?})", Q::default(), self.key)
|
||||
|
|
118
src/interned.rs
118
src/interned.rs
|
@ -20,24 +20,28 @@ const INTERN_DURABILITY: Durability = Durability::HIGH;
|
|||
|
||||
/// Handles storage where the value is 'derived' by executing a
|
||||
/// function (in contrast to "inputs").
|
||||
pub struct InternedStorage<DB, Q>
|
||||
pub struct InternedStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Value: InternKey,
|
||||
DB: Database,
|
||||
{
|
||||
group_index: u16,
|
||||
tables: RwLock<InternTables<Q::Key>>,
|
||||
}
|
||||
|
||||
/// Storage for the looking up interned things.
|
||||
pub struct LookupInternedStorage<DB, Q, IQ>
|
||||
pub struct LookupInternedStorage<Q, IQ>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Key: InternKey,
|
||||
Q::Value: Eq + Hash,
|
||||
IQ: Query<DB, Key = Q::Value, Value = Q::Key, Group = Q::Group, GroupStorage = Q::GroupStorage>,
|
||||
DB: Database,
|
||||
IQ: Query<
|
||||
Key = Q::Value,
|
||||
Value = Q::Key,
|
||||
Group = Q::Group,
|
||||
DynDb = Q::DynDb,
|
||||
GroupStorage = Q::GroupStorage,
|
||||
>,
|
||||
{
|
||||
phantom: std::marker::PhantomData<(Q::Key, IQ)>,
|
||||
}
|
||||
|
@ -114,10 +118,9 @@ struct Slot<K> {
|
|||
accessed_at: AtomicCell<Option<Revision>>,
|
||||
}
|
||||
|
||||
impl<DB, Q> std::panic::RefUnwindSafe for InternedStorage<DB, Q>
|
||||
impl<Q> std::panic::RefUnwindSafe for InternedStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
DB: Database,
|
||||
Q: Query,
|
||||
Q::Key: std::panic::RefUnwindSafe,
|
||||
Q::Value: InternKey,
|
||||
Q::Value: std::panic::RefUnwindSafe,
|
||||
|
@ -172,19 +175,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> InternedStorage<DB, Q>
|
||||
impl<Q> InternedStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Key: Eq + Hash + Clone,
|
||||
Q::Value: InternKey,
|
||||
DB: Database,
|
||||
{
|
||||
/// If `key` has already been interned, returns its slot. Otherwise, creates a new slot.
|
||||
///
|
||||
/// In either case, the `accessed_at` field of the slot is updated
|
||||
/// to the current revision, ensuring that the slot cannot be GC'd
|
||||
/// while the current queries execute.
|
||||
fn intern_index(&self, db: &DB, key: &Q::Key) -> Arc<Slot<Q::Key>> {
|
||||
fn intern_index(&self, db: &Q::DynDb, key: &Q::Key) -> Arc<Slot<Q::Key>> {
|
||||
if let Some(i) = self.intern_check(db, key) {
|
||||
return i;
|
||||
}
|
||||
|
@ -266,7 +268,7 @@ where
|
|||
slot
|
||||
}
|
||||
|
||||
fn intern_check(&self, db: &DB, key: &Q::Key) -> Option<Arc<Slot<Q::Key>>> {
|
||||
fn intern_check(&self, db: &Q::DynDb, key: &Q::Key) -> Option<Arc<Slot<Q::Key>>> {
|
||||
let revision_now = db.salsa_runtime().current_revision();
|
||||
let slot = self.tables.read().slot_for_key(key, revision_now)?;
|
||||
Some(slot)
|
||||
|
@ -274,17 +276,16 @@ where
|
|||
|
||||
/// Given an index, lookup and clone its value, updating the
|
||||
/// `accessed_at` time if necessary.
|
||||
fn lookup_value(&self, db: &DB, index: InternId) -> Arc<Slot<Q::Key>> {
|
||||
fn lookup_value(&self, db: &Q::DynDb, index: InternId) -> Arc<Slot<Q::Key>> {
|
||||
let revision_now = db.salsa_runtime().current_revision();
|
||||
self.tables.read().slot_for_index(index, revision_now)
|
||||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> QueryStorageOps<DB, Q> for InternedStorage<DB, Q>
|
||||
impl<Q> QueryStorageOps<Q> for InternedStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Value: InternKey,
|
||||
DB: Database,
|
||||
{
|
||||
fn new(group_index: u16) -> Self {
|
||||
InternedStorage {
|
||||
|
@ -295,7 +296,7 @@ where
|
|||
|
||||
fn fmt_index(
|
||||
&self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
index: DatabaseKeyIndex,
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
|
@ -306,7 +307,12 @@ where
|
|||
write!(fmt, "{}({:?})", Q::QUERY_NAME, slot.value)
|
||||
}
|
||||
|
||||
fn maybe_changed_since(&self, db: &DB, input: DatabaseKeyIndex, revision: Revision) -> bool {
|
||||
fn maybe_changed_since(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
input: DatabaseKeyIndex,
|
||||
revision: Revision,
|
||||
) -> bool {
|
||||
assert_eq!(input.group_index, self.group_index);
|
||||
assert_eq!(input.query_index, Q::QUERY_INDEX);
|
||||
let intern_id = InternId::from(input.key_index);
|
||||
|
@ -314,7 +320,11 @@ where
|
|||
slot.maybe_changed_since(db, revision)
|
||||
}
|
||||
|
||||
fn try_fetch(&self, db: &DB, key: &Q::Key) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
fn try_fetch(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
key: &Q::Key,
|
||||
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
let slot = self.intern_index(db, key);
|
||||
let changed_at = slot.interned_at;
|
||||
let index = slot.index;
|
||||
|
@ -326,11 +336,11 @@ where
|
|||
Ok(<Q::Value>::from_intern_id(index))
|
||||
}
|
||||
|
||||
fn durability(&self, _db: &DB, _key: &Q::Key) -> Durability {
|
||||
fn durability(&self, _db: &Q::DynDb, _key: &Q::Key) -> Durability {
|
||||
INTERN_DURABILITY
|
||||
}
|
||||
|
||||
fn entries<C>(&self, _db: &DB) -> C
|
||||
fn entries<C>(&self, _db: &Q::DynDb) -> C
|
||||
where
|
||||
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
|
||||
{
|
||||
|
@ -345,11 +355,10 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q> QueryStorageMassOps for InternedStorage<DB, Q>
|
||||
impl<Q> QueryStorageMassOps for InternedStorage<Q>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Value: InternKey,
|
||||
DB: Database,
|
||||
{
|
||||
fn sweep(&self, runtime: &Runtime, strategy: SweepStrategy) {
|
||||
let mut tables = self.tables.write();
|
||||
|
@ -400,20 +409,19 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, IQ> QueryStorageOps<DB, Q> for LookupInternedStorage<DB, Q, IQ>
|
||||
impl<Q, IQ> QueryStorageOps<Q> for LookupInternedStorage<Q, IQ>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Key: InternKey,
|
||||
Q::Value: Eq + Hash,
|
||||
IQ: Query<
|
||||
DB,
|
||||
Key = Q::Value,
|
||||
Value = Q::Key,
|
||||
Storage = InternedStorage<DB, IQ>,
|
||||
Storage = InternedStorage<IQ>,
|
||||
Group = Q::Group,
|
||||
DynDb = Q::DynDb,
|
||||
GroupStorage = Q::GroupStorage,
|
||||
>,
|
||||
DB: Database + HasQueryGroup<Q::Group>,
|
||||
{
|
||||
fn new(_group_index: u16) -> Self {
|
||||
LookupInternedStorage {
|
||||
|
@ -423,24 +431,33 @@ where
|
|||
|
||||
fn fmt_index(
|
||||
&self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
index: DatabaseKeyIndex,
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result {
|
||||
let group_storage = <DB as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let interned_storage = IQ::query_storage(group_storage);
|
||||
interned_storage.fmt_index(db, index, fmt)
|
||||
}
|
||||
|
||||
fn maybe_changed_since(&self, db: &DB, input: DatabaseKeyIndex, revision: Revision) -> bool {
|
||||
let group_storage = <DB as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
fn maybe_changed_since(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
input: DatabaseKeyIndex,
|
||||
revision: Revision,
|
||||
) -> bool {
|
||||
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let interned_storage = IQ::query_storage(group_storage);
|
||||
interned_storage.maybe_changed_since(db, input, revision)
|
||||
}
|
||||
|
||||
fn try_fetch(&self, db: &DB, key: &Q::Key) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
fn try_fetch(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
key: &Q::Key,
|
||||
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>> {
|
||||
let index = key.as_intern_id();
|
||||
let group_storage = <DB as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let interned_storage = IQ::query_storage(group_storage);
|
||||
let slot = interned_storage.lookup_value(db, index);
|
||||
let value = slot.value.clone();
|
||||
|
@ -453,15 +470,15 @@ where
|
|||
Ok(value)
|
||||
}
|
||||
|
||||
fn durability(&self, _db: &DB, _key: &Q::Key) -> Durability {
|
||||
fn durability(&self, _db: &Q::DynDb, _key: &Q::Key) -> Durability {
|
||||
INTERN_DURABILITY
|
||||
}
|
||||
|
||||
fn entries<C>(&self, db: &DB) -> C
|
||||
fn entries<C>(&self, db: &Q::DynDb) -> C
|
||||
where
|
||||
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
|
||||
{
|
||||
let group_storage = <DB as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let group_storage = <Q::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
|
||||
let interned_storage = IQ::query_storage(group_storage);
|
||||
let tables = interned_storage.tables.read();
|
||||
tables
|
||||
|
@ -474,19 +491,24 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<DB, Q, IQ> QueryStorageMassOps for LookupInternedStorage<DB, Q, IQ>
|
||||
impl<Q, IQ> QueryStorageMassOps for LookupInternedStorage<Q, IQ>
|
||||
where
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
Q::Key: InternKey,
|
||||
Q::Value: Eq + Hash,
|
||||
IQ: Query<DB, Key = Q::Value, Value = Q::Key, Group = Q::Group, GroupStorage = Q::GroupStorage>,
|
||||
DB: Database,
|
||||
IQ: Query<
|
||||
Key = Q::Value,
|
||||
Value = Q::Key,
|
||||
Group = Q::Group,
|
||||
DynDb = Q::DynDb,
|
||||
GroupStorage = Q::GroupStorage,
|
||||
>,
|
||||
{
|
||||
fn sweep(&self, _: &Runtime, _strategy: SweepStrategy) {}
|
||||
}
|
||||
|
||||
impl<K> Slot<K> {
|
||||
fn maybe_changed_since<DB: Database>(&self, db: &DB, revision: Revision) -> bool {
|
||||
fn maybe_changed_since<DB: ?Sized + Database>(&self, db: &DB, revision: Revision) -> bool {
|
||||
let revision_now = db.salsa_runtime().current_revision();
|
||||
if !self.try_update_accessed_at(revision_now) {
|
||||
// if we failed to update accessed-at, then this slot was garbage collected
|
||||
|
@ -549,7 +571,7 @@ impl<K> Slot<K> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check that `Slot<DB, Q, MP>: Send + Sync` as long as
|
||||
/// Check that `Slot<Q, MP>: Send + Sync` as long as
|
||||
/// `DB::DatabaseData: Send + Sync`, which in turn implies that
|
||||
/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
|
||||
#[allow(dead_code)]
|
||||
|
@ -561,7 +583,7 @@ where
|
|||
is_send_sync::<Slot<K>>();
|
||||
}
|
||||
|
||||
/// Check that `Slot<DB, Q, MP>: 'static` as long as
|
||||
/// Check that `Slot<Q, MP>: 'static` as long as
|
||||
/// `DB::DatabaseData: 'static`, which in turn implies that
|
||||
/// `Q::Key: 'static`, `Q::Value: 'static`.
|
||||
#[allow(dead_code)]
|
||||
|
|
48
src/lib.rs
48
src/lib.rs
|
@ -45,7 +45,7 @@ pub use crate::storage::Storage;
|
|||
/// The base trait which your "query context" must implement. Gives
|
||||
/// access to the salsa runtime, which you must embed into your query
|
||||
/// context (along with whatever other state you may require).
|
||||
pub trait Database: plumbing::DatabaseOps {
|
||||
pub trait Database: 'static + plumbing::DatabaseOps {
|
||||
/// Iterates through all query storage and removes any values that
|
||||
/// have not been used since the last revision was created. The
|
||||
/// intended use-cycle is that you first execute all of your
|
||||
|
@ -330,7 +330,7 @@ pub trait ParallelDatabase: Database + Send {
|
|||
///
|
||||
/// [fm]: trait.ParallelDatabase.html#method.snapshot
|
||||
#[derive(Debug)]
|
||||
pub struct Snapshot<DB>
|
||||
pub struct Snapshot<DB: ?Sized>
|
||||
where
|
||||
DB: ParallelDatabase,
|
||||
{
|
||||
|
@ -420,7 +420,7 @@ where
|
|||
|
||||
/// Trait implements by all of the "special types" associated with
|
||||
/// each of your queries.
|
||||
pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
||||
pub trait Query: Debug + Default + Sized + 'static {
|
||||
/// Type that you you give as a parameter -- for queries with zero
|
||||
/// or more than one input, this will be a tuple.
|
||||
type Key: Clone + Debug + Hash + Eq;
|
||||
|
@ -429,14 +429,17 @@ pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
|||
type Value: Clone + Debug;
|
||||
|
||||
/// Internal struct storing the values for the query.
|
||||
type Storage: plumbing::QueryStorageOps<DB, Self>;
|
||||
type Storage: plumbing::QueryStorageOps<Self>;
|
||||
|
||||
/// Associate query group struct.
|
||||
type Group: plumbing::QueryGroup<DB, GroupStorage = Self::GroupStorage>;
|
||||
type Group: plumbing::QueryGroup<DynDb = Self::DynDb, GroupStorage = Self::GroupStorage>;
|
||||
|
||||
/// Generated struct that contains storage for all queries in a group.
|
||||
type GroupStorage;
|
||||
|
||||
/// Dyn version of the associated trait for this query group.
|
||||
type DynDb: ?Sized + Database + HasQueryGroup<Self::Group>;
|
||||
|
||||
/// A unique index identifying this query within the group.
|
||||
const QUERY_INDEX: u16;
|
||||
|
||||
|
@ -451,22 +454,20 @@ pub trait Query<DB: Database>: Debug + Default + Sized + 'static {
|
|||
/// Gives access to various less common operations on queries.
|
||||
///
|
||||
/// [the `query` method]: trait.Database.html#method.query
|
||||
pub struct QueryTable<'me, DB, Q>
|
||||
pub struct QueryTable<'me, Q>
|
||||
where
|
||||
DB: plumbing::GetQueryTable<Q>,
|
||||
Q: Query<DB> + 'me,
|
||||
Q: Query + 'me,
|
||||
{
|
||||
db: &'me DB,
|
||||
db: &'me Q::DynDb,
|
||||
storage: &'me Q::Storage,
|
||||
}
|
||||
|
||||
impl<'me, DB, Q> QueryTable<'me, DB, Q>
|
||||
impl<'me, Q> QueryTable<'me, Q>
|
||||
where
|
||||
DB: plumbing::GetQueryTable<Q>,
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
{
|
||||
/// Constructs a new `QueryTable`.
|
||||
pub fn new(db: &'me DB, storage: &'me Q::Storage) -> Self {
|
||||
pub fn new(db: &'me Q::DynDb, storage: &'me Q::Storage) -> Self {
|
||||
Self { db, storage }
|
||||
}
|
||||
|
||||
|
@ -497,22 +498,20 @@ where
|
|||
/// set the value of an input query.
|
||||
///
|
||||
/// [the `query_mut` method]: trait.Database.html#method.query_mut
|
||||
pub struct QueryTableMut<'me, DB, Q>
|
||||
pub struct QueryTableMut<'me, Q>
|
||||
where
|
||||
DB: plumbing::GetQueryTable<Q>,
|
||||
Q: Query<DB> + 'me,
|
||||
Q: Query + 'me,
|
||||
{
|
||||
db: &'me mut DB,
|
||||
db: &'me mut Q::DynDb,
|
||||
storage: Arc<Q::Storage>,
|
||||
}
|
||||
|
||||
impl<'me, DB, Q> QueryTableMut<'me, DB, Q>
|
||||
impl<'me, Q> QueryTableMut<'me, Q>
|
||||
where
|
||||
DB: plumbing::GetQueryTable<Q>,
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
{
|
||||
/// Constructs a new `QueryTableMut`.
|
||||
pub fn new(db: &'me mut DB, storage: Arc<Q::Storage>) -> Self {
|
||||
pub fn new(db: &'me mut Q::DynDb, storage: Arc<Q::Storage>) -> Self {
|
||||
Self { db, storage }
|
||||
}
|
||||
|
||||
|
@ -525,7 +524,7 @@ where
|
|||
/// [the `query_mut` method]: trait.Database.html#method.query_mut
|
||||
pub fn set(&mut self, key: Q::Key, value: Q::Value)
|
||||
where
|
||||
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
||||
Q::Storage: plumbing::InputQueryStorageOps<Q>,
|
||||
{
|
||||
self.set_with_durability(key, value, Durability::LOW);
|
||||
}
|
||||
|
@ -540,7 +539,7 @@ where
|
|||
/// [the `query_mut` method]: trait.Database.html#method.query_mut
|
||||
pub fn set_with_durability(&mut self, key: Q::Key, value: Q::Value, durability: Durability)
|
||||
where
|
||||
Q::Storage: plumbing::InputQueryStorageOps<DB, Q>,
|
||||
Q::Storage: plumbing::InputQueryStorageOps<Q>,
|
||||
{
|
||||
self.storage.set(self.db, &key, value, durability);
|
||||
}
|
||||
|
@ -568,7 +567,7 @@ where
|
|||
/// pattern](https://salsa-rs.github.io/salsa/common_patterns/on_demand_inputs.html).
|
||||
pub fn invalidate(&mut self, key: &Q::Key)
|
||||
where
|
||||
Q::Storage: plumbing::DerivedQueryStorageOps<DB, Q>,
|
||||
Q::Storage: plumbing::DerivedQueryStorageOps<Q>,
|
||||
{
|
||||
self.storage.invalidate(self.db, key)
|
||||
}
|
||||
|
@ -600,5 +599,6 @@ where
|
|||
#[allow(unused_imports)]
|
||||
#[macro_use]
|
||||
extern crate salsa_macros;
|
||||
use plumbing::HasQueryGroup;
|
||||
#[doc(hidden)]
|
||||
pub use salsa_macros::*;
|
||||
|
|
115
src/plumbing.rs
115
src/plumbing.rs
|
@ -36,7 +36,7 @@ pub trait DatabaseStorageTypes: Database {
|
|||
}
|
||||
|
||||
/// Internal operations that the runtime uses to operate on the database.
|
||||
pub trait DatabaseOps: Sized {
|
||||
pub trait DatabaseOps {
|
||||
/// Gives access to the underlying salsa runtime.
|
||||
fn ops_salsa_runtime(&self) -> &Runtime;
|
||||
|
||||
|
@ -65,88 +65,83 @@ pub trait QueryStorageMassOps {
|
|||
fn sweep(&self, runtime: &Runtime, strategy: SweepStrategy);
|
||||
}
|
||||
|
||||
pub trait DatabaseKey<DB>: Clone + Debug + Eq + Hash {}
|
||||
pub trait DatabaseKey: Clone + Debug + Eq + Hash {}
|
||||
|
||||
pub trait QueryFunction<DB: Database>: Query<DB> {
|
||||
fn execute(db: &DB, key: Self::Key) -> Self::Value;
|
||||
fn recover(db: &DB, cycle: &[DatabaseKeyIndex], key: &Self::Key) -> Option<Self::Value> {
|
||||
pub trait QueryFunction: Query {
|
||||
fn execute(db: &Self::DynDb, key: Self::Key) -> Self::Value;
|
||||
|
||||
fn recover(
|
||||
db: &Self::DynDb,
|
||||
cycle: &[DatabaseKeyIndex],
|
||||
key: &Self::Key,
|
||||
) -> Option<Self::Value> {
|
||||
let _ = (db, cycle, key);
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// The `GetQueryTable` trait makes the connection the *database type*
|
||||
/// `DB` and some specific *query type* `Q` that it supports. Note
|
||||
/// that the `Database` trait itself is not specific to any query, and
|
||||
/// the impls of the query trait are not specific to any *database*
|
||||
/// (in particular, query groups are defined without knowing the final
|
||||
/// database type). This trait then serves to put the query in the
|
||||
/// context of the full database. It gives access to the storage for
|
||||
/// the query and also to creating the query descriptor. For any given
|
||||
/// database, impls of this trait are created by the
|
||||
/// `database_storage` macro.
|
||||
pub trait GetQueryTable<Q: Query<Self>>: Database {
|
||||
/// Create a query table, which has access to the storage for the query
|
||||
/// and offers methods like `get`.
|
||||
fn get_query_table(db: &Self) -> QueryTable<'_, Self, Q>;
|
||||
|
||||
/// Create a mutable query table, which has access to the storage
|
||||
/// for the query and offers methods like `set`.
|
||||
fn get_query_table_mut(db: &mut Self) -> QueryTableMut<'_, Self, Q>;
|
||||
}
|
||||
|
||||
impl<DB, Q> GetQueryTable<Q> for DB
|
||||
/// Create a query table, which has access to the storage for the query
|
||||
/// and offers methods like `get`.
|
||||
pub fn get_query_table<Q>(db: &Q::DynDb) -> QueryTable<'_, Q>
|
||||
where
|
||||
DB: Database,
|
||||
Q: Query<DB>,
|
||||
DB: HasQueryGroup<Q::Group>,
|
||||
Q: Query,
|
||||
{
|
||||
fn get_query_table(db: &DB) -> QueryTable<'_, DB, Q> {
|
||||
let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
|
||||
let query_storage: &Q::Storage = Q::query_storage(group_storage);
|
||||
QueryTable::new(db, query_storage)
|
||||
}
|
||||
|
||||
fn get_query_table_mut(db: &mut DB) -> QueryTableMut<'_, DB, Q> {
|
||||
let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
|
||||
let query_storage = Q::query_storage(group_storage).clone();
|
||||
QueryTableMut::new(db, query_storage)
|
||||
}
|
||||
let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
|
||||
let query_storage: &Q::Storage = Q::query_storage(group_storage);
|
||||
QueryTable::new(db, query_storage)
|
||||
}
|
||||
|
||||
pub trait QueryGroup<DB: Database> {
|
||||
/// Create a mutable query table, which has access to the storage
|
||||
/// for the query and offers methods like `set`.
|
||||
pub fn get_query_table_mut<Q>(db: &mut Q::DynDb) -> QueryTableMut<'_, Q>
|
||||
where
|
||||
Q: Query,
|
||||
{
|
||||
let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
|
||||
let query_storage = Q::query_storage(group_storage).clone();
|
||||
QueryTableMut::new(db, query_storage)
|
||||
}
|
||||
|
||||
pub trait QueryGroup: Sized {
|
||||
type GroupStorage;
|
||||
|
||||
/// Dyn version of the associated database trait.
|
||||
type DynDb: ?Sized + Database + HasQueryGroup<Self>;
|
||||
}
|
||||
|
||||
/// Trait implemented by a database for each group that it supports.
|
||||
/// `S` and `K` are the types for *group storage* and *group key*, respectively.
|
||||
pub trait HasQueryGroup<G>: Database
|
||||
where
|
||||
G: QueryGroup<Self>,
|
||||
G: QueryGroup,
|
||||
{
|
||||
/// Access the group storage struct from the database.
|
||||
fn group_storage(db: &Self) -> &G::GroupStorage;
|
||||
fn group_storage(&self) -> &G::GroupStorage;
|
||||
}
|
||||
|
||||
pub trait QueryStorageOps<DB, Q>
|
||||
pub trait QueryStorageOps<Q>
|
||||
where
|
||||
Self: QueryStorageMassOps,
|
||||
DB: Database,
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
{
|
||||
fn new(group_index: u16) -> Self;
|
||||
|
||||
/// Format a database key index in a suitable way.
|
||||
fn fmt_index(
|
||||
&self,
|
||||
db: &DB,
|
||||
db: &Q::DynDb,
|
||||
index: DatabaseKeyIndex,
|
||||
fmt: &mut std::fmt::Formatter<'_>,
|
||||
) -> std::fmt::Result;
|
||||
|
||||
/// True if the value of `input`, which must be from this query, may have
|
||||
/// changed since the given revision.
|
||||
fn maybe_changed_since(&self, db: &DB, input: DatabaseKeyIndex, revision: Revision) -> bool;
|
||||
fn maybe_changed_since(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
input: DatabaseKeyIndex,
|
||||
revision: Revision,
|
||||
) -> bool;
|
||||
|
||||
/// Execute the query, returning the result (often, the result
|
||||
/// will be memoized). This is the "main method" for
|
||||
|
@ -155,13 +150,17 @@ where
|
|||
/// Returns `Err` in the event of a cycle, meaning that computing
|
||||
/// the value for this `key` is recursively attempting to fetch
|
||||
/// itself.
|
||||
fn try_fetch(&self, db: &DB, key: &Q::Key) -> Result<Q::Value, CycleError<DatabaseKeyIndex>>;
|
||||
fn try_fetch(
|
||||
&self,
|
||||
db: &Q::DynDb,
|
||||
key: &Q::Key,
|
||||
) -> Result<Q::Value, CycleError<DatabaseKeyIndex>>;
|
||||
|
||||
/// Returns the durability associated with a given key.
|
||||
fn durability(&self, db: &DB, key: &Q::Key) -> Durability;
|
||||
fn durability(&self, db: &Q::DynDb, key: &Q::Key) -> Durability;
|
||||
|
||||
/// Get the (current) set of the entries in the query storage
|
||||
fn entries<C>(&self, db: &DB) -> C
|
||||
fn entries<C>(&self, db: &Q::DynDb) -> C
|
||||
where
|
||||
C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>;
|
||||
}
|
||||
|
@ -169,12 +168,11 @@ where
|
|||
/// An optional trait that is implemented for "user mutable" storage:
|
||||
/// that is, storage whose value is not derived from other storage but
|
||||
/// is set independently.
|
||||
pub trait InputQueryStorageOps<DB, Q>
|
||||
pub trait InputQueryStorageOps<Q>
|
||||
where
|
||||
DB: Database,
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
{
|
||||
fn set(&self, db: &mut DB, key: &Q::Key, new_value: Q::Value, durability: Durability);
|
||||
fn set(&self, db: &mut Q::DynDb, key: &Q::Key, new_value: Q::Value, durability: Durability);
|
||||
}
|
||||
|
||||
/// An optional trait that is implemented for "user mutable" storage:
|
||||
|
@ -184,10 +182,9 @@ pub trait LruQueryStorageOps {
|
|||
fn set_lru_capacity(&self, new_capacity: usize);
|
||||
}
|
||||
|
||||
pub trait DerivedQueryStorageOps<DB, Q>
|
||||
pub trait DerivedQueryStorageOps<Q>
|
||||
where
|
||||
DB: Database,
|
||||
Q: Query<DB>,
|
||||
Q: Query,
|
||||
{
|
||||
fn invalidate(&self, db: &mut DB, key: &Q::Key);
|
||||
fn invalidate(&self, db: &mut Q::DynDb, key: &Q::Key);
|
||||
}
|
||||
|
|
|
@ -39,50 +39,50 @@ trait Database: salsa::Database {
|
|||
fn cycle_c(&self) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
fn recover_a(_db: &impl Database, cycle: &[String]) -> Result<(), Error> {
|
||||
fn recover_a(_db: &dyn Database, cycle: &[String]) -> Result<(), Error> {
|
||||
Err(Error {
|
||||
cycle: cycle.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
fn recover_b(_db: &impl Database, cycle: &[String]) -> Result<(), Error> {
|
||||
fn recover_b(_db: &dyn Database, cycle: &[String]) -> Result<(), Error> {
|
||||
Err(Error {
|
||||
cycle: cycle.to_owned(),
|
||||
})
|
||||
}
|
||||
|
||||
fn memoized_a(db: &impl Database) -> () {
|
||||
fn memoized_a(db: &dyn Database) -> () {
|
||||
db.memoized_b()
|
||||
}
|
||||
|
||||
fn memoized_b(db: &impl Database) -> () {
|
||||
fn memoized_b(db: &dyn Database) -> () {
|
||||
db.memoized_a()
|
||||
}
|
||||
|
||||
fn volatile_a(db: &impl Database) -> () {
|
||||
fn volatile_a(db: &dyn Database) -> () {
|
||||
db.salsa_runtime().report_untracked_read();
|
||||
db.volatile_b()
|
||||
}
|
||||
|
||||
fn volatile_b(db: &impl Database) -> () {
|
||||
fn volatile_b(db: &dyn Database) -> () {
|
||||
db.salsa_runtime().report_untracked_read();
|
||||
db.volatile_a()
|
||||
}
|
||||
|
||||
fn cycle_leaf(_db: &impl Database) -> () {}
|
||||
fn cycle_leaf(_db: &dyn Database) -> () {}
|
||||
|
||||
fn cycle_a(db: &impl Database) -> Result<(), Error> {
|
||||
fn cycle_a(db: &dyn Database) -> Result<(), Error> {
|
||||
let _ = db.cycle_b();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cycle_b(db: &impl Database) -> Result<(), Error> {
|
||||
fn cycle_b(db: &dyn Database) -> Result<(), Error> {
|
||||
db.cycle_leaf();
|
||||
let _ = db.cycle_a();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cycle_c(db: &impl Database) -> Result<(), Error> {
|
||||
fn cycle_c(db: &dyn Database) -> Result<(), Error> {
|
||||
db.cycle_b()
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ pub(crate) trait GcDatabase: salsa::Database + HasLog {
|
|||
fn compute_all(&self) -> Vec<usize>;
|
||||
}
|
||||
|
||||
fn fibonacci(db: &impl GcDatabase, key: usize) -> usize {
|
||||
fn fibonacci(db: &dyn GcDatabase, key: usize) -> usize {
|
||||
db.log().add(format!("fibonacci({:?})", key));
|
||||
if key == 0 {
|
||||
0
|
||||
|
@ -31,7 +31,7 @@ fn fibonacci(db: &impl GcDatabase, key: usize) -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
fn triangular(db: &impl GcDatabase, key: usize) -> usize {
|
||||
fn triangular(db: &dyn GcDatabase, key: usize) -> usize {
|
||||
db.log().add(format!("triangular({:?})", key));
|
||||
if key == 0 {
|
||||
0
|
||||
|
@ -40,7 +40,7 @@ fn triangular(db: &impl GcDatabase, key: usize) -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute(db: &impl GcDatabase, key: usize) -> usize {
|
||||
fn compute(db: &dyn GcDatabase, key: usize) -> usize {
|
||||
db.log().add(format!("compute({:?})", key));
|
||||
if db.use_triangular(key) {
|
||||
db.triangular(key)
|
||||
|
@ -49,7 +49,7 @@ fn compute(db: &impl GcDatabase, key: usize) -> usize {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_all(db: &impl GcDatabase) -> Vec<usize> {
|
||||
fn compute_all(db: &dyn GcDatabase) -> Vec<usize> {
|
||||
db.log().add("compute_all()");
|
||||
(db.min()..db.max()).map(|v| db.compute(v)).collect()
|
||||
}
|
||||
|
|
|
@ -20,11 +20,11 @@ pub(crate) trait InternDatabase {
|
|||
fn repeat_intern2(&self, x: &'static str) -> InternId;
|
||||
}
|
||||
|
||||
fn repeat_intern1(db: &impl InternDatabase, x: &'static str) -> InternId {
|
||||
fn repeat_intern1(db: &dyn InternDatabase, x: &'static str) -> InternId {
|
||||
db.intern_str(x)
|
||||
}
|
||||
|
||||
fn repeat_intern2(db: &impl InternDatabase, x: &'static str) -> InternId {
|
||||
fn repeat_intern2(db: &dyn InternDatabase, x: &'static str) -> InternId {
|
||||
db.intern_str(x)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,16 +19,16 @@ pub(crate) trait VolatileDatabase: Database {
|
|||
fn repeat2(&self) -> usize;
|
||||
}
|
||||
|
||||
fn volatile(db: &impl VolatileDatabase) -> usize {
|
||||
fn volatile(db: &dyn VolatileDatabase) -> usize {
|
||||
db.salsa_runtime().report_untracked_read();
|
||||
db.atomic_cell().load(Ordering::SeqCst)
|
||||
}
|
||||
|
||||
fn repeat1(db: &impl VolatileDatabase) -> usize {
|
||||
fn repeat1(db: &dyn VolatileDatabase) -> usize {
|
||||
db.volatile()
|
||||
}
|
||||
|
||||
fn repeat2(db: &impl VolatileDatabase) -> usize {
|
||||
fn repeat2(db: &dyn VolatileDatabase) -> usize {
|
||||
db.volatile()
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,12 @@ pub(crate) trait ConstantsDatabase: TestContext {
|
|||
fn add3(&self, key1: char, key2: char, key3: char) -> usize;
|
||||
}
|
||||
|
||||
fn add(db: &impl ConstantsDatabase, key1: char, key2: char) -> usize {
|
||||
fn add(db: &dyn ConstantsDatabase, key1: char, key2: char) -> usize {
|
||||
db.log().add(format!("add({}, {})", key1, key2));
|
||||
db.input(key1) + db.input(key2)
|
||||
}
|
||||
|
||||
fn add3(db: &impl ConstantsDatabase, key1: char, key2: char, key3: char) -> usize {
|
||||
fn add3(db: &dyn ConstantsDatabase, key1: char, key2: char, key3: char) -> usize {
|
||||
db.log().add(format!("add3({}, {}, {})", key1, key2, key3));
|
||||
db.add(key1, key2) + db.input(key3)
|
||||
}
|
||||
|
|
|
@ -12,17 +12,17 @@ pub(crate) trait MemoizedDepInputsContext: TestContext {
|
|||
fn dep_input2(&self) -> usize;
|
||||
}
|
||||
|
||||
fn dep_memoized2(db: &impl MemoizedDepInputsContext) -> usize {
|
||||
fn dep_memoized2(db: &dyn MemoizedDepInputsContext) -> usize {
|
||||
db.log().add("Memoized2 invoked");
|
||||
db.dep_memoized1()
|
||||
}
|
||||
|
||||
fn dep_memoized1(db: &impl MemoizedDepInputsContext) -> usize {
|
||||
fn dep_memoized1(db: &dyn MemoizedDepInputsContext) -> usize {
|
||||
db.log().add("Memoized1 invoked");
|
||||
db.dep_derived1() * 2
|
||||
}
|
||||
|
||||
fn dep_derived1(db: &impl MemoizedDepInputsContext) -> usize {
|
||||
fn dep_derived1(db: &dyn MemoizedDepInputsContext) -> usize {
|
||||
db.log().add("Derived1 invoked");
|
||||
db.dep_input1() / 2
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ pub(crate) trait MemoizedInputsContext: TestContext {
|
|||
fn input2(&self) -> usize;
|
||||
}
|
||||
|
||||
fn max(db: &impl MemoizedInputsContext) -> usize {
|
||||
fn max(db: &dyn MemoizedInputsContext) -> usize {
|
||||
db.log().add("Max invoked");
|
||||
std::cmp::max(db.input1(), db.input2())
|
||||
}
|
||||
|
|
|
@ -10,18 +10,18 @@ pub(crate) trait MemoizedVolatileContext: TestContext {
|
|||
fn volatile(&self) -> usize;
|
||||
}
|
||||
|
||||
fn memoized2(db: &impl MemoizedVolatileContext) -> usize {
|
||||
fn memoized2(db: &dyn MemoizedVolatileContext) -> usize {
|
||||
db.log().add("Memoized2 invoked");
|
||||
db.memoized1()
|
||||
}
|
||||
|
||||
fn memoized1(db: &impl MemoizedVolatileContext) -> usize {
|
||||
fn memoized1(db: &dyn MemoizedVolatileContext) -> usize {
|
||||
db.log().add("Memoized1 invoked");
|
||||
let v = db.volatile();
|
||||
v / 2
|
||||
}
|
||||
|
||||
fn volatile(db: &impl MemoizedVolatileContext) -> usize {
|
||||
fn volatile(db: &dyn MemoizedVolatileContext) -> usize {
|
||||
db.log().add("Volatile invoked");
|
||||
db.salsa_runtime().report_untracked_read();
|
||||
db.clock().increment()
|
||||
|
|
|
@ -28,11 +28,11 @@ trait QueryGroup: salsa::Database {
|
|||
fn get_volatile(&self, x: u32) -> usize;
|
||||
}
|
||||
|
||||
fn get(_db: &impl QueryGroup, x: u32) -> Arc<HotPotato> {
|
||||
fn get(_db: &dyn QueryGroup, x: u32) -> Arc<HotPotato> {
|
||||
Arc::new(HotPotato::new(x))
|
||||
}
|
||||
|
||||
fn get_volatile(db: &impl QueryGroup, _x: u32) -> usize {
|
||||
fn get_volatile(db: &dyn QueryGroup, _x: u32) -> usize {
|
||||
static COUNTER: AtomicUsize = AtomicUsize::new(0);
|
||||
db.salsa_runtime().report_untracked_read();
|
||||
COUNTER.fetch_add(1, Ordering::SeqCst)
|
||||
|
|
|
@ -5,7 +5,7 @@ trait MyDatabase: salsa::Database {
|
|||
}
|
||||
|
||||
mod another_module {
|
||||
pub(crate) fn another_name(_: &impl crate::MyDatabase, (): ()) -> () {}
|
||||
pub(crate) fn another_name(_: &dyn crate::MyDatabase, (): ()) -> () {}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -8,11 +8,11 @@ trait NoSendSyncDatabase: salsa::Database {
|
|||
fn no_send_sync_key(&self, key: Rc<bool>) -> bool;
|
||||
}
|
||||
|
||||
fn no_send_sync_value(_db: &impl NoSendSyncDatabase, key: bool) -> Rc<bool> {
|
||||
fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Rc<bool> {
|
||||
Rc::new(key)
|
||||
}
|
||||
|
||||
fn no_send_sync_key(_db: &impl NoSendSyncDatabase, key: Rc<bool>) -> bool {
|
||||
fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Rc<bool>) -> bool {
|
||||
*key
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ trait QueryGroup: salsa::Database + AsRef<HashMap<u32, u32>> {
|
|||
fn c(&self, x: u32) -> u32;
|
||||
}
|
||||
|
||||
fn a(db: &impl QueryGroup, x: u32) -> u32 {
|
||||
fn a(db: &dyn QueryGroup, x: u32) -> u32 {
|
||||
let durability = if x % 2 == 0 {
|
||||
Durability::LOW
|
||||
} else {
|
||||
|
@ -26,11 +26,11 @@ fn a(db: &impl QueryGroup, x: u32) -> u32 {
|
|||
external_state[&x]
|
||||
}
|
||||
|
||||
fn b(db: &impl QueryGroup, x: u32) -> u32 {
|
||||
fn b(db: &dyn QueryGroup, x: u32) -> u32 {
|
||||
db.a(x)
|
||||
}
|
||||
|
||||
fn c(db: &impl QueryGroup, x: u32) -> u32 {
|
||||
fn c(db: &dyn QueryGroup, x: u32) -> u32 {
|
||||
db.b(x)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@ trait PanicSafelyDatabase: salsa::Database {
|
|||
fn outer(&self) -> ();
|
||||
}
|
||||
|
||||
fn panic_safely(db: &impl PanicSafelyDatabase) -> () {
|
||||
fn panic_safely(db: &dyn PanicSafelyDatabase) -> () {
|
||||
assert_eq!(db.one(), 1);
|
||||
}
|
||||
|
||||
static OUTER_CALLS: AtomicU32 = AtomicU32::new(0);
|
||||
|
||||
fn outer(db: &impl PanicSafelyDatabase) -> () {
|
||||
fn outer(db: &dyn PanicSafelyDatabase) -> () {
|
||||
OUTER_CALLS.fetch_add(1, SeqCst);
|
||||
db.panic_safely();
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
use crate::setup::{ParDatabase, ParDatabaseImpl};
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn snapshot_from_query() {
|
||||
let db = ParDatabaseImpl::default();
|
||||
db.snapshot_me();
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
mod setup;
|
||||
|
||||
mod cancellation;
|
||||
mod fork_from_query;
|
||||
mod frozen;
|
||||
mod independent;
|
||||
mod race;
|
||||
|
|
|
@ -6,7 +6,7 @@ use std::cell::Cell;
|
|||
use std::sync::Arc;
|
||||
|
||||
#[salsa::query_group(Par)]
|
||||
pub(crate) trait ParDatabase: Knobs + salsa::ParallelDatabase {
|
||||
pub(crate) trait ParDatabase: Knobs {
|
||||
#[salsa::input]
|
||||
fn input(&self, key: char) -> usize;
|
||||
|
||||
|
@ -23,8 +23,6 @@ pub(crate) trait ParDatabase: Knobs + salsa::ParallelDatabase {
|
|||
|
||||
/// Invokes `sum2_drop_sum`
|
||||
fn sum3_drop_sum(&self, key: &'static str) -> usize;
|
||||
|
||||
fn snapshot_me(&self) -> ();
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
|
@ -111,7 +109,7 @@ pub(crate) struct KnobsStruct {
|
|||
pub(crate) sum3_drop_sum_should_panic: Cell<bool>,
|
||||
}
|
||||
|
||||
fn sum(db: &impl ParDatabase, key: &'static str) -> usize {
|
||||
fn sum(db: &dyn ParDatabase, key: &'static str) -> usize {
|
||||
let mut sum = 0;
|
||||
|
||||
db.signal(db.knobs().sum_signal_on_entry.get());
|
||||
|
@ -159,31 +157,26 @@ fn sum(db: &impl ParDatabase, key: &'static str) -> usize {
|
|||
sum
|
||||
}
|
||||
|
||||
fn sum2(db: &impl ParDatabase, key: &'static str) -> usize {
|
||||
fn sum2(db: &dyn ParDatabase, key: &'static str) -> usize {
|
||||
db.sum(key)
|
||||
}
|
||||
|
||||
fn sum2_drop_sum(db: &impl ParDatabase, key: &'static str) -> usize {
|
||||
fn sum2_drop_sum(db: &dyn ParDatabase, key: &'static str) -> usize {
|
||||
let _ = db.sum(key);
|
||||
22
|
||||
}
|
||||
|
||||
fn sum3(db: &impl ParDatabase, key: &'static str) -> usize {
|
||||
fn sum3(db: &dyn ParDatabase, key: &'static str) -> usize {
|
||||
db.sum2(key)
|
||||
}
|
||||
|
||||
fn sum3_drop_sum(db: &impl ParDatabase, key: &'static str) -> usize {
|
||||
fn sum3_drop_sum(db: &dyn ParDatabase, key: &'static str) -> usize {
|
||||
if db.knobs().sum3_drop_sum_should_panic.get() {
|
||||
panic!("sum3_drop_sum executed")
|
||||
}
|
||||
db.sum2_drop_sum(key)
|
||||
}
|
||||
|
||||
fn snapshot_me(db: &impl ParDatabase) {
|
||||
// this should panic
|
||||
db.snapshot();
|
||||
}
|
||||
|
||||
#[salsa::database(Par)]
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ParDatabaseImpl {
|
||||
|
|
|
@ -24,14 +24,14 @@ trait StressDatabase: salsa::Database {
|
|||
fn c(&self, key: usize) -> Cancelable<usize>;
|
||||
}
|
||||
|
||||
fn b(db: &impl StressDatabase, key: usize) -> Cancelable<usize> {
|
||||
fn b(db: &dyn StressDatabase, key: usize) -> Cancelable<usize> {
|
||||
if db.salsa_runtime().is_current_revision_canceled() {
|
||||
return Err(Canceled);
|
||||
}
|
||||
Ok(db.a(key))
|
||||
}
|
||||
|
||||
fn c(db: &impl StressDatabase, key: usize) -> Cancelable<usize> {
|
||||
fn c(db: &dyn StressDatabase, key: usize) -> Cancelable<usize> {
|
||||
db.b(key)
|
||||
}
|
||||
|
||||
|
|
|
@ -10,13 +10,13 @@ pub(crate) trait Database: Counter {
|
|||
|
||||
/// Because this query is memoized, we only increment the counter
|
||||
/// the first time it is invoked.
|
||||
fn memoized(db: &impl Database) -> usize {
|
||||
fn memoized(db: &dyn Database) -> usize {
|
||||
db.volatile()
|
||||
}
|
||||
|
||||
/// Because this query is volatile, each time it is invoked,
|
||||
/// we will increment the counter.
|
||||
fn volatile(db: &impl Database) -> usize {
|
||||
fn volatile(db: &dyn Database) -> usize {
|
||||
db.salsa_runtime().report_untracked_read();
|
||||
db.increment()
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ trait QueryGroup {
|
|||
fn get(&self, x: u32) -> u32;
|
||||
}
|
||||
|
||||
fn wrap(db: &impl QueryGroup, x: u32) -> u32 {
|
||||
fn wrap(db: &dyn QueryGroup, x: u32) -> u32 {
|
||||
db.input(x)
|
||||
}
|
||||
|
||||
fn get(db: &impl QueryGroup, x: u32) -> u32 {
|
||||
fn get(db: &dyn QueryGroup, x: u32) -> u32 {
|
||||
db.wrap(x)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,19 +12,19 @@ trait HelloWorldDatabase: salsa::Database {
|
|||
fn trailing(&self, a: u32, b: u32) -> u32;
|
||||
}
|
||||
|
||||
fn none(_db: &impl HelloWorldDatabase) -> u32 {
|
||||
fn none(_db: &dyn HelloWorldDatabase) -> u32 {
|
||||
22
|
||||
}
|
||||
|
||||
fn one(_db: &impl HelloWorldDatabase, k: u32) -> u32 {
|
||||
fn one(_db: &dyn HelloWorldDatabase, k: u32) -> u32 {
|
||||
k * 2
|
||||
}
|
||||
|
||||
fn two(_db: &impl HelloWorldDatabase, a: u32, b: u32) -> u32 {
|
||||
fn two(_db: &dyn HelloWorldDatabase, a: u32, b: u32) -> u32 {
|
||||
a * b
|
||||
}
|
||||
|
||||
fn trailing(_db: &impl HelloWorldDatabase, a: u32, b: u32) -> u32 {
|
||||
fn trailing(_db: &dyn HelloWorldDatabase, a: u32, b: u32) -> u32 {
|
||||
a - b
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue