Skip to content

Commit

Permalink
merge handle into the database
Browse files Browse the repository at this point in the history
Separate handles are no longer needed.
  • Loading branch information
nikomatsakis committed Jul 27, 2024
1 parent d5f2ea7 commit 69a2cb8
Show file tree
Hide file tree
Showing 11 changed files with 131 additions and 195 deletions.
3 changes: 2 additions & 1 deletion components/salsa-macro-rules/src/setup_input_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ macro_rules! setup_input_struct {
pub fn ingredient_mut(db: &mut dyn $zalsa::Database) -> (&mut $zalsa_struct::IngredientImpl<Self>, $zalsa::Revision) {
let zalsa_mut = db.zalsa_mut();
let index = zalsa_mut.add_or_lookup_jar_by_type(&<$zalsa_struct::JarImpl<$Configuration>>::default());
let (ingredient, current_revision) = zalsa_mut.lookup_ingredient_mut(index);
let current_revision = zalsa_mut.current_revision();
let ingredient = zalsa_mut.lookup_ingredient_mut(index);
let ingredient = ingredient.assert_type_mut::<$zalsa_struct::IngredientImpl<Self>>();
(ingredient, current_revision)
}
Expand Down
97 changes: 85 additions & 12 deletions src/database.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::{any::Any, panic::RefUnwindSafe};
use std::{any::Any, panic::RefUnwindSafe, sync::Arc};

use parking_lot::{Condvar, Mutex};

use crate::{
self as salsa, local_state,
storage::{Zalsa, ZalsaImpl},
Durability, Event, Revision,
Durability, Event, EventKind, Revision,
};

/// The trait implemented by all Salsa databases.
Expand Down Expand Up @@ -34,7 +36,6 @@ pub unsafe trait Database: AsDynDatabase + Any {
/// is owned by the current thread, this could trigger deadlock.
fn synthetic_write(&mut self, durability: Durability) {
let zalsa_mut = self.zalsa_mut();
zalsa_mut.new_revision();
zalsa_mut.report_tracked_write(durability);
}

Expand All @@ -57,10 +58,14 @@ pub unsafe trait Database: AsDynDatabase + Any {
local_state::attach(self, |_state| op(self))
}

/// Plumbing methods.
/// Plumbing method: Access the internal salsa methods.
#[doc(hidden)]
fn zalsa(&self) -> &dyn 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;
}
Expand Down Expand Up @@ -102,7 +107,11 @@ impl dyn Database {
/// Concrete implementation of the [`Database`][] trait.
/// Takes an optional type parameter `U` that allows you to thread your own data.
pub struct DatabaseImpl<U: UserData = ()> {
storage: ZalsaImpl<U>,
/// Reference to the database. This is always `Some` except during destruction.
zalsa_impl: Option<Arc<ZalsaImpl<U>>>,

/// Coordination data.
coordinate: Arc<Coordinate>,
}

impl<U: UserData + Default> Default for DatabaseImpl<U> {
Expand All @@ -116,9 +125,7 @@ impl DatabaseImpl<()> {
///
/// You can also use the [`Default`][] trait if your userdata implements it.
pub fn new() -> Self {
Self {
storage: ZalsaImpl::with(()),
}
Self::with(())
}
}

Expand All @@ -128,16 +135,47 @@ impl<U: UserData> DatabaseImpl<U> {
/// You can also use the [`Default`][] trait if your userdata implements it.
pub fn with(u: U) -> Self {
Self {
storage: ZalsaImpl::with(u),
zalsa_impl: Some(Arc::new(ZalsaImpl::with(u))),
coordinate: Arc::new(Coordinate {
clones: Mutex::new(1),
cvar: Default::default(),
}),
}
}

fn zalsa_impl(&self) -> &Arc<ZalsaImpl<U>> {
self.zalsa_impl.as_ref().unwrap()
}

// ANCHOR: cancel_other_workers
/// Sets cancellation flag and blocks until all other workers with access
/// to this storage have completed.
///
/// This could deadlock if there is a single worker with two handles to the
/// same database!
fn cancel_others(&mut self) {
let zalsa = self.zalsa_impl();
zalsa.set_cancellation_flag();

self.salsa_event(&|| Event {
thread_id: std::thread::current().id(),

kind: EventKind::DidSetCancellationFlag,
});

let mut clones = self.coordinate.clones.lock();
while *clones != 1 {
self.coordinate.cvar.wait(&mut clones);
}
}
// ANCHOR_END: cancel_other_workers
}

impl<U: UserData> std::ops::Deref for DatabaseImpl<U> {
type Target = U;

fn deref(&self) -> &U {
&self.storage.user_data()
self.zalsa_impl().user_data()
}
}

Expand All @@ -146,11 +184,17 @@ impl<U: UserData + RefUnwindSafe> RefUnwindSafe for DatabaseImpl<U> {}
#[salsa_macros::db]
unsafe impl<U: UserData> Database for DatabaseImpl<U> {
fn zalsa(&self) -> &dyn Zalsa {
&self.storage
&**self.zalsa_impl()
}

fn zalsa_mut(&mut self) -> &mut dyn Zalsa {
&mut self.storage
self.cancel_others();

// The ref count on the `Arc` should now be 1
let arc_zalsa_mut = self.zalsa_impl.as_mut().unwrap();
let zalsa_mut = Arc::get_mut(arc_zalsa_mut).unwrap();
zalsa_mut.new_revision();
zalsa_mut
}

// Report a salsa event.
Expand All @@ -159,6 +203,28 @@ unsafe impl<U: UserData> Database for DatabaseImpl<U> {
}
}

impl<U: UserData> Clone for DatabaseImpl<U> {
fn clone(&self) -> Self {
*self.coordinate.clones.lock() += 1;

Self {
zalsa_impl: self.zalsa_impl.clone(),
coordinate: Arc::clone(&self.coordinate),
}
}
}

impl<U: UserData> Drop for DatabaseImpl<U> {
fn drop(&mut self) {
// Drop the database handle *first*
self.zalsa_impl.take();

// *Now* decrement the number of clones and notify once we have completed
*self.coordinate.clones.lock() -= 1;
self.coordinate.cvar.notify_all();
}
}

pub trait UserData: Any + Sized {
/// Callback invoked by the [`Database`][] at key points during salsa execution.
/// By overriding this method, you can inject logging or other custom behavior.
Expand All @@ -174,3 +240,10 @@ pub trait UserData: Any + Sized {
}

impl UserData for () {}

struct Coordinate {
/// Counter of the number of clones of actor. Begins at 1.
/// Incremented when cloned, decremented when dropped.
clones: Mutex<usize>,
cvar: Condvar,
}
125 changes: 0 additions & 125 deletions src/handle.rs

This file was deleted.

2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ mod database;
mod durability;
mod event;
mod function;
mod handle;
mod hash;
mod id;
mod ingredient;
Expand Down Expand Up @@ -36,7 +35,6 @@ pub use self::database::UserData;
pub use self::durability::Durability;
pub use self::event::Event;
pub use self::event::EventKind;
pub use self::handle::Handle;
pub use self::id::Id;
pub use self::input::setter::Setter;
pub use self::key::DatabaseKeyIndex;
Expand Down
Loading

0 comments on commit 69a2cb8

Please sign in to comment.