mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-02-02 09:46:06 +00:00
remove the Zalsa trait and make it a struct
This commit is contained in:
parent
34e109d390
commit
703e12def8
4 changed files with 95 additions and 141 deletions
|
@ -5,7 +5,7 @@ use parking_lot::{Condvar, Mutex};
|
|||
use crate::{
|
||||
self as salsa,
|
||||
local_state::{self, LocalState},
|
||||
storage::{Zalsa, ZalsaImpl},
|
||||
storage::Zalsa,
|
||||
Durability, Event, EventKind, Revision,
|
||||
};
|
||||
|
||||
|
@ -61,14 +61,14 @@ pub unsafe trait Database: Send + AsDynDatabase + Any {
|
|||
|
||||
/// Plumbing method: Access the internal salsa methods.
|
||||
#[doc(hidden)]
|
||||
fn zalsa(&self) -> &dyn Zalsa;
|
||||
fn zalsa(&self) -> &Zalsa;
|
||||
|
||||
/// Plumbing method: Access the internal salsa methods for mutating the database.
|
||||
///
|
||||
/// **WARNING:** Triggers a new revision, canceling other database handles.
|
||||
/// This can lead to deadlock!
|
||||
#[doc(hidden)]
|
||||
fn zalsa_mut(&mut self) -> &mut dyn Zalsa;
|
||||
fn zalsa_mut(&mut self) -> &mut Zalsa;
|
||||
|
||||
/// Access the thread-local state associated with this database
|
||||
#[doc(hidden)]
|
||||
|
@ -113,10 +113,10 @@ impl dyn Database {
|
|||
/// Takes an optional type parameter `U` that allows you to thread your own data.
|
||||
pub struct DatabaseImpl<U: UserData = ()> {
|
||||
/// Reference to the database. This is always `Some` except during destruction.
|
||||
zalsa_impl: Option<Arc<ZalsaImpl>>,
|
||||
zalsa_impl: Option<Arc<Zalsa>>,
|
||||
|
||||
/// Coordination data for cancellation of other handles when `zalsa_mut` is called.
|
||||
/// This could be stored in ZalsaImpl but it makes things marginally cleaner to keep it separate.
|
||||
/// This could be stored in Zalsa but it makes things marginally cleaner to keep it separate.
|
||||
coordinate: Arc<Coordinate>,
|
||||
|
||||
/// Per-thread state
|
||||
|
@ -147,7 +147,7 @@ impl<U: UserData> DatabaseImpl<U> {
|
|||
/// You can also use the [`Default`][] trait if your userdata implements it.
|
||||
pub fn with(u: U) -> Self {
|
||||
Self {
|
||||
zalsa_impl: Some(Arc::new(ZalsaImpl::with(u))),
|
||||
zalsa_impl: Some(Arc::new(Zalsa::with(u))),
|
||||
coordinate: Arc::new(Coordinate {
|
||||
clones: Mutex::new(1),
|
||||
cvar: Default::default(),
|
||||
|
@ -157,10 +157,10 @@ impl<U: UserData> DatabaseImpl<U> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Access the `Arc<ZalsaImpl>`. This should always be
|
||||
/// Access the `Arc<Zalsa>`. This should always be
|
||||
/// possible as `zalsa_impl` only becomes
|
||||
/// `None` once we are in the `Drop` impl.
|
||||
fn zalsa_impl(&self) -> &Arc<ZalsaImpl> {
|
||||
fn zalsa_impl(&self) -> &Arc<Zalsa> {
|
||||
self.zalsa_impl.as_ref().unwrap()
|
||||
}
|
||||
|
||||
|
@ -200,11 +200,11 @@ impl<U: UserData + RefUnwindSafe> RefUnwindSafe for DatabaseImpl<U> {}
|
|||
|
||||
#[salsa_macros::db]
|
||||
unsafe impl<U: UserData> Database for DatabaseImpl<U> {
|
||||
fn zalsa(&self) -> &dyn Zalsa {
|
||||
fn zalsa(&self) -> &Zalsa {
|
||||
&**self.zalsa_impl()
|
||||
}
|
||||
|
||||
fn zalsa_mut(&mut self) -> &mut dyn Zalsa {
|
||||
fn zalsa_mut(&mut self) -> &mut Zalsa {
|
||||
self.cancel_others();
|
||||
|
||||
// The ref count on the `Arc` should now be 1
|
||||
|
|
|
@ -98,7 +98,7 @@ where
|
|||
pub(super) fn shallow_verify_memo(
|
||||
&self,
|
||||
db: &C::DbView,
|
||||
zalsa: &dyn Zalsa,
|
||||
zalsa: &Zalsa,
|
||||
database_key_index: DatabaseKeyIndex,
|
||||
memo: &Memo<C::Output<'_>>,
|
||||
) -> bool {
|
||||
|
|
|
@ -129,7 +129,7 @@ impl<V> Memo<V> {
|
|||
}
|
||||
}
|
||||
/// True if this memo is known not to have changed based on its durability.
|
||||
pub(super) fn check_durability(&self, zalsa: &dyn Zalsa) -> bool {
|
||||
pub(super) fn check_durability(&self, zalsa: &Zalsa) -> bool {
|
||||
let last_changed = zalsa.last_changed_revision(self.revisions.durability);
|
||||
let verified_at = self.verified_at.load();
|
||||
tracing::debug!(
|
||||
|
|
212
src/storage.rs
212
src/storage.rs
|
@ -16,131 +16,6 @@ pub fn views<Db: ?Sized + Database>(db: &Db) -> &Views {
|
|||
db.zalsa().views()
|
||||
}
|
||||
|
||||
/// The "plumbing interface" to the Salsa database.
|
||||
///
|
||||
/// **NOT SEMVER STABLE.**
|
||||
pub trait Zalsa {
|
||||
/// Returns a reference to the underlying.
|
||||
fn views(&self) -> &Views;
|
||||
|
||||
/// Returns the nonce for the underyling storage.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This nonce is guaranteed to be unique for the database and never to be reused.
|
||||
fn nonce(&self) -> Nonce<StorageNonce>;
|
||||
|
||||
/// Lookup the index assigned to the given jar (if any). This lookup is based purely on the jar's type.
|
||||
fn lookup_jar_by_type(&self, jar: &dyn Jar) -> Option<IngredientIndex>;
|
||||
|
||||
/// Adds a jar to the database, returning the index of the first ingredient.
|
||||
/// If a jar of this type is already present, returns the existing index.
|
||||
fn add_or_lookup_jar_by_type(&self, jar: &dyn Jar) -> IngredientIndex;
|
||||
|
||||
/// Gets an `&`-ref to an ingredient by index
|
||||
fn lookup_ingredient(&self, index: IngredientIndex) -> &dyn Ingredient;
|
||||
|
||||
/// Gets an `&mut`-ref to an ingredient by index.
|
||||
fn lookup_ingredient_mut(&mut self, index: IngredientIndex) -> &mut dyn Ingredient;
|
||||
|
||||
fn runtimex(&self) -> &Runtime;
|
||||
|
||||
/// Return the current revision
|
||||
fn current_revision(&self) -> Revision;
|
||||
|
||||
/// Return the time when an input of durability `durability` last changed
|
||||
fn last_changed_revision(&self, durability: Durability) -> Revision;
|
||||
|
||||
/// True if any threads have signalled for cancellation
|
||||
fn load_cancellation_flag(&self) -> bool;
|
||||
|
||||
/// Signal for cancellation, indicating current thread is trying to get unique access.
|
||||
fn set_cancellation_flag(&self);
|
||||
|
||||
/// Reports a (synthetic) tracked write to "some input of the given durability".
|
||||
fn report_tracked_write(&mut self, durability: Durability);
|
||||
}
|
||||
|
||||
impl Zalsa for ZalsaImpl {
|
||||
fn views(&self) -> &Views {
|
||||
&self.views_of
|
||||
}
|
||||
|
||||
fn nonce(&self) -> Nonce<StorageNonce> {
|
||||
self.nonce
|
||||
}
|
||||
|
||||
fn lookup_jar_by_type(&self, jar: &dyn Jar) -> Option<IngredientIndex> {
|
||||
self.jar_map.lock().get(&jar.type_id()).copied()
|
||||
}
|
||||
|
||||
fn add_or_lookup_jar_by_type(&self, jar: &dyn Jar) -> IngredientIndex {
|
||||
{
|
||||
let jar_type_id = jar.type_id();
|
||||
let mut jar_map = self.jar_map.lock();
|
||||
*jar_map
|
||||
.entry(jar_type_id)
|
||||
.or_insert_with(|| {
|
||||
let index = IngredientIndex::from(self.ingredients_vec.len());
|
||||
let ingredients = jar.create_ingredients(index);
|
||||
for ingredient in ingredients {
|
||||
let expected_index = ingredient.ingredient_index();
|
||||
|
||||
if ingredient.requires_reset_for_new_revision() {
|
||||
self.ingredients_requiring_reset.push(expected_index);
|
||||
}
|
||||
|
||||
let actual_index = self
|
||||
.ingredients_vec
|
||||
.push(ingredient);
|
||||
assert_eq!(
|
||||
expected_index.as_usize(),
|
||||
actual_index,
|
||||
"ingredient `{:?}` was predicted to have index `{:?}` but actually has index `{:?}`",
|
||||
self.ingredients_vec.get(actual_index).unwrap(),
|
||||
expected_index,
|
||||
actual_index,
|
||||
);
|
||||
|
||||
}
|
||||
index
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_ingredient(&self, index: IngredientIndex) -> &dyn Ingredient {
|
||||
&**self.ingredients_vec.get(index.as_usize()).unwrap()
|
||||
}
|
||||
|
||||
fn lookup_ingredient_mut(&mut self, index: IngredientIndex) -> &mut dyn Ingredient {
|
||||
&mut **self.ingredients_vec.get_mut(index.as_usize()).unwrap()
|
||||
}
|
||||
|
||||
fn current_revision(&self) -> Revision {
|
||||
self.runtime.current_revision()
|
||||
}
|
||||
|
||||
fn load_cancellation_flag(&self) -> bool {
|
||||
self.runtime.load_cancellation_flag()
|
||||
}
|
||||
|
||||
fn report_tracked_write(&mut self, durability: Durability) {
|
||||
self.runtime.report_tracked_write(durability)
|
||||
}
|
||||
|
||||
fn runtimex(&self) -> &Runtime {
|
||||
&self.runtime
|
||||
}
|
||||
|
||||
fn last_changed_revision(&self, durability: Durability) -> Revision {
|
||||
self.runtime.last_changed_revision(durability)
|
||||
}
|
||||
|
||||
fn set_cancellation_flag(&self) {
|
||||
self.runtime.set_cancellation_flag()
|
||||
}
|
||||
}
|
||||
|
||||
/// Nonce type representing the underlying database storage.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct StorageNonce;
|
||||
|
@ -180,9 +55,10 @@ impl IngredientIndex {
|
|||
}
|
||||
}
|
||||
|
||||
/// The "storage" struct stores all the data for the jars.
|
||||
/// It is shared between the main database and any active snapshots.
|
||||
pub(crate) struct ZalsaImpl {
|
||||
/// The "plumbing interface" to the Salsa database. Stores all the ingredients and other data.
|
||||
///
|
||||
/// **NOT SEMVER STABLE.**
|
||||
pub struct Zalsa {
|
||||
user_data: Box<dyn Any + Send + Sync>,
|
||||
|
||||
views_of: Views,
|
||||
|
@ -210,7 +86,7 @@ pub(crate) struct ZalsaImpl {
|
|||
runtime: Runtime,
|
||||
}
|
||||
|
||||
impl ZalsaImpl {
|
||||
impl Zalsa {
|
||||
pub(crate) fn with<U: UserData>(user_data: U) -> Self {
|
||||
Self {
|
||||
views_of: Views::new::<DatabaseImpl<U>>(),
|
||||
|
@ -223,6 +99,84 @@ impl ZalsaImpl {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn views(&self) -> &Views {
|
||||
&self.views_of
|
||||
}
|
||||
|
||||
pub(crate) fn nonce(&self) -> Nonce<StorageNonce> {
|
||||
self.nonce
|
||||
}
|
||||
|
||||
/// **NOT SEMVER STABLE**
|
||||
pub fn add_or_lookup_jar_by_type(&self, jar: &dyn Jar) -> IngredientIndex {
|
||||
{
|
||||
let jar_type_id = jar.type_id();
|
||||
let mut jar_map = self.jar_map.lock();
|
||||
*jar_map
|
||||
.entry(jar_type_id)
|
||||
.or_insert_with(|| {
|
||||
let index = IngredientIndex::from(self.ingredients_vec.len());
|
||||
let ingredients = jar.create_ingredients(index);
|
||||
for ingredient in ingredients {
|
||||
let expected_index = ingredient.ingredient_index();
|
||||
|
||||
if ingredient.requires_reset_for_new_revision() {
|
||||
self.ingredients_requiring_reset.push(expected_index);
|
||||
}
|
||||
|
||||
let actual_index = self
|
||||
.ingredients_vec
|
||||
.push(ingredient);
|
||||
assert_eq!(
|
||||
expected_index.as_usize(),
|
||||
actual_index,
|
||||
"ingredient `{:?}` was predicted to have index `{:?}` but actually has index `{:?}`",
|
||||
self.ingredients_vec.get(actual_index).unwrap(),
|
||||
expected_index,
|
||||
actual_index,
|
||||
);
|
||||
|
||||
}
|
||||
index
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn lookup_ingredient(&self, index: IngredientIndex) -> &dyn Ingredient {
|
||||
&**self.ingredients_vec.get(index.as_usize()).unwrap()
|
||||
}
|
||||
|
||||
/// **NOT SEMVER STABLE**
|
||||
pub fn lookup_ingredient_mut(&mut self, index: IngredientIndex) -> &mut dyn Ingredient {
|
||||
&mut **self.ingredients_vec.get_mut(index.as_usize()).unwrap()
|
||||
}
|
||||
|
||||
/// **NOT SEMVER STABLE**
|
||||
pub fn current_revision(&self) -> Revision {
|
||||
self.runtime.current_revision()
|
||||
}
|
||||
|
||||
pub(crate) fn load_cancellation_flag(&self) -> bool {
|
||||
self.runtime.load_cancellation_flag()
|
||||
}
|
||||
|
||||
pub(crate) fn report_tracked_write(&mut self, durability: Durability) {
|
||||
self.runtime.report_tracked_write(durability)
|
||||
}
|
||||
|
||||
pub(crate) fn runtimex(&self) -> &Runtime {
|
||||
&self.runtime
|
||||
}
|
||||
|
||||
/// **NOT SEMVER STABLE**
|
||||
pub fn last_changed_revision(&self, durability: Durability) -> Revision {
|
||||
self.runtime.last_changed_revision(durability)
|
||||
}
|
||||
|
||||
pub(crate) fn set_cancellation_flag(&self) {
|
||||
self.runtime.set_cancellation_flag()
|
||||
}
|
||||
|
||||
pub(crate) fn user_data(&self) -> &(dyn Any + Send + Sync) {
|
||||
&*self.user_data
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue