Crate tmfalloc

source ·
Expand description

TMFAlloc: Transactional Mapped File Allocator for Rust

Storage initialization

#[derive(Debug)]
struct S { /* some fields */ };
let h = tmfalloc::Holder::<S>::new("test1", None, tmfalloc::TI,
        0xfedcab0987654321, |a| { S{ /* ... */ } }).unwrap();
// Detects memory areas overlapping:
match tmfalloc::Holder::<S>::new("test1", None, tmfalloc::TI,
        0xfedcab0987654321, |a| { panic!("Impossible!") }).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 = tmfalloc::Holder::<S>::new("test2", Some(0x70ffefe00000),
    tmfalloc::TI, 0x1234567890abcdef, |a| { S(2718281828) }).unwrap();
let mut w = h1.write();
w.0 = 31415926;

w.commit();
assert_eq!(w.0, 31415926);
drop(w);
assert_eq!(h1.address(), 0x70ffefe00000);
assert_eq!(h1.size(), tmfalloc::TI);
drop(h1);

let h2 = tmfalloc::Holder::<S>::new("test2", None, tmfalloc::TI,
    0x1234567890abcdef, |a| {panic!("Should never happen")} ).unwrap();
let r = h2.read();
assert_eq!(r.0, 31415926);

Data changes can be rolled back

Explicitly

// -*- Skip -*-
w.0 = 31415926;

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

Implicitly

// -*- Skip -*-
w.0 = 31415926;

assert_eq!(w.0, 31415926);
drop(w);
drop(h1);
// -*- Skip -*-
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 = tmfalloc::Holder::<S>::new("test5", Some(0x70ffefe00000),
                         tmfalloc::TI, 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 = tmfalloc::Holder::<S>::new("test5", None, tmfalloc::TI,
         0xfedcba9876543210, |a| {panic!("Should never happen")} ).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 = tmfalloc::Holder::<V>::new("test6", Some(0x70ffefe00000),
        tmfalloc::TI, 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

#![feature(allocator_api)]
type V = std::vec::Vec<u8, tmfalloc::Allocator>;
let mut h = tmfalloc::Holder::<V>::new("test7", Some(0x70ffefe00000),
          tmfalloc::MI, 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 = tmfalloc::Holder::<V>::new("test7", Some(0x70ffefe00000), 2 *
            tmfalloc::MI, 0xfedcba9876543210, |a| { panic!("!")}).unwrap();
let mut w = h.write();
w.clear();
w.shrink_to_fit();
w.commit();

Re-exports

Modules

Structs

  • Holder: RAII fixture to initialize the storage files and mmapping
  • A smart pointer allowing storage exclusive write access
  • Reader: a smart pointer allowing storage concurrent read access

Enums

  • Error: all possible errors of Holder and arena initialization

Constants

Type Aliases