Struct corundum::sync::Parc [−][src]
A thread-safe reference-counting persistent pointer. ‘Parc’ stands for ‘Persistent Atomically Reference Counted’.
The main aspect of Parc<T>
is that its atomic counters are also
transactional to provide failure atomicity which means that functions
pclone
, downgrade
, and upgrade
require a Journal
to operate.
In other words, you need to wrap them in a transaction
. The counters are
atomic, so it is safe to share it in multiple threads.
Since Parc
uses reference counting for resource management, it inherits
the cyclic references problem. Please visit this
for the information on
how Weak
helps to resolve that issue.
Unlike Arc
, Parc
does not implement Send
to prevent memory leak.
The reason is that if a Parc
is created in a transaction without being
reachable from the root object, and moves to a thread, due to being RAII,
its drop function gets called in the other thread outside the original
transaction. Therefore, it destroys allocation consistency and leaves the
Parc
unreachable in the memory if a crash happens between the original
transaction is done and the drop function is called.
To allow sharing, Parc
provides a safe mechanism to cross the thread
boundaries. When you need to share it, you can obtain a VWeak
object by calling demote()
function. The VWeak
object is both
Sync
and Send
and acts like a volatile reference. Calling
VWeak
::
promote()
gives access to data by creating a new reference
of type Parc
inside the other thread, if the referent is still available.
Calling demote()
is dynamically prohibited to be inside a transaction.
Therefore, the Parc
should be already reachable from the root object and
packed outside a transaction.
Examples
use corundum::default::*; use std::thread; type P = BuddyAlloc; let p = P::open::<Parc<i32>>("foo.pool", O_CF).unwrap(); let v = p.demote(); let mut threads = vec![]; for i in 0..10 { let p = v.clone(); threads.push(thread::spawn(move || { transaction(|j| { if let Some(p) = p.promote(j) { println!("access {} from thread {}", *p, i); } }).unwrap(); })); } for t in threads { t.join().unwrap(); }
Mutability
Parc
doesn’t provide mutable reference to the inner value. To allow
interior mutability, you may use Parc<
PMutex
<T,P>,P>
(or in short,
Parc<
PMutex
<T>>
using aliased types).
use corundum::default::*; use std::thread; type P = BuddyAlloc; let p = P::open::<Parc<PMutex<i32>>>("foo.pool", O_CF).unwrap(); let v = p.demote(); let mut threads = vec![]; for i in 0..10 { let p = v.clone(); threads.push(thread::spawn(move || { transaction(|j| { if let Some(p) = p.promote(j) { let mut p = p.lock(j); *p += 1; println!("thread {} makes it {}", i, *p); } }).unwrap(); })); } for t in threads { t.join().unwrap(); } let res = transaction(|j| { *p.lock(j) }).unwrap(); assert_eq!(res, 10);
Implementations
impl<T: PSafe, A: MemPool> Parc<T, A>
[src]
pub fn new(value: T, journal: &Journal<A>) -> Parc<T, A>
[src]
Constructs a new Parc<T>
.
Examples
use corundum::sync::Parc; Heap::transaction(|j| { let five = Parc::new(5, j); }).unwrap();
pub fn new_uninit(journal: &Journal<A>) -> Parc<MaybeUninit<T>, A>
[src]
Constructs a new Parc
with uninitialized contents.
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; corundum::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5) }).unwrap();
pub fn new_zeroed(journal: &Journal<A>) -> Parc<MaybeUninit<T>, A>
[src]
Constructs a new Parc
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::alloc::heap::*; use corundum::sync::Parc; Heap::transaction(|j| { let zero = Parc::<u32,Heap>::new_zeroed(j); let zero = unsafe { zero.assume_init() }; assert_eq!(*zero, 0) }).unwrap();
impl<T: PSafe, A: MemPool> Parc<MaybeUninit<T>, A>
[src]
pub unsafe fn assume_init(self) -> Parc<T, A>
[src]
Converts to Parc<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::alloc::heap::*; use corundum::sync::Parc; corundum::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5); }).unwrap();
impl<T: PSafe, A: MemPool> Parc<MaybeUninit<T>, A>
[src]
pub fn get_mut(this: &mut Self) -> Option<&mut MaybeUninit<T>>
[src]
Returns a mutable reference into the given Parc
, if there are
no other Parc
or Weak
pointers to the same allocation.
Returns None
otherwise, because it is not safe to mutate a shared
value. It only works for Parc<MaybeUninit<T>>
to be able to defer the
initialization.
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; corundum::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut(&mut five).unwrap().as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5) }).unwrap();
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut MaybeUninit<T>
[src]
Returns a mutable reference into the given Parc
, without any check.
It only works for Parc<MaybeUninit<T>>
to be able to defer the
initialization.
Safety
Any other Parc
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 Parc::new
.
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; corundum::transaction(|j| { let mut five = Parc::<u32,Heap>::new_uninit(j); let five = unsafe { // Deferred initialization: Parc::get_mut_unchecked(&mut five).as_mut_ptr().write(5); five.assume_init() }; assert_eq!(*five, 5); }).unwrap();
impl<T: PSafe + ?Sized, A: MemPool> Parc<T, A>
[src]
pub fn downgrade(this: &Self, j: &Journal<A>) -> Weak<T, A>
[src]
Creates a new Weak
pointer to this allocation.
The Weak
pointer can be upgrade
d later in a transaction.
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; Heap::transaction(|j| { let five = Parc::new(5, j); let _weak_five = Parc::downgrade(&five, j); }).unwrap()
pub fn demote(&self) -> VWeak<T, A>
[src]
Creates a new sharable VWeak
pointer to this
allocation.
Errors
This function requires the allocation to be reachable from the persistent root. Therefore, it panics if it gets called inside a transaction.
Examples
use corundum::default::*; type P = BuddyAlloc; let obj = P::open::<Parc<i32>>("foo.pool", O_CF).unwrap(); let v = obj.demote(); assert_eq!(Parc::strong_count(&obj), 1); P::transaction(|j| { if let Some(obj) = v.promote(j) { assert_eq!(Parc::strong_count(&obj), 2); } }).unwrap(); assert_eq!(Parc::strong_count(&obj), 1);
pub unsafe fn unsafe_demote(&self) -> VWeak<T, A>
[src]
Demote without dynamically checking transaction boundaries
pub fn weak_count(this: &Self) -> usize
[src]
Gets the number of Weak
pointers to this allocation.
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; Heap::transaction(|j| { let five = Parc::new(5, j); let _weak_five = Parc::downgrade(&five, j); assert_eq!(1, Parc::weak_count(&five)); }).unwrap()
pub fn strong_count(this: &Self) -> usize
[src]
Gets the number of Strong
pointers to this allocation.
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; use corundum::clone::PClone; Heap::transaction(|j| { let five = Parc::new(5, j); let _also_five = Parc::pclone(&five, j); assert_eq!(2, Parc::strong_count(&five)); }).unwrap();
pub fn ptr_eq(this: &Self, other: &Self) -> bool
[src]
Returns true
if the two Parc
s point to the same allocation
(in a vein similar to std::ptr::eq
).
Examples
use corundum::alloc::heap::*; use corundum::sync::Parc; use corundum::clone::PClone; Heap::transaction(|j| { let five = Parc::new(5, j); let same_five = Parc::pclone(&five, j); let other_five = Parc::new(5, j); assert!(Parc::ptr_eq(&five, &same_five)); assert!(!Parc::ptr_eq(&five, &other_five)); }).unwrap();
impl<T: PSafe, A: MemPool> Parc<T, A>
[src]
pub fn initialize(arc: &Option<Parc<T, A>>, value: T) -> Result<()>
[src]
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 = BuddyAlloc; let root = P::open::<Option<Parc<i32>>>("foo.pool", O_CF).unwrap(); Parc::initialize(&*root, 25); let value = **root.as_ref().unwrap(); assert_eq!(value, 25);
Trait Implementations
impl<T: PSafe + ?Sized, A: MemPool> AsRef<T> for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Borrow<T> for Parc<T, A>
[src]
impl<T: Debug + PSafe, A: MemPool> Debug for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Deref for Parc<T, A>
[src]
impl<T: Display + PSafe, A: MemPool> Display for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Drop for Parc<T, A>
[src]
fn drop(&mut self)
[src]
Drops the Parc
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::alloc::heap::*; use corundum::sync::Parc; use corundum::clone::PClone; struct Foo; impl Drop for Foo { fn drop(&mut self) { println!("dropped!"); } } Heap::transaction(|j| { let foo = Parc::new(Foo, j); let foo2 = Parc::pclone(&foo, j); drop(foo); // Doesn't print anything drop(foo2); // Prints "dropped!" }).unwrap();
impl<T: Eq + PSafe + ?Sized, A: MemPool> Eq for Parc<T, A>
[src]
impl<T: Hash + PSafe, A: MemPool> Hash for Parc<T, A>
[src]
fn hash<H: Hasher>(&self, state: &mut H)
[src]
pub fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl<T: Ord + PSafe + ?Sized, A: MemPool> Ord for Parc<T, A>
[src]
fn cmp(&self, other: &Parc<T, A>) -> Ordering
[src]
#[must_use]pub fn max(self, other: Self) -> Self
1.21.0[src]
#[must_use]pub fn min(self, other: Self) -> Self
1.21.0[src]
#[must_use]pub fn clamp(self, min: Self, max: Self) -> Self
1.50.0[src]
impl<T: PSafe + ?Sized, A: MemPool> PClone<A> for Parc<T, A>
[src]
fn pclone(&self, j: &Journal<A>) -> Parc<T, A>
[src]
fn pclone_from(&mut self, source: &Self, journal: &Journal<A>)
[src]
impl<T: PartialEq + PSafe + ?Sized, A: MemPool> PartialEq<Parc<T, A>> for Parc<T, A>
[src]
fn eq(&self, other: &Parc<T, A>) -> bool
[src]
#[must_use]pub fn ne(&self, other: &Rhs) -> bool
1.0.0[src]
impl<T: PartialOrd + PSafe + ?Sized, A: MemPool> PartialOrd<Parc<T, A>> for Parc<T, A>
[src]
fn partial_cmp(&self, other: &Parc<T, A>) -> Option<Ordering>
[src]
fn lt(&self, other: &Parc<T, A>) -> bool
[src]
fn le(&self, other: &Parc<T, A>) -> bool
[src]
fn gt(&self, other: &Parc<T, A>) -> bool
[src]
fn ge(&self, other: &Parc<T, A>) -> bool
[src]
impl<T: PSafe, A: MemPool> PmemUsage for Parc<T, A>
[src]
impl<T: PSafe + PmemUsage + ?Sized, A: MemPool> PmemUsage for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Pointer for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> RefUnwindSafe for Parc<T, A>
[src]
impl<T: RootObj<A> + PSafe, A: MemPool> RootObj<A> for Parc<T, A>
[src]
impl<T: Default + PSafe + ?Sized, A: MemPool> RootObj<A> for Parc<T, A>
[src]
impl<T: ?Sized, A: MemPool> !Send for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> TxInSafe for Parc<T, A>
[src]
impl<T: ?Sized, A: MemPool> !TxOutSafe for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> Unpin for Parc<T, A>
[src]
impl<T: PSafe + ?Sized, A: MemPool> UnwindSafe for Parc<T, A>
[src]
impl<T: ?Sized, A: MemPool> !VSafe for Parc<T, A>
[src]
Auto Trait Implementations
impl<T: ?Sized, A> LooseTxInUnsafe for Parc<T, A> where
A: LooseTxInUnsafe,
T: LooseTxInUnsafe,
A: LooseTxInUnsafe,
T: LooseTxInUnsafe,
impl<T: ?Sized, A> PSafe for Parc<T, A>
impl<T: ?Sized, A> PSend for Parc<T, A> where
A: PSend,
T: PSend,
A: PSend,
T: PSend,
impl<T, A> !Sync for Parc<T, A>
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T, A> ToPString<A> for T where
T: Display + ?Sized,
A: MemPool,
[src]
T: Display + ?Sized,
A: MemPool,
pub default fn to_pstring(&Self, &Journal<A>) -> String<A>
[src]
impl<T> ToString for T where
T: Display + ?Sized,
[src]
T: Display + ?Sized,
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
pub fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<V, T> VZip<V> for T where
V: MultiLane<T>,
V: MultiLane<T>,