Skip to content

Move salsa event system into Zalsa #849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions components/salsa-macro-rules/src/setup_accumulator_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@ macro_rules! setup_accumulator_impl {

// Suppress the lint against `cfg(loom)`.
#[allow(unexpected_cfgs)]
fn $ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<$Struct> {
fn $ingredient(zalsa: &$zalsa::Zalsa) -> &$zalsa_struct::IngredientImpl<$Struct> {
$zalsa::__maybe_lazy_static! {
static $CACHE: $zalsa::IngredientCache<$zalsa_struct::IngredientImpl<$Struct>> =
$zalsa::IngredientCache::new();
}

let zalsa = db.zalsa();
$CACHE.get_or_create(zalsa, || {
zalsa.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Struct>>()
})
Expand All @@ -42,8 +41,8 @@ macro_rules! setup_accumulator_impl {
where
Db: ?Sized + $zalsa::Database,
{
let db = db.as_dyn_database();
$ingredient(db).push(db, self);
let (zalsa, zalsa_local) = db.zalsas();
$ingredient(zalsa).push(zalsa_local, self);
}
}
};
Expand Down
17 changes: 11 additions & 6 deletions components/salsa-macro-rules/src/setup_input_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,18 @@ macro_rules! setup_input_struct {
}

impl $Configuration {
pub fn ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<Self> {
Self::ingredient_(db.zalsa())
}

// Suppress the lint against `cfg(loom)`.
#[allow(unexpected_cfgs)]
pub fn ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<Self> {
fn ingredient_(zalsa: &$zalsa::Zalsa) -> &$zalsa_struct::IngredientImpl<Self> {
zalsa_::__maybe_lazy_static! {
static CACHE: $zalsa::IngredientCache<$zalsa_struct::IngredientImpl<$Configuration>> =
$zalsa::IngredientCache::new();
}

let zalsa = db.zalsa();
CACHE.get_or_create(zalsa, || {
zalsa.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>()
})
Expand Down Expand Up @@ -184,7 +187,7 @@ macro_rules! setup_input_struct {
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
$Db: ?Sized + $zalsa::Database,
{
let fields = $Configuration::ingredient(db.as_dyn_database()).field(
let fields = $Configuration::ingredient_(db.zalsa()).field(
db.as_dyn_database(),
self,
$field_index,
Expand Down Expand Up @@ -221,7 +224,8 @@ macro_rules! setup_input_struct {
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
$Db: ?Sized + salsa::Database,
{
$Configuration::ingredient(db.as_dyn_database()).get_singleton_input(db)
let zalsa = db.zalsa();
$Configuration::ingredient_(zalsa).get_singleton_input(zalsa)
}

#[track_caller]
Expand Down Expand Up @@ -271,8 +275,9 @@ macro_rules! setup_input_struct {
// FIXME(rust-lang/rust#65991): The `db` argument *should* have the type `dyn Database`
$Db: ?Sized + salsa::Database
{
let current_revision = $zalsa::current_revision(db);
let ingredient = $Configuration::ingredient(db.as_dyn_database());
let zalsa = db.zalsa();
let current_revision = zalsa.current_revision();
let ingredient = $Configuration::ingredient_(zalsa);
let (fields, stamps) = builder::builder_into_inner(self, current_revision);
ingredient.new_input(db.as_dyn_database(), fields, stamps)
}
Expand Down
4 changes: 2 additions & 2 deletions components/salsa-macro-rules/src/setup_tracked_fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ macro_rules! setup_tracked_fn {
$inner($db, $($input_id),*)
}

fn cycle_initial<$db_lt>(db: &$db_lt dyn $Db, ($($input_id),*): ($($input_ty),*)) -> Self::Output<$db_lt> {
fn cycle_initial<$db_lt>(db: &$db_lt Self::DbView, ($($input_id),*): ($($input_ty),*)) -> Self::Output<$db_lt> {
$($cycle_recovery_initial)*(db, $($input_id),*)
}

Expand All @@ -231,7 +231,7 @@ macro_rules! setup_tracked_fn {
if $needs_interner {
$Configuration::intern_ingredient(db).data(db.as_dyn_database(), key).clone()
} else {
$zalsa::FromIdWithDb::from_id(key, db)
$zalsa::FromIdWithDb::from_id(key, db.zalsa())
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions components/salsa-macro-rules/src/setup_tracked_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,15 +169,18 @@ macro_rules! setup_tracked_struct {
}

impl $Configuration {
pub fn ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<Self> {
Self::ingredient_(db.zalsa())
}

// Suppress the lint against `cfg(loom)`.
#[allow(unexpected_cfgs)]
pub fn ingredient(db: &dyn $zalsa::Database) -> &$zalsa_struct::IngredientImpl<$Configuration> {
fn ingredient_(zalsa: &$zalsa::Zalsa) -> &$zalsa_struct::IngredientImpl<Self> {
$zalsa::__maybe_lazy_static! {
static CACHE: $zalsa::IngredientCache<$zalsa_struct::IngredientImpl<$Configuration>> =
$zalsa::IngredientCache::new();
}

let zalsa = db.zalsa();
CACHE.get_or_create(zalsa, || {
zalsa.add_or_lookup_jar_by_type::<$zalsa_struct::JarImpl<$Configuration>>()
})
Expand Down Expand Up @@ -216,8 +219,8 @@ macro_rules! setup_tracked_struct {
}

impl $zalsa::TrackedStructInDb for $Struct<'_> {
fn database_key_index(db: &dyn $zalsa::Database, id: $zalsa::Id) -> $zalsa::DatabaseKeyIndex {
$Configuration::ingredient(db).database_key_index(id)
fn database_key_index(zalsa: &$zalsa::Zalsa, id: $zalsa::Id) -> $zalsa::DatabaseKeyIndex {
$Configuration::ingredient_(zalsa).database_key_index(id)
}
}

Expand Down
5 changes: 2 additions & 3 deletions components/salsa-macros/src/supertype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ fn enum_impl(enum_item: syn::ItemEnum) -> syn::Result<TokenStream> {
impl #impl_generics zalsa::FromIdWithDb for #enum_name #type_generics
#where_clause {
#[inline]
fn from_id(__id: zalsa::Id, __db: &(impl ?Sized + zalsa::Database)) -> Self {
let __zalsa = __db.zalsa();
let __type_id = __zalsa.lookup_page_type_id(__id);
fn from_id(__id: zalsa::Id, zalsa: &zalsa::Zalsa) -> Self {
let __type_id = zalsa.lookup_page_type_id(__id);
<Self as zalsa::SalsaStructInDb>::cast(__id, __type_id).expect("invalid enum variant")
}
}
Expand Down
42 changes: 28 additions & 14 deletions examples/calc/db.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
#[cfg(test)]
use std::sync::{Arc, Mutex};

// ANCHOR: db_struct
#[salsa::db]
#[derive(Default, Clone)]
#[derive(Clone)]
#[cfg_attr(not(test), derive(Default))]
pub struct CalcDatabaseImpl {
storage: salsa::Storage<Self>,

// The logs are only used for testing and demonstrating reuse:
#[cfg(test)]
logs: Arc<Mutex<Option<Vec<String>>>>,
}

#[cfg(test)]
impl Default for CalcDatabaseImpl {
fn default() -> Self {
let logs = <Arc<Mutex<Option<Vec<String>>>>>::default();
Self {
storage: salsa::Storage::new(Some(Box::new({
let logs = logs.clone();
move |event| {
eprintln!("Event: {event:?}");
// Log interesting events, if logging is enabled
if let Some(logs) = &mut *logs.lock().unwrap() {
// only log interesting events
if let salsa::EventKind::WillExecute { .. } = event.kind {
logs.push(format!("Event: {event:?}"));
}
}
}
}))),
logs,
}
}
}
// ANCHOR_END: db_struct

impl CalcDatabaseImpl {
Expand All @@ -34,17 +60,5 @@ impl CalcDatabaseImpl {

// ANCHOR: db_impl
#[salsa::db]
impl salsa::Database for CalcDatabaseImpl {
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
let event = event();
eprintln!("Event: {event:?}");
// Log interesting events, if logging is enabled
if let Some(logs) = &mut *self.logs.lock().unwrap() {
// only log interesting events
if let salsa::EventKind::WillExecute { .. } = event.kind {
logs.push(format!("Event: {event:?}"));
}
}
}
}
impl salsa::Database for CalcDatabaseImpl {}
// ANCHOR_END: db_impl
23 changes: 12 additions & 11 deletions examples/lazy-input/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,18 @@ struct LazyInputDatabase {

impl LazyInputDatabase {
fn new(tx: Sender<DebounceEventResult>) -> Self {
let logs: Arc<Mutex<Vec<String>>> = Default::default();
Self {
storage: Default::default(),
logs: Default::default(),
storage: Storage::new(Some(Box::new({
let logs = logs.clone();
move |event| {
// don't log boring events
if let salsa::EventKind::WillExecute { .. } = event.kind {
logs.lock().unwrap().push(format!("{event:?}"));
}
}
}))),
logs,
files: DashMap::new(),
file_watcher: Arc::new(Mutex::new(
new_debouncer(Duration::from_secs(1), tx).unwrap(),
Expand All @@ -99,15 +108,7 @@ impl LazyInputDatabase {
}

#[salsa::db]
impl salsa::Database for LazyInputDatabase {
fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
// don't log boring events
let event = event();
if let salsa::EventKind::WillExecute { .. } = event.kind {
self.logs.lock().unwrap().push(format!("{event:?}"));
}
}
}
impl salsa::Database for LazyInputDatabase {}

#[salsa::db]
impl Db for LazyInputDatabase {
Expand Down
11 changes: 3 additions & 8 deletions src/accumulator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use accumulated::{Accumulated, AnyAccumulated};
use crate::function::VerifyResult;
use crate::ingredient::{Ingredient, Jar};
use crate::loom::sync::Arc;
use crate::plumbing::IngredientIndices;
use crate::plumbing::{IngredientIndices, ZalsaLocal};
use crate::table::memo::MemoTableTypes;
use crate::zalsa::{IngredientIndex, Zalsa};
use crate::{Database, Id, Revision};
Expand Down Expand Up @@ -62,11 +62,7 @@ pub struct IngredientImpl<A: Accumulator> {

impl<A: Accumulator> IngredientImpl<A> {
/// Find the accumulator ingredient for `A` in the database, if any.
pub fn from_db<Db>(db: &Db) -> Option<&Self>
where
Db: ?Sized + Database,
{
let zalsa = db.zalsa();
pub fn from_zalsa(zalsa: &Zalsa) -> Option<&Self> {
let index = zalsa.add_or_lookup_jar_by_type::<JarImpl<A>>();
let ingredient = zalsa.lookup_ingredient(index).assert_type::<Self>();
Some(ingredient)
Expand All @@ -79,8 +75,7 @@ impl<A: Accumulator> IngredientImpl<A> {
}
}

pub fn push(&self, db: &dyn Database, value: A) {
let zalsa_local = db.zalsa_local();
pub fn push(&self, zalsa_local: &ZalsaLocal, value: A) {
if let Err(()) = zalsa_local.accumulate(self.index, value) {
panic!("cannot accumulate values outside of an active tracked function");
}
Expand Down
15 changes: 3 additions & 12 deletions src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,11 @@ use std::any::Any;
use std::borrow::Cow;

use crate::zalsa::{IngredientIndex, ZalsaDatabase};
use crate::{Durability, Event, Revision};
use crate::{Durability, Revision};

/// The trait implemented by all Salsa databases.
/// You can create your own subtraits of this trait using the `#[salsa::db]`(`crate::db`) procedural macro.
pub trait Database: Send + AsDynDatabase + Any + ZalsaDatabase {
/// This function is invoked by the salsa runtime at various points during execution.
/// You can customize what happens by implementing the [`UserData`][] trait.
/// By default, the event is logged at level debug using tracing facade.
///
/// # Parameters
///
/// * `event`, a fn that, if called, will create the event that occurred
fn salsa_event(&self, event: &dyn Fn() -> Event);

/// Enforces current LRU limits, evicting entries if necessary.
///
/// **WARNING:** Just like an ordinary write, this method triggers
Expand All @@ -24,7 +15,6 @@ pub trait Database: Send + AsDynDatabase + Any + ZalsaDatabase {
/// is owned by the current thread, this could trigger deadlock.
fn trigger_lru_eviction(&mut self) {
let zalsa_mut = self.zalsa_mut();
zalsa_mut.runtime_mut().reset_cancellation_flag();
zalsa_mut.evict_lru();
}

Expand Down Expand Up @@ -77,7 +67,8 @@ pub trait Database: Send + AsDynDatabase + Any + ZalsaDatabase {
/// `salsa_event` is emitted when this method is called, so that should be
/// used instead.
fn unwind_if_revision_cancelled(&self) {
self.zalsa().unwind_if_revision_cancelled(self);
let (zalsa, zalsa_local) = self.zalsas();
zalsa.unwind_if_revision_cancelled(zalsa_local);
}

/// Execute `op` with the database in thread-local storage for debug print-outs.
Expand Down
29 changes: 20 additions & 9 deletions src/database_impl.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
use tracing::Level;

use crate::storage::HasStorage;
use crate::{Database, Event, Storage};
use crate::{Database, Storage};

/// Default database implementation that you can use if you don't
/// require any custom user data.
#[derive(Default, Clone)]
#[derive(Clone)]
pub struct DatabaseImpl {
storage: Storage<Self>,
}

impl Default for DatabaseImpl {
fn default() -> Self {
Self {
// Default behavior: tracing debug log the event.
storage: Storage::new(if tracing::enabled!(Level::DEBUG) {
Some(Box::new(|event| {
tracing::debug!("salsa_event({:?})", event)
}))
} else {
None
}),
}
}
}

impl DatabaseImpl {
/// Create a new database; equivalent to `Self::default`.
pub fn new() -> Self {
Expand All @@ -19,13 +36,7 @@ impl DatabaseImpl {
}
}

impl Database for DatabaseImpl {
/// Default behavior: tracing debug log the event.
#[inline(always)]
fn salsa_event(&self, event: &dyn Fn() -> Event) {
tracing::debug!("salsa_event({:?})", event());
}
}
impl Database for DatabaseImpl {}

// SAFETY: The `storage` and `storage_mut` fields return a reference to the same storage field owned by `self`.
unsafe impl HasStorage for DatabaseImpl {
Expand Down
Loading