use Alloc not Box

to avoid uniqueness guarantees
This commit is contained in:
Niko Matsakis 2024-05-27 07:39:46 -04:00
parent a7b2805b06
commit 81942f37e5
4 changed files with 53 additions and 8 deletions

View 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 {}

View file

@ -3,6 +3,7 @@ use std::fmt;
use std::hash::Hash;
use std::marker::PhantomData;
use crate::alloc::Alloc;
use crate::durability::Durability;
use crate::id::{AsId, LookupId};
use crate::ingredient::{fmt_index, IngredientRequiresReset};
@ -39,7 +40,7 @@ pub struct InternedIngredient<C: Configuration> {
/// Maps from an interned id to its data.
///
/// 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: AtomicCell<u32>,
@ -121,7 +122,7 @@ where
let value = self
.value_map
.entry(next_id)
.or_insert(Box::new(ValueStruct {
.or_insert(Alloc::new(ValueStruct {
id: next_id,
fields: internal_data,
}));

View file

@ -1,4 +1,5 @@
pub mod accumulator;
mod alloc;
pub mod cancelled;
pub mod cycle;
pub mod database;

View file

@ -7,6 +7,7 @@ use crossbeam::queue::SegQueue;
use dashmap::mapref::one::RefMut;
use crate::{
alloc::Alloc,
hash::{FxDashMap, FxHasher},
plumbing::transmute_lifetime,
Id, Runtime,
@ -18,21 +19,21 @@ pub(crate) struct StructMap<C>
where
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
/// 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
/// `&db` reference. This queue itself is not freed until we have an `&mut db` reference,
/// 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>
where
C: Configuration,
{
map: Arc<FxDashMap<Id, Box<ValueStruct<C>>>>,
map: Arc<FxDashMap<Id, Alloc<ValueStruct<C>>>>,
}
/// 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> {
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 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 has not been updated in this revision.
fn get_from_map<'db>(
map: &'db FxDashMap<Id, Box<ValueStruct<C>>>,
map: &'db FxDashMap<Id, Alloc<ValueStruct<C>>>,
runtime: &'db Runtime,
id: Id,
) -> &'db ValueStruct<C> {
@ -230,7 +231,7 @@ pub(crate) struct UpdateRef<'db, C>
where
C: Configuration,
{
guard: RefMut<'db, Id, Box<ValueStruct<C>>, FxHasher>,
guard: RefMut<'db, Id, Alloc<ValueStruct<C>>, FxHasher>,
}
impl<'db, C> UpdateRef<'db, C>