Expand description
A single-thread reference-counting persistent pointer. ‘Prc’ stands for ‘Persistent Reference Counted’.
The main aspect of Prc<T>
is that its counters are transactional which
means that functions pclone
, downgrade
, and upgrade
require a
Journal
to operate. In other words, you need to wrap them in a
transaction
.
Prc
uses reference counting to manage memory. Although it provides a fast
solution for deallocation without scan, cyclic references yield a memory
leak. At this point, we have not provided a static solution to detect cyclic
references. However, following Rust’s partial solution for that, you may use
Weak
references for reference cycles.
References to data can be strong (using pclone
), weak (using downgrade
),
or volatile weak (using demote
). The first two generate NV-to-NV
pointers, while the last on is a V-to-NV pointer. Please see Weak
and
VWeak
for more details on their implementation and safety. Please also
visit the module-level documentation for the cyclic references
issue.
Examples
use corundum::prc::Prc;
use corundum::clone::PClone;
P::transaction(|j| {
let p = Prc::<i32,P>::new(1, j);
// Create a new persistent strong reference
let s = p.pclone(j);
assert_eq!(*p, *s);
assert_eq!(2, Prc::strong_count(&p));
assert_eq!(0, Prc::weak_count(&p));
// Create a new persistent weak reference
let w = Prc::downgrade(&p, j);
assert_eq!(2, Prc::strong_count(&p));
assert_eq!(1, Prc::weak_count(&p));
// Create a new volatile weak reference
let v = Prc::demote(&p);
assert_eq!(2, Prc::strong_count(&p));
assert_eq!(1, Prc::weak_count(&p));
// Upgrade the persistent weak ref to a strong ref
let ws = w.upgrade(j).unwrap();
assert_eq!(3, Prc::strong_count(&p));
assert_eq!(1, Prc::weak_count(&p));
// Upgrade the volatile weak ref to a strong ref
let vs = w.upgrade(j).unwrap();
assert_eq!(4, Prc::strong_count(&p));
assert_eq!(1, Prc::weak_count(&p));
}).unwrap();
Implementations
sourceimpl<T: PSafe, A: MemPool> Prc<T, A>
impl<T: PSafe, A: MemPool> Prc<T, A>
sourcepub fn new(value: T, journal: &Journal<A>) -> Prc<T, A>
pub fn new(value: T, journal: &Journal<A>) -> Prc<T, A>
Constructs a new Prc<T>
.
It also creates a DropOnFailure
log to make sure that if the program
crashes, the allocation drops of recovery.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let five = Prc::new(5, j);
}).unwrap();
sourcepub fn new_uninit(journal: &Journal<A>) -> Prc<MaybeUninit<T>, A>
pub fn new_uninit(journal: &Journal<A>) -> Prc<MaybeUninit<T>, A>
Constructs a new Prc
with uninitialized contents.
A DropOnFailure
log is taken for the allocation.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let mut five = Prc::<u32,Heap>::new_uninit(j);
let five = unsafe {
// Deferred initialization:
Prc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5)
}).unwrap();
sourcepub fn new_zeroed(journal: &Journal<A>) -> Prc<MaybeUninit<T>, A>
pub fn new_zeroed(journal: &Journal<A>) -> Prc<MaybeUninit<T>, A>
Constructs a new Prc
with uninitialized contents, with the memory
being filled with 0
bytes.
See MaybeUninit::zeroed
for examples of correct and incorrect usage of
this method.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let zero = Prc::<i32,P>::new_zeroed(j);
let zero = unsafe { zero.assume_init() };
assert_eq!(*zero, 0)
}).unwrap();
sourceimpl<T: PSafe, A: MemPool> Prc<MaybeUninit<T>, A>
impl<T: PSafe, A: MemPool> Prc<MaybeUninit<T>, A>
sourcepub unsafe fn assume_init(self) -> Prc<T, A>
pub unsafe fn assume_init(self) -> Prc<T, A>
Converts to Rc<T>
.
Safety
As with MaybeUninit::assume_init
,
it is up to the caller to guarantee that the inner value
really is in an initialized state.
Calling this when the content is not yet fully initialized
causes immediate undefined behavior.
Examples
use corundum::prc::Prc;
corundum::transaction(|j| {
let mut five = Prc::<u32,P>::new_uninit(j);
let five = unsafe {
// Deferred initialization:
Prc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5);
}).unwrap();
sourceimpl<T: PSafe, A: MemPool> Prc<MaybeUninit<T>, A>
impl<T: PSafe, A: MemPool> Prc<MaybeUninit<T>, A>
sourcepub fn get_mut(this: &mut Self) -> Option<&mut MaybeUninit<T>>
pub fn get_mut(this: &mut Self) -> Option<&mut MaybeUninit<T>>
Returns a mutable reference into the given Prc
, if there are
no other Prc
or Weak
pointers to the same allocation.
Returns None
otherwise, because it is not safe to mutate a shared
value. It only works for Prc<MaybeUninit<T>>
to be able to defer the
initialization.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let mut five = Prc::<u32,P>::new_uninit(j);
let five = unsafe {
// Deferred initialization:
Prc::get_mut(&mut five).unwrap().as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5)
}).unwrap();
sourcepub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut MaybeUninit<T>
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut MaybeUninit<T>
Returns a mutable reference into the given Prc
,
without any check.
It only works for Prc<MaybeUninit<T>>
to be able to defer the
initialization.
Safety
Any other Prc
or Weak
pointers to the same allocation must not be
dereferenced for the duration of the returned borrow.
This is trivially the case if no such pointers exist,
for example immediately after Rc::new
.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let mut five = Prc::<i32,P>::new_uninit(j);
let five = unsafe {
// Deferred initialization:
Prc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
five.assume_init()
};
assert_eq!(*five, 5);
}).unwrap();
sourceimpl<T: PSafe + ?Sized, A: MemPool> Prc<T, A>
impl<T: PSafe + ?Sized, A: MemPool> Prc<T, A>
sourcepub fn demote(this: &Self) -> VWeak<T, A>
pub fn demote(this: &Self) -> VWeak<T, A>
Creates a new Weak
volatile to this allocation.
The Weak
pointer can later be promote
d to a Prc
.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let five = Prc::new(5, j);
let weak_five = Prc::demote(&five);
assert_eq!(Prc::strong_count(&five), 1);
if let Some(f) = weak_five.promote(j) {
assert_eq!(*f, 5);
assert_eq!(Prc::strong_count(&five), 2);
}
assert_eq!(Prc::strong_count(&five), 1);
}).unwrap()
sourcepub unsafe fn unsafe_demote(&self) -> VWeak<T, A>
pub unsafe fn unsafe_demote(&self) -> VWeak<T, A>
Demote without dynamically checking transaction boundaries
sourcepub fn weak_count(this: &Self) -> usize
pub fn weak_count(this: &Self) -> usize
Gets the number of Weak
pointers to this allocation.
Examples
use corundum::prc::Prc;
P::transaction(|j| {
let five = Prc::new(5, j);
let _weak_five = Prc::downgrade(&five, j);
assert_eq!(1, Prc::weak_count(&five));
}).unwrap()
sourcepub fn strong_count(this: &Self) -> usize
pub fn strong_count(this: &Self) -> usize
Gets the number of Weak
pointers to this allocation.
Examples
use corundum::prc::Prc;
use corundum::clone::PClone;
P::transaction(|j| {
let five = Prc::new(5, j);
let _also_five = Prc::pclone(&five, j);
assert_eq!(2, Prc::strong_count(&five));
}).unwrap();
sourcepub fn ptr_eq(this: &Self, other: &Self) -> bool
pub fn ptr_eq(this: &Self, other: &Self) -> bool
Returns true
if the two Prc
s point to the same allocation
(in a vein similar to ptr::eq
).
Examples
use corundum::prc::Prc;
use corundum::clone::PClone;
P::transaction(|j| {
let five = Prc::new(5, j);
let same_five = Prc::pclone(&five, j);
let other_five = Prc::new(5, j);
assert!(Prc::ptr_eq(&five, &same_five));
assert!(!Prc::ptr_eq(&five, &other_five));
}).unwrap();
sourceimpl<T: PSafe, A: MemPool> Prc<T, A>
impl<T: PSafe, A: MemPool> Prc<T, A>
sourcepub fn initialize(rc: &Option<Prc<T, A>>, value: T) -> Result<()>
pub fn initialize(rc: &Option<Prc<T, A>>, value: T) -> Result<()>
Initializes boxed data with value
in-place if it is None
This function should not be called from a transaction as it updates data without taking high-level logs. If transaction is unsuccessful, there is no way to recover data. However, it is safe to use it outside a transaction because it uses low-level logs to provide safety for a single update without drop. A dynamic check at the beginning makes sure of that.
Examples
use corundum::default::*;
type P = Allocator;
let root = P::open::<Option<Prc<i32>>>("foo.pool", O_CF).unwrap();
Prc::initialize(&*root, 25);
let value = **root.as_ref().unwrap();
assert_eq!(value, 25);
Trait Implementations
sourceimpl<T: PSafe + ?Sized, A: MemPool> Drop for Prc<T, A>
impl<T: PSafe + ?Sized, A: MemPool> Drop for Prc<T, A>
sourcefn drop(&mut self)
fn drop(&mut self)
Drops the Prc
safely
This will decrement the strong reference count. If the strong reference
count reaches zero then the only other references (if any) are
Weak
, so we drop
the inner value on commit using a DropOnCommit
log.
Examples
use corundum::prc::Prc;
use corundum::clone::PClone;
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
println!("dropped!");
}
}
P::transaction(|j| {
let foo = Prc::new(Foo, j);
let foo2 = Prc::pclone(&foo, j);
drop(foo); // Doesn't print anything
drop(foo2); // Prints "dropped!"
}).unwrap();
sourceimpl<T: Ord + PSafe + ?Sized, A: MemPool> Ord for Prc<T, A>
impl<T: Ord + PSafe + ?Sized, A: MemPool> Ord for Prc<T, A>
sourceimpl<T: PSafe + ?Sized, A: MemPool> PClone<A> for Prc<T, A>
impl<T: PSafe + ?Sized, A: MemPool> PClone<A> for Prc<T, A>
sourcefn pclone(&self, journal: &Journal<A>) -> Prc<T, A>
fn pclone(&self, journal: &Journal<A>) -> Prc<T, A>
Creates a new strong reference to the object
It increments the strong reference counter in a failure-atomic manner. When a transaction is aborted or power fails, every strong references to the object should be gone, and the counters should rollback to the consistent state before the transaction.
Examples
let root = P::open::<Prc<i32>>("foo.pool", O_CF).unwrap();
let _ = P::transaction(|j| {
let _n1 = root.pclone(j);
let _n2 = root.pclone(j);
let _n3 = root.pclone(j);
assert_eq!(4, Prc::strong_count(&root));
panic!("abort")
});
assert_eq!(1, Prc::strong_count(&root));
sourcefn pclone_from(&mut self, source: &Self, journal: &Journal<A>)
fn pclone_from(&mut self, source: &Self, journal: &Journal<A>)
Performs copy-assignment from source
. Read more
sourceimpl<T: PartialOrd + PSafe + ?Sized, A: MemPool> PartialOrd<Prc<T, A>> for Prc<T, A>
impl<T: PartialOrd + PSafe + ?Sized, A: MemPool> PartialOrd<Prc<T, A>> for Prc<T, A>
sourcefn partial_cmp(&self, other: &Prc<T, A>) -> Option<Ordering>
fn partial_cmp(&self, other: &Prc<T, A>) -> Option<Ordering>
This method returns an ordering between self
and other
values if one exists. Read more
sourcefn lt(&self, other: &Prc<T, A>) -> bool
fn lt(&self, other: &Prc<T, A>) -> bool
This method tests less than (for self
and other
) and is used by the <
operator. Read more
sourcefn le(&self, other: &Prc<T, A>) -> bool
fn le(&self, other: &Prc<T, A>) -> bool
This method tests less than or equal to (for self
and other
) and is used by the <=
operator. Read more
sourceimpl<T: PSafe, A: MemPool> PmemUsage for Prc<T, A>
impl<T: PSafe, A: MemPool> PmemUsage for Prc<T, A>
sourcedefault fn size_of() -> usize
default fn size_of() -> usize
Size of the object on Persistent Memory Assuming that self is not on PM, or considered else were, the size of allocated persistent memory is the sum of all persistent objects pointed by this object. Read more
sourcefn size_of_pmem() -> usize
fn size_of_pmem() -> usize
Size of the object on Persistent Memory including Self
Assuming that self is also on PM (e.g. the root object), the size of allocated persistent memory
includes the size of all objects pointed by this object and the size Self
. Read more
sourceimpl<T: PSafe + PmemUsage + ?Sized, A: MemPool> PmemUsage for Prc<T, A>
impl<T: PSafe + PmemUsage + ?Sized, A: MemPool> PmemUsage for Prc<T, A>
sourcefn size_of() -> usize
fn size_of() -> usize
Size of the object on Persistent Memory Assuming that self is not on PM, or considered else were, the size of allocated persistent memory is the sum of all persistent objects pointed by this object. Read more
sourcefn size_of_pmem() -> usize
fn size_of_pmem() -> usize
Size of the object on Persistent Memory including Self
Assuming that self is also on PM (e.g. the root object), the size of allocated persistent memory
includes the size of all objects pointed by this object and the size Self
. Read more
impl<T: Eq + PSafe + ?Sized, A: MemPool> Eq for Prc<T, A>
impl<T: ?Sized, A: MemPool> !PSend for Prc<T, A>
impl<T: ?Sized, A: MemPool> !Send for Prc<T, A>
impl<T: ?Sized, A: MemPool> !Sync for Prc<T, A>
impl<T: ?Sized, A: MemPool> !TxOutSafe for Prc<T, A>
impl<T: PSafe + ?Sized, A: MemPool> Unpin for Prc<T, A>
impl<T: ?Sized, A: MemPool> !VSafe for Prc<T, A>
Auto Trait Implementations
impl<T: ?Sized, A> LooseTxInUnsafe for Prc<T, A> where
T: LooseTxInUnsafe,
impl<T: ?Sized, A> PSafe for Prc<T, A>
impl<T: ?Sized, A> RefUnwindSafe for Prc<T, A> where
T: RefUnwindSafe,
impl<T: ?Sized, A> TxInSafe for Prc<T, A> where
T: TxInSafe,
impl<T: ?Sized, A> UnwindSafe for Prc<T, A> where
T: UnwindSafe,
Blanket Implementations
sourceimpl<T> BorrowMut<T> for T where
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
const: unstable · sourcefn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more