Crate tmfalloc

source ·
Expand description

§TMFAlloc: Transactional Mapped File Allocator for Rust

§Storage initialization

#[derive(Debug)]
struct S { /* some fields */ };
let h = unsafe {
    tmfalloc::Holder::<S>::open("test1", Some(ADDRESS), tmfalloc::MI,
                0xfedcab0987654321, |a| { S{ /* ... */ } }) }.unwrap();
// Detects memory areas overlapping:
match unsafe { tmfalloc::Holder::<S>::open("test1", None, tmfalloc::MI,
                0xfedcab0987654321, |a| { panic!("!") }) }.unwrap_err() {
    tmfalloc::Error::IoError(e) => {
        assert_eq!(e.kind(), std::io::ErrorKind::AlreadyExists) },
    _ => panic!("Wrong type of error")
}

§Commited data in storage becomes persistent

struct S(u64);
let mut h1 = unsafe {
    tmfalloc::Holder::<S>::open("test2", Some(ADDRESS), tmfalloc::MI,
                    0x1234567890abcdef, |a| { S(2718281828) }) }.unwrap();
let mut w = h1.write();
w.0 = 31415926;

w.commit();
assert_eq!(w.0, 31415926);
drop(w);
drop(h1);

let h2 = unsafe {
    tmfalloc::Holder::<S>::open("test2", None, tmfalloc::MI,
                    0x1234567890abcdef, |a| { panic!("!")} ) }.unwrap();
let r = h2.read();
assert_eq!(r.0, 31415926);
assert_eq!(h2.address(), ADDRESS);
assert_eq!(h2.size(), tmfalloc::MI);

§Data changes can be rolled back

§Explicitly

// --snip--
w.0 = 31415926;

w.rollback();
assert_eq!(w.0, 2718281828);
// --snip--
let r = h2.read();
assert_eq!(r.0, 2718281828);

§Implicitly

// --snip--
w.0 = 31415926;

assert_eq!(w.0, 31415926);
drop(w);
drop(h1);
// --snip--
let r = h2.read();
assert_eq!(r.0, 2718281828);

§Allocator makes standard collections persistent

#![feature(allocator_api, btreemap_alloc)]
type A = tmfalloc::Allocator;
type V = std::vec::Vec<u8, A>;
struct S {
    v: V,
    b: std::boxed::Box<usize, A>,
    m: std::collections::BTreeMap<V, usize, A>,
    s: std::collections::BTreeSet<usize, A>,
}
impl S { fn new(a: tmfalloc::Allocator) -> S {
    S {
        v: V::new_in(a.clone()),
        b: std::boxed::Box::<usize, A>::new_in(0, a.clone()),
        m: std::collections::BTreeMap::<V, usize, A>::new_in(a.clone()),
        s: std::collections::BTreeSet::<usize, A>::new_in(a),
    }
} }
let mut h1 = unsafe {
    tmfalloc::Holder::<S>::open("test5", Some(ADDRESS), tmfalloc::MI,
                    0xfedcba9876543210, S::new) }.unwrap();
let mut w = h1.write();
let a: A = w.allocator();
w.v.extend_from_slice(b"Once upon a time...");
w.b = Box::new_in(12345, a.clone());
w.m.insert("Fyodor Dostoevsky".as_bytes().to_vec_in(a.clone()), 59);
w.m.insert("Leo Tolstoy".as_bytes().to_vec_in(a.clone()), 82);
w.m.insert("Anton Chekhov".as_bytes().to_vec_in(a.clone()), 44);
w.m.insert("Vladimir Nabokov".as_bytes().to_vec_in(a), 78);
for i in [13, 11, 7, 5, 3, 2, 1] { w.s.insert(i); } ;
w.commit();
drop(w);
drop(h1);

let h2 = unsafe {
    tmfalloc::Holder::<S>::open("test5", None, tmfalloc::MI,
                    0xfedcba9876543210, |a| {panic!("!")}) }.unwrap();
let r = h2.read();
assert_eq!(r.v, b"Once upon a time...");
assert_eq!(*r.b, 12345);
assert_eq!(std::str::from_utf8(r.m.first_key_value().unwrap().0),
                                                    Ok("Anton Chekhov"));
assert_eq!(std::str::from_utf8(r.m.last_key_value().unwrap().0),
                                                    Ok("Vladimir Nabokov"));
let mut i = r.s.iter();
for j in [1usize, 2, 3, 5, 7, 11, 13] {
    assert_eq!(Some(&j), i.next());
}
assert_eq!(None, i.next());

§Data could be deallocated to reuse the memory

#![feature(allocator_api)]
type V = std::vec::Vec<u8, tmfalloc::Allocator>;
let mut h = unsafe {
    tmfalloc::Holder::<V>::open("test6", Some(ADDRESS), tmfalloc::MI,
                    0xfedcba9876543210, |a| { V::new_in(a) }) }.unwrap();
let mut w = h.write();
w.extend_from_slice(b"Once upon a time...");
let address1 = w.as_ptr();
w.commit();
drop(w);

let mut w = h.write();
w.clear();
w.shrink_to_fit();
w.extend_from_slice(b"Twice upon a time...");
let address2 = w.as_ptr();
w.commit();
assert_eq!(address1, address2);

§Storage can be expanded, but not trimmed

#![feature(allocator_api)]
type V = std::vec::Vec<u8, tmfalloc::Allocator>;
let mut h = unsafe {
    tmfalloc::Holder::<V>::open("test7", Some(ADDRESS), SIZE,
                    0xfedcba9876543210, |a| { V::new_in(a) }) }.unwrap();
let mut w = h.write();
w.extend_from_slice(&[b'.'; tmfalloc::MI - 2 * tmfalloc::KI]);
w.commit();
drop(w);
drop(h);
let mut h = unsafe {
    tmfalloc::Holder::<V>::open("test7", None, 2 * SIZE,
                    0xfedcba9876543210, |a| { panic!("!") }) }.unwrap();
let mut w = h.write();
w.extend_from_slice(&[b'.'; tmfalloc::MI]);
w.commit();
w.clear();
w.shrink_to_fit();
w.commit();
drop(w);
drop(h);
match unsafe {
        tmfalloc::Holder::<V>::open("test7", None, SIZE,
            0xfedcba9876543210, |a| { panic!("!") }) }.unwrap_err() {
    tmfalloc::Error::WrongSize => {},
    _ => panic!("Wrong type of error")
}

§Same storage can be used in several threads

#![feature(allocator_api)]
let mut h0 = unsafe {
    tmfalloc::Holder::<char>::open("test8", Some(ADDRESS), SIZE,
                    0xabcdef9876543210, |a| { '.' }) }.unwrap();
use std::{thread, time};
let mut h1 = h0.clone();
thread::spawn(move || {
    let mut w = h1.write();
    *w = '!';
    w.commit();
}).join().expect("The thread has panicked");
let mut h2 = h0.clone();
let mut w = h0.write();
assert_eq!(*w, '!');
*w = '.';
let t = thread::spawn(move || {
    let mut w = h2.write();
    *w = '?';
    w.commit();
});
thread::sleep(time::Duration::from_millis(1));
assert_eq!(*w, '.');
drop(w);
t.join().expect("The thread has panicked");
let mut h3 = h0.clone();
let mut r = h0.read();
thread::spawn(move || {
    let mut r = h3.read();
    assert_eq!(*r, '?');
}).join().expect("The thread has panicked");
assert_eq!(*r, '?');

Structs§

  • Allocator applicable for standard containers to make them persistent.
  • RAII fixture to provide Holder::read and Holder::write storage access methods on open files and memory mapping.
  • A smart pointer to the Root for storage exclusive write access.
  • A smart pointer to the Root for storage concurrent read access.

Enums§

  • All possible errors of Holder and arena initialization.

Constants§

Type Aliases§