mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-15 09:48:53 +00:00
use Alloc not Box
to avoid uniqueness guarantees
This commit is contained in:
parent
a7b2805b06
commit
81942f37e5
4 changed files with 53 additions and 8 deletions
42
components/salsa-2022/src/alloc.rs
Normal file
42
components/salsa-2022/src/alloc.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
/// A box but without the uniqueness guarantees.
|
||||||
|
pub struct Alloc<T> {
|
||||||
|
data: NonNull<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Alloc<T> {
|
||||||
|
pub fn new(data: T) -> Self {
|
||||||
|
let data = Box::new(data);
|
||||||
|
let data = Box::into_raw(data);
|
||||||
|
Alloc {
|
||||||
|
data: unsafe { NonNull::new_unchecked(data) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Drop for Alloc<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let data: *mut T = self.data.as_ptr();
|
||||||
|
let data: Box<T> = unsafe { Box::from_raw(data) };
|
||||||
|
drop(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::Deref for Alloc<T> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
unsafe { self.data.as_ref() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::ops::DerefMut for Alloc<T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
unsafe { self.data.as_mut() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl<T> Send for Alloc<T> where T: Send {}
|
||||||
|
|
||||||
|
unsafe impl<T> Sync for Alloc<T> where T: Sync {}
|
|
@ -3,6 +3,7 @@ use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::alloc::Alloc;
|
||||||
use crate::durability::Durability;
|
use crate::durability::Durability;
|
||||||
use crate::id::{AsId, LookupId};
|
use crate::id::{AsId, LookupId};
|
||||||
use crate::ingredient::{fmt_index, IngredientRequiresReset};
|
use crate::ingredient::{fmt_index, IngredientRequiresReset};
|
||||||
|
@ -39,7 +40,7 @@ pub struct InternedIngredient<C: Configuration> {
|
||||||
/// Maps from an interned id to its data.
|
/// Maps from an interned id to its data.
|
||||||
///
|
///
|
||||||
/// Deadlock requirement: We access `value_map` while holding lock on `key_map`, but not vice versa.
|
/// Deadlock requirement: We access `value_map` while holding lock on `key_map`, but not vice versa.
|
||||||
value_map: FxDashMap<Id, Box<ValueStruct<C>>>,
|
value_map: FxDashMap<Id, Alloc<ValueStruct<C>>>,
|
||||||
|
|
||||||
/// counter for the next id.
|
/// counter for the next id.
|
||||||
counter: AtomicCell<u32>,
|
counter: AtomicCell<u32>,
|
||||||
|
@ -121,7 +122,7 @@ where
|
||||||
let value = self
|
let value = self
|
||||||
.value_map
|
.value_map
|
||||||
.entry(next_id)
|
.entry(next_id)
|
||||||
.or_insert(Box::new(ValueStruct {
|
.or_insert(Alloc::new(ValueStruct {
|
||||||
id: next_id,
|
id: next_id,
|
||||||
fields: internal_data,
|
fields: internal_data,
|
||||||
}));
|
}));
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
pub mod accumulator;
|
pub mod accumulator;
|
||||||
|
mod alloc;
|
||||||
pub mod cancelled;
|
pub mod cancelled;
|
||||||
pub mod cycle;
|
pub mod cycle;
|
||||||
pub mod database;
|
pub mod database;
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crossbeam::queue::SegQueue;
|
||||||
use dashmap::mapref::one::RefMut;
|
use dashmap::mapref::one::RefMut;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
alloc::Alloc,
|
||||||
hash::{FxDashMap, FxHasher},
|
hash::{FxDashMap, FxHasher},
|
||||||
plumbing::transmute_lifetime,
|
plumbing::transmute_lifetime,
|
||||||
Id, Runtime,
|
Id, Runtime,
|
||||||
|
@ -18,21 +19,21 @@ pub(crate) struct StructMap<C>
|
||||||
where
|
where
|
||||||
C: Configuration,
|
C: Configuration,
|
||||||
{
|
{
|
||||||
map: Arc<FxDashMap<Id, Box<ValueStruct<C>>>>,
|
map: Arc<FxDashMap<Id, Alloc<ValueStruct<C>>>>,
|
||||||
|
|
||||||
/// When specific entities are deleted, their data is added
|
/// When specific entities are deleted, their data is added
|
||||||
/// to this vector rather than being immediately freed. This is because we may` have
|
/// to this vector rather than being immediately freed. This is because we may` have
|
||||||
/// references to that data floating about that are tied to the lifetime of some
|
/// references to that data floating about that are tied to the lifetime of some
|
||||||
/// `&db` reference. This queue itself is not freed until we have an `&mut db` reference,
|
/// `&db` reference. This queue itself is not freed until we have an `&mut db` reference,
|
||||||
/// guaranteeing that there are no more references to it.
|
/// guaranteeing that there are no more references to it.
|
||||||
deleted_entries: SegQueue<Box<ValueStruct<C>>>,
|
deleted_entries: SegQueue<Alloc<ValueStruct<C>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct StructMapView<C>
|
pub(crate) struct StructMapView<C>
|
||||||
where
|
where
|
||||||
C: Configuration,
|
C: Configuration,
|
||||||
{
|
{
|
||||||
map: Arc<FxDashMap<Id, Box<ValueStruct<C>>>>,
|
map: Arc<FxDashMap<Id, Alloc<ValueStruct<C>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return value for [`StructMap`][]'s `update` method.
|
/// Return value for [`StructMap`][]'s `update` method.
|
||||||
|
@ -79,7 +80,7 @@ where
|
||||||
pub fn insert<'db>(&'db self, runtime: &'db Runtime, value: ValueStruct<C>) -> &ValueStruct<C> {
|
pub fn insert<'db>(&'db self, runtime: &'db Runtime, value: ValueStruct<C>) -> &ValueStruct<C> {
|
||||||
assert_eq!(value.created_at, runtime.current_revision());
|
assert_eq!(value.created_at, runtime.current_revision());
|
||||||
|
|
||||||
let boxed_value = Box::new(value);
|
let boxed_value = Alloc::new(value);
|
||||||
let pointer = std::ptr::addr_of!(*boxed_value);
|
let pointer = std::ptr::addr_of!(*boxed_value);
|
||||||
|
|
||||||
let old_value = self.map.insert(boxed_value.id, boxed_value);
|
let old_value = self.map.insert(boxed_value.id, boxed_value);
|
||||||
|
@ -165,7 +166,7 @@ where
|
||||||
/// * If the value is not present in the map.
|
/// * If the value is not present in the map.
|
||||||
/// * If the value has not been updated in this revision.
|
/// * If the value has not been updated in this revision.
|
||||||
fn get_from_map<'db>(
|
fn get_from_map<'db>(
|
||||||
map: &'db FxDashMap<Id, Box<ValueStruct<C>>>,
|
map: &'db FxDashMap<Id, Alloc<ValueStruct<C>>>,
|
||||||
runtime: &'db Runtime,
|
runtime: &'db Runtime,
|
||||||
id: Id,
|
id: Id,
|
||||||
) -> &'db ValueStruct<C> {
|
) -> &'db ValueStruct<C> {
|
||||||
|
@ -230,7 +231,7 @@ pub(crate) struct UpdateRef<'db, C>
|
||||||
where
|
where
|
||||||
C: Configuration,
|
C: Configuration,
|
||||||
{
|
{
|
||||||
guard: RefMut<'db, Id, Box<ValueStruct<C>>, FxHasher>,
|
guard: RefMut<'db, Id, Alloc<ValueStruct<C>>, FxHasher>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'db, C> UpdateRef<'db, C>
|
impl<'db, C> UpdateRef<'db, C>
|
||||||
|
|
Loading…
Reference in a new issue