Skip to content

Commit

Permalink
Do not allocate input singleton data for non-singleton inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril committed Dec 15, 2024
1 parent 5cd2b63 commit c97a75c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 36 deletions.
2 changes: 1 addition & 1 deletion components/salsa-macro-rules/src/setup_input_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ macro_rules! setup_input_struct {
impl $zalsa_struct::Configuration for $Configuration {
const DEBUG_NAME: &'static str = stringify!($Struct);
const FIELD_DEBUG_NAMES: &'static [&'static str] = &[$(stringify!($field_id)),*];
const IS_SINGLETON: bool = $is_singleton;
type Singleton = $zalsa::macro_if! {if $is_singleton {$zalsa::input::Singleton} else {$zalsa::input::NoSingleton}};

/// The input struct (which wraps an `Id`)
type Struct = $Struct;
Expand Down
55 changes: 20 additions & 35 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ use std::{any::Any, fmt, ops::DerefMut};

pub mod input_field;
pub mod setter;
pub mod singleton;

use crossbeam::atomic::AtomicCell;
use input_field::FieldIngredientImpl;
use parking_lot::Mutex;

use crate::{
accumulator::accumulated_map::InputAccumulatedValues,
cycle::CycleRecoveryStrategy,
id::{AsId, FromId},
ingredient::{fmt_index, Ingredient},
input::singleton::{Singleton, SingletonChoice},
key::{DatabaseKeyIndex, DependencyIndex},
plumbing::{Jar, JarAux, Stamp},
table::{memo::MemoTable, sync::SyncTable, Slot, Table},
Expand All @@ -23,7 +23,9 @@ use crate::{
pub trait Configuration: Any {
const DEBUG_NAME: &'static str;
const FIELD_DEBUG_NAMES: &'static [&'static str];
const IS_SINGLETON: bool;

/// The singleton state for this input if any.
type Singleton: SingletonChoice + Send + Sync;

/// The input struct (which wraps an `Id`)
type Struct: FromId + 'static + Send + Sync;
Expand Down Expand Up @@ -65,17 +67,15 @@ impl<C: Configuration> Jar for JarImpl<C> {

pub struct IngredientImpl<C: Configuration> {
ingredient_index: IngredientIndex,
singleton_index: AtomicCell<Option<Id>>,
singleton_lock: Mutex<()>,
singleton: C::Singleton,
_phantom: std::marker::PhantomData<C::Struct>,
}

impl<C: Configuration> IngredientImpl<C> {
pub fn new(index: IngredientIndex) -> Self {
Self {
ingredient_index: index,
singleton_index: AtomicCell::new(None),
singleton_lock: Default::default(),
singleton: Default::default(),
_phantom: std::marker::PhantomData,
}
}
Expand All @@ -98,29 +98,15 @@ impl<C: Configuration> IngredientImpl<C> {
pub fn new_input(&self, db: &dyn Database, fields: C::Fields, stamps: C::Stamps) -> C::Struct {
let (zalsa, zalsa_local) = db.zalsas();

// If declared as a singleton, only allow a single instance
let guard = if C::IS_SINGLETON {
let guard = self.singleton_lock.lock();
if self.singleton_index.load().is_some() {
panic!("singleton struct may not be duplicated");
}
Some(guard)
} else {
None
};

let id = zalsa_local.allocate(zalsa.table(), self.ingredient_index, || Value::<C> {
fields,
stamps,
memos: Default::default(),
syncs: Default::default(),
let id = self.singleton.with_lock(|| {
zalsa_local.allocate(zalsa.table(), self.ingredient_index, || Value::<C> {
fields,
stamps,
memos: Default::default(),
syncs: Default::default(),
})
});

if C::IS_SINGLETON {
self.singleton_index.store(Some(id));
drop(guard);
}

FromId::from_id(id)
}

Expand Down Expand Up @@ -159,13 +145,12 @@ impl<C: Configuration> IngredientImpl<C> {
setter(&mut r.fields)
}

/// Get the singleton input previously created (if any).
pub fn get_singleton_input(&self) -> Option<C::Struct> {
assert!(
C::IS_SINGLETON,
"get_singleton_input invoked on a non-singleton"
);
self.singleton_index.load().map(FromId::from_id)
/// Get the singleton input previously created.
pub fn get_singleton_input(&self) -> Option<C::Struct>
where
C: Configuration<Singleton = Singleton>,
{
self.singleton.index().map(FromId::from_id)
}

/// Access field of an input.
Expand Down
55 changes: 55 additions & 0 deletions src/input/singleton.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crossbeam::atomic::AtomicCell;
use parking_lot::Mutex;

use crate::{id::FromId, Id};

mod sealed {
pub trait Sealed {}
}

pub trait SingletonChoice: sealed::Sealed + Default {
fn with_lock(&self, cb: impl FnOnce() -> Id) -> Id;
fn index(&self) -> Option<Id>;
}

pub struct Singleton {
index: AtomicCell<Option<Id>>,
lock: Mutex<()>,
}
impl sealed::Sealed for Singleton {}
impl SingletonChoice for Singleton {
fn with_lock(&self, cb: impl FnOnce() -> Id) -> Id {
let _guard = self.lock.lock();
if self.index.load().is_some() {
panic!("singleton struct may not be duplicated");
}
let id = cb();
self.index.store(Some(id));
drop(_guard);
id
}

fn index(&self) -> Option<Id> {
self.index.load().map(FromId::from_id)
}
}

impl Default for Singleton {
fn default() -> Self {
Self {
index: AtomicCell::new(None),
lock: Default::default(),
}
}
}
#[derive(Default)]
pub struct NoSingleton;
impl sealed::Sealed for NoSingleton {}
impl SingletonChoice for NoSingleton {
fn with_lock(&self, cb: impl FnOnce() -> Id) -> Id {
cb()
}
fn index(&self) -> Option<Id> {
None
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ pub mod plumbing {
pub mod input {
pub use crate::input::input_field::FieldIngredientImpl;
pub use crate::input::setter::SetterImpl;
pub use crate::input::singleton::NoSingleton;
pub use crate::input::singleton::Singleton;
pub use crate::input::Configuration;
pub use crate::input::HasBuilder;
pub use crate::input::IngredientImpl;
Expand Down

0 comments on commit c97a75c

Please sign in to comment.