pub struct Prc<T: PSafe + ?Sized, A: MemPool> { /* private fields */ }
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

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();

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();

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();

Owns contents of p without cloning, leaving p untouched

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();

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();

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();

Creates a new Weak persistent pointer to this allocation.

The Weak pointer can later be upgraded to a Prc.

Examples
use corundum::prc::Prc;

P::transaction(|j| {
    let five = Prc::new(5, j);
    let _weak_five = Prc::downgrade(&five, j);
}).unwrap()

Creates a new Weak volatile to this allocation.

The Weak pointer can later be promoted 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()

Demote without dynamically checking transaction boundaries

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()

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();

Returns true if the two Prcs 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();

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

Converts this type into a shared reference of the (usually inferred) input type.

Immutably borrows from an owned value. Read more

Formats the value using the given formatter. Read more

The resulting type after dereferencing.

Dereferences the value.

Formats the value using the given formatter. Read more

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();

Feeds this value into the given Hasher. Read more

Feeds a slice of this type into the given Hasher. Read more

This method returns an Ordering between self and other. Read more

Compares and returns the maximum of two values. Read more

Compares and returns the minimum of two values. Read more

Restrict a value to a certain interval. Read more

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));

Performs copy-assignment from source. Read more

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

This method returns an ordering between self and other values if one exists. Read more

This method tests less than (for self and other) and is used by the < operator. Read more

This method tests less than or equal to (for self and other) and is used by the <= operator. Read more

This method tests greater than (for self and other) and is used by the > operator. Read more

This method tests greater than or equal to (for self and other) and is used by the >= operator. Read more

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

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

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

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

Formats the value using the given formatter.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Converts the given value to a String. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.