Struct corundum::sync::Parc[][src]

pub struct Parc<T: PSafe + ?Sized, A: MemPool> { /* fields omitted */ }

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.

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 upgraded 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 Parcs 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]

type Target = T

The resulting type after dereferencing.

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]

impl<T: Ord + PSafe + ?Sized, A: MemPool> Ord for Parc<T, A>[src]

impl<T: PSafe + ?Sized, A: MemPool> PClone<A> for Parc<T, A>[src]

impl<T: PartialEq + PSafe + ?Sized, A: MemPool> PartialEq<Parc<T, A>> for Parc<T, A>[src]

impl<T: PartialOrd + PSafe + ?Sized, A: MemPool> PartialOrd<Parc<T, A>> for Parc<T, A>[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

impl<T: ?Sized, A> PSafe for Parc<T, A>

impl<T: ?Sized, A> PSend for Parc<T, A> where
    A: PSend,
    T: PSend

impl<T, A> !Sync for Parc<T, A>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T, A> ToPString<A> for T where
    T: Display + ?Sized,
    A: MemPool
[src]

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,