mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-07-07 21:35:17 +00:00
Use Revision
and Durability
directly in input Value
(#902)
`Stamp` contains a lot of padding bytes, wasting 7 bytes per field for inputs due to the array packing. By packing each field into a separate array we regain that space
This commit is contained in:
parent
2c57c5628b
commit
38a3c9e06d
7 changed files with 43 additions and 46 deletions
|
@ -80,14 +80,12 @@ macro_rules! setup_input_struct {
|
|||
const FIELD_DEBUG_NAMES: &'static [&'static str] = &[$(stringify!($field_id)),*];
|
||||
type Singleton = $zalsa::macro_if! {if $is_singleton {$zalsa::input::Singleton} else {$zalsa::input::NotSingleton}};
|
||||
|
||||
/// The input struct (which wraps an `Id`)
|
||||
type Struct = $Struct;
|
||||
|
||||
/// A (possibly empty) tuple of the fields for this struct.
|
||||
type Fields = ($($field_ty,)*);
|
||||
|
||||
/// A array of [`StampedValue<()>`](`StampedValue`) tuples, one per each of the value fields.
|
||||
type Stamps = [$zalsa::Stamp; $N];
|
||||
type Revisions = [$zalsa::Revision; $N];
|
||||
type Durabilities = [$zalsa::Durability; $N];
|
||||
}
|
||||
|
||||
impl $Configuration {
|
||||
|
@ -274,8 +272,8 @@ macro_rules! setup_input_struct {
|
|||
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)
|
||||
let (fields, revision, durabilities) = builder::builder_into_inner(self, current_revision);
|
||||
ingredient.new_input(db.as_dyn_database(), fields, revision, durabilities)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,10 +292,8 @@ macro_rules! setup_input_struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn builder_into_inner(builder: $Builder, revision: $zalsa::Revision) -> (($($field_ty,)*), [$zalsa::Stamp; $N]) {
|
||||
let stamps = [$($zalsa::stamp(revision, builder.durabilities[$field_index])),*];
|
||||
|
||||
(builder.fields, stamps)
|
||||
pub(super) fn builder_into_inner(builder: $Builder, revision: $zalsa::Revision) -> (($($field_ty,)*), [$zalsa::Revision; $N], [$zalsa::Durability; $N]) {
|
||||
(builder.fields, [revision; $N], [$(builder.durabilities[$field_index]),*])
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
|
|
|
@ -141,7 +141,6 @@ impl ActiveQuery {
|
|||
|
||||
pub(super) fn stamp(&self) -> Stamp {
|
||||
Stamp {
|
||||
value: (),
|
||||
durability: self.durability,
|
||||
changed_at: self.changed_at,
|
||||
}
|
||||
|
|
44
src/input.rs
44
src/input.rs
|
@ -14,7 +14,7 @@ use crate::id::{AsId, FromId, FromIdWithDb};
|
|||
use crate::ingredient::Ingredient;
|
||||
use crate::input::singleton::{Singleton, SingletonChoice};
|
||||
use crate::key::DatabaseKeyIndex;
|
||||
use crate::plumbing::{Jar, Stamp};
|
||||
use crate::plumbing::Jar;
|
||||
use crate::sync::Arc;
|
||||
use crate::table::memo::{MemoTable, MemoTableTypes};
|
||||
use crate::table::{Slot, Table};
|
||||
|
@ -35,8 +35,11 @@ pub trait Configuration: Any {
|
|||
/// A (possibly empty) tuple of the fields for this struct.
|
||||
type Fields: Send + Sync;
|
||||
|
||||
/// A array of [`StampedValue<()>`](`StampedValue`) tuples, one per each of the value fields.
|
||||
type Stamps: Send + Sync + fmt::Debug + IndexMut<usize, Output = Stamp>;
|
||||
/// A array of [`Revision`], one per each of the value fields.
|
||||
type Revisions: Send + Sync + fmt::Debug + IndexMut<usize, Output = Revision>;
|
||||
|
||||
/// A array of [`Durability`], one per each of the value fields.
|
||||
type Durabilities: Send + Sync + fmt::Debug + IndexMut<usize, Output = Durability>;
|
||||
}
|
||||
|
||||
pub struct JarImpl<C: Configuration> {
|
||||
|
@ -100,13 +103,20 @@ impl<C: Configuration> IngredientImpl<C> {
|
|||
DatabaseKeyIndex::new(self.ingredient_index, id.as_id())
|
||||
}
|
||||
|
||||
pub fn new_input(&self, db: &dyn Database, fields: C::Fields, stamps: C::Stamps) -> C::Struct {
|
||||
pub fn new_input(
|
||||
&self,
|
||||
db: &dyn Database,
|
||||
fields: C::Fields,
|
||||
revisions: C::Revisions,
|
||||
durabilities: C::Durabilities,
|
||||
) -> C::Struct {
|
||||
let (zalsa, zalsa_local) = db.zalsas();
|
||||
|
||||
let id = self.singleton.with_scope(|| {
|
||||
zalsa_local.allocate(zalsa, self.ingredient_index, |_| Value::<C> {
|
||||
fields,
|
||||
stamps,
|
||||
revisions,
|
||||
durabilities,
|
||||
memos: Default::default(),
|
||||
})
|
||||
});
|
||||
|
@ -139,14 +149,14 @@ impl<C: Configuration> IngredientImpl<C> {
|
|||
// Also, we don't access any other data from the table while `r` is active.
|
||||
let data = unsafe { &mut *data_raw };
|
||||
|
||||
let stamp = &mut data.stamps[field_index];
|
||||
data.revisions[field_index] = runtime.current_revision();
|
||||
|
||||
if stamp.durability != Durability::MIN {
|
||||
runtime.report_tracked_write(stamp.durability);
|
||||
let field_durability = &mut data.durabilities[field_index];
|
||||
if *field_durability != Durability::MIN {
|
||||
runtime.report_tracked_write(*field_durability);
|
||||
}
|
||||
*field_durability = durability.unwrap_or(*field_durability);
|
||||
|
||||
stamp.durability = durability.unwrap_or(stamp.durability);
|
||||
stamp.changed_at = runtime.current_revision();
|
||||
setter(&mut data.fields)
|
||||
}
|
||||
|
||||
|
@ -174,11 +184,12 @@ impl<C: Configuration> IngredientImpl<C> {
|
|||
let field_ingredient_index = self.ingredient_index.successor(field_index);
|
||||
let id = id.as_id();
|
||||
let value = Self::data(zalsa, id);
|
||||
let stamp = &value.stamps[field_index];
|
||||
let durability = value.durabilities[field_index];
|
||||
let revision = value.revisions[field_index];
|
||||
zalsa_local.report_tracked_read_simple(
|
||||
DatabaseKeyIndex::new(field_ingredient_index, id),
|
||||
stamp.durability,
|
||||
stamp.changed_at,
|
||||
durability,
|
||||
revision,
|
||||
);
|
||||
&value.fields
|
||||
}
|
||||
|
@ -251,8 +262,11 @@ where
|
|||
/// a particular revision.
|
||||
fields: C::Fields,
|
||||
|
||||
/// The revision and durability information for each field: when did this field last change.
|
||||
stamps: C::Stamps,
|
||||
/// Revisions of the fields.
|
||||
revisions: C::Revisions,
|
||||
|
||||
/// Durabilities of the fields.
|
||||
durabilities: C::Durabilities,
|
||||
|
||||
/// Memos
|
||||
memos: MemoTable,
|
||||
|
|
|
@ -59,7 +59,7 @@ where
|
|||
) -> VerifyResult {
|
||||
let zalsa = db.zalsa();
|
||||
let value = <IngredientImpl<C>>::data(zalsa, input);
|
||||
VerifyResult::changed_if(value.stamps[self.field_index].changed_at > revision)
|
||||
VerifyResult::changed_if(value.revisions[self.field_index] > revision)
|
||||
}
|
||||
|
||||
fn fmt_index(&self, index: crate::Id, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
|
|
|
@ -84,6 +84,7 @@ pub mod plumbing {
|
|||
pub use crate::attach::{attach, with_attached_database};
|
||||
pub use crate::cycle::{CycleRecoveryAction, CycleRecoveryStrategy};
|
||||
pub use crate::database::{current_revision, Database};
|
||||
pub use crate::durability::Durability;
|
||||
pub use crate::id::{AsId, FromId, FromIdWithDb, Id};
|
||||
pub use crate::ingredient::{Ingredient, Jar, Location};
|
||||
pub use crate::key::DatabaseKeyIndex;
|
||||
|
@ -92,7 +93,7 @@ pub mod plumbing {
|
|||
NewMemoIngredientIndices,
|
||||
};
|
||||
pub use crate::revision::Revision;
|
||||
pub use crate::runtime::{stamp, Runtime, Stamp, StampedValue};
|
||||
pub use crate::runtime::{stamp, Runtime, Stamp};
|
||||
pub use crate::salsa_struct::SalsaStructInDb;
|
||||
pub use crate::storage::{HasStorage, Storage};
|
||||
pub use crate::tracked_struct::TrackedStructInDb;
|
||||
|
|
|
@ -116,31 +116,18 @@ impl std::fmt::Debug for Running<'_> {
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct StampedValue<V> {
|
||||
pub value: V,
|
||||
pub struct Stamp {
|
||||
pub durability: Durability,
|
||||
pub changed_at: Revision,
|
||||
}
|
||||
|
||||
pub type Stamp = StampedValue<()>;
|
||||
|
||||
pub fn stamp(revision: Revision, durability: Durability) -> Stamp {
|
||||
StampedValue {
|
||||
value: (),
|
||||
Stamp {
|
||||
durability,
|
||||
changed_at: revision,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> StampedValue<V> {
|
||||
// FIXME: Use or remove this.
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn merge_revision_info<U>(&mut self, other: &StampedValue<U>) {
|
||||
self.durability = self.durability.min(other.durability);
|
||||
self.changed_at = self.changed_at.max(other.changed_at);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Runtime {
|
||||
fn default() -> Self {
|
||||
Runtime {
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::ingredient::{Ingredient, Jar};
|
|||
use crate::key::DatabaseKeyIndex;
|
||||
use crate::plumbing::ZalsaLocal;
|
||||
use crate::revision::OptionalAtomicRevision;
|
||||
use crate::runtime::StampedValue;
|
||||
use crate::runtime::Stamp;
|
||||
use crate::salsa_struct::SalsaStructInDb;
|
||||
use crate::sync::Arc;
|
||||
use crate::table::memo::{MemoTable, MemoTableTypes, MemoTableWithTypesMut};
|
||||
|
@ -435,7 +435,7 @@ where
|
|||
zalsa: &'db Zalsa,
|
||||
zalsa_local: &'db ZalsaLocal,
|
||||
current_revision: Revision,
|
||||
current_deps: &StampedValue<()>,
|
||||
current_deps: &Stamp,
|
||||
fields: C::Fields<'db>,
|
||||
) -> Id {
|
||||
let value = |_| Value {
|
||||
|
@ -496,7 +496,7 @@ where
|
|||
zalsa: &'db Zalsa,
|
||||
current_revision: Revision,
|
||||
mut id: Id,
|
||||
current_deps: &StampedValue<()>,
|
||||
current_deps: &Stamp,
|
||||
fields: C::Fields<'db>,
|
||||
) -> Result<Id, C::Fields<'db>> {
|
||||
let data_raw = Self::data_raw(zalsa.table(), id);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue