Crate corundum[−][src]
Expand description
Corundum is a crate with an idiomatic persistent memory programming interface and leverages Rust’s type system to statically avoid most common persistent memory programming bugs. Corundum lets programmers develop persistent data structures using familiar Rust constructs and have confidence that they will be free of those bugs.
Statically Prevented Bugs
Common Bugs | Explanation | Approach |
---|---|---|
Inter-Pool Pointers | A pointer in another pool which is unavailable | Type checking pools in persistent pointers. |
P-to-V Pointers | A persistent pointer pointing at volatile memory | Persistent pointers accept only PSafe types and volatile pointers are !PSafe . Only, VCell allows single-execution P-to-V pointers. |
V-to-P Pointers | A volatile pointer keeping a zero-referenced object alive | Only VWeak allows V-to-P pointers which is a weak reference and does not keep data alive. |
Unlogged Updates | An unrecoverable update to persistent data | Modifications are enforced to be inside atomic transaction s. |
Data Race | Updating persistent data simultaneously in two threads | Mutable borrowing is limited to PMutex which uses a transaction-wide lock to provide both atomicity and isolation. |
Locked Mutex | A persistent mutex remains locked on powerfail | PMutex uses VCell which resets at restart. |
Memory Leaks* | An allocated memory becomes unreachable | Persistent objects, except the root object, cannot cross transaction boundaries, and memory allocation is available only inside a transaction. Therefore, the allocation can survive only if there is a reference from the root object (or a decedent of it) to the data. * Cyclic references are not prevented in this version, which lead to a memory leak. Please visit this link for the information on how to manually resolve that issue. |
For more technical details on the implementation, please refer to Corundum’s academic paper and/or watch the presentation 📺.
Persistent Objects
Persistent objects in Corundum are available through persistent pointers:
Pbox
: A pointer type for persistent memory allocation.Prc
: A single-threaded reference-counting persistent pointer.Parc
: A thread-safe reference-counting persistent pointer.
Programming Model
Persistent memory is available as a file on a DAX-enable file system such as
EXT4-DAX or NOVA. These files are called memory pools. Corundum allows
memory pool types rather than memory pool objects to enforce pointer safety
while compilation. The trait MemPool
provides the necessary
functionalities for the pool type.
The first step is to open a memory pool file in the program to be able to
work with persistent data. The default
module provides a default memory
pool type (BuddyAlloc
). To open a pool, we can invoke open<T>()
function which [initializes and] returns a reference to the root object of
type T
.
Data modification is provided and allowed only through transaction
al
interface. None of the persistent pointers is mutably dereferencing for
safety. Mutable objects are allowed via interior mutability of any of the
following memory cells:
PCell<T,P>
(orPCell<T>
): An unborrowable, mutable persistent memory location for a value of typeT
in poolP
.PRefCell<T,P>
(orPRefCell<T>
): A mutable persistent memory location with dynamically checked borrow rules for a value of typeT
in poolP
.PMutex<T,P>
(orPMutex<T>
): A mutual exclusion primitive useful for protecting shared persistent data of typeT
in poolP
.
The following example creates a pool file for a linked-list-based stack, and
obtains the root object of type Node
.
use corundum::default::*; // Aliasing the pool type for convenience type P = BuddyAlloc; #[derive(Root)] struct Node { value: i32, next: PRefCell<Option<Prc<Node>>> } fn main() { let head = P::open::<Node>("foo.pool", O_CF).unwrap(); P::transaction(|j| { let mut h = head.next.borrow_mut(j); *h = Some(Prc::new(Node { value: rand::random(), next: head.next.pclone(j) }, j)); }).expect("Unsuccessful transaction"); }
Re-exports
pub use stm::transaction;
Modules
Persistent Memory allocation APIs
A persistent pointer type for persistent memory allocation
Persistent shareable mutable containers
The PClone
trait for types that cannot be ‘implicitly copied’
The default allocator module
Low-level utils
Single-threaded reference-counting persistent pointers
Manually manage memory through raw pointers
A Result
type with string error messages
Software transactional memory APIs
Persistent unicode string slices
Useful synchronization primitives
A contiguous growable array type with heap-allocated contents, written Vec
Macros
This macro creates a new pool module and aliases for persistent types. It
generates type BuddyAlloc
which a persistent allocator type. It is
recommended to alias the BuddyAlloc
type for tidiness.
This macro can be used to access static data of an arbitrary allocator
Structs
A simple wrapper around a type to assert that it is safe to go in a transaction.
Traits
The implementing type can be asserted TxInSafe
albeit being !TxInSafe
by using AssertTxInSafe
.
It marks the implementing type to be free of pointers to the volatile heap, and persistence safe.
Safe to be sent to another thread
Creates a default value of the type
It is equal to UnwindSafe, but is used to ensure doubly that mutable references cannot go inside a transaction.
It marks the implementing type to be safe crossing transaction boundaries
Safe to be stored in volatile memory useful in VCell
type to prevent
storing persistent pointers in VCell