Struct corundum::stm::Chaperon [−][src]
pub struct Chaperon { /* fields omitted */ }
Expand description
A third-party observer for multi-pool transactions
It provides an atomic supper transaction (a session
) for manipulating
persistent data in multiple pools, atomically. The involved pools go to a
transient state when they call transaction inside a chaperoned session
.
The finalization functions (e.g. commit
or rollback
) are delayed
until the end of the session
. To keep track of pools’ states, it creates
a chaperon file with necessary information for recovering them, in case of a
crash.
Implementations
Loads a chaperon file
pub fn session<T, F: FnOnce() -> T>(filename: &str, body: F) -> Result<T> where
F: UnwindSafe,
T: UnwindSafe + TxOutSafe,
pub fn session<T, F: FnOnce() -> T>(filename: &str, body: F) -> Result<T> where
F: UnwindSafe,
T: UnwindSafe + TxOutSafe,
Starts a chaperoned session
It creates a chaperoned session in which multiple pools can start a
transaction
. The transactions won’t be finalized until the session
ends. A chaperon file keeps the necessary information for recovering the
involved pools. If the operation is successful, it returns a value of
type T
.
Safety
- In case of a crash, the involved pools are not individually recoverable on the absence of the chaperon file.
- Chaperoned sessions cannot be nested.
Examples
use corundum::alloc::heap::*; use corundum::stm::{Chaperon, Journal}; use corundum::cell::{PCell, RootObj}; use corundum::boxed::Pbox; corundum::pool!(pool1); corundum::pool!(pool2); type P1 = pool1::BuddyAlloc; type P2 = pool2::BuddyAlloc; struct Root<M: MemPool> { val: Pbox<PCell<i32, M>, M> } impl<M: MemPool> RootObj<M> for Root<M> { fn init(j: &Journal<M>) -> Self { Root { val: Pbox::new(PCell::new(0), j) } } } let root1 = P1::open::<Root<P1>>("pool1.pool", O_CF).unwrap(); let root2 = P2::open::<Root<P2>>("pool2.pool", O_CF).unwrap(); let _=Chaperon::session("chaperon.pool", || { let v = P2::transaction(|j| { let old = root2.val.get(); root2.val.set(old+1, j); // <-- should persist if both transactions commit old // <-- Send out p2's old data }).unwrap(); P1::transaction(|j| { let mut p1 = root1.val.get(); root1.val.set(p1+v, j); }).unwrap(); }).unwrap(); // <-- both transactions commit here let v1 = root1.val.get(); let v2 = root2.val.get(); println!("root1 = {}", v1); println!("root2 = {}", v2); assert_eq!(v1, calc(v2-1)); fn calc(n: i32) -> i32 { if n < 1 { 0 } else { n + calc(n-1) } }