use plugmem_arena::{
Arena, ArenaCfg, BlobHeap, BlobHeapCfg, ChunkPool, ChunkPoolCfg, Interner, ListHandle,
ShardMode, Slot, key,
};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Rec {
k: u64,
v: u64,
}
impl Slot for Rec {
const SIZE: usize = 16;
const KEY_LEN: usize = 8;
fn write(&self, out: &mut [u8]) {
key::write_u64(out, self.k);
key::write_u64(&mut out[8..], self.v);
}
fn read(bytes: &[u8]) -> Self {
Self {
k: key::read_u64(bytes),
v: key::read_u64(&bytes[8..]),
}
}
}
#[test]
fn arena_borrowed_load_equals_owned() {
let mut a = Arena::<Rec>::new(ArenaCfg::new(4, ShardMode::Ordered)).unwrap();
for i in 0..2000u64 {
a.insert(&Rec { k: i * 3, v: i }).unwrap();
}
for i in 0..600u64 {
let mut k = [0u8; 8];
key::write_u64(&mut k, i * 3);
assert!(a.remove(&k));
}
let (mut meta, mut pool) = (Vec::new(), Vec::new());
a.dump_meta(&mut meta);
a.dump_pool(&mut pool);
let owned = Arena::<Rec>::load(*a.cfg(), &meta, &pool).unwrap();
let borrowed = Arena::<Rec>::load_borrowed(*a.cfg(), &meta, &pool).unwrap();
let want: Vec<_> = a.iter().collect();
assert_eq!(owned.iter().collect::<Vec<_>>(), want);
assert_eq!(borrowed.iter().collect::<Vec<_>>(), want);
let redump = |x: &Arena<'_, Rec>| {
let (mut m, mut p) = (Vec::new(), Vec::new());
x.dump_meta(&mut m);
x.dump_pool(&mut p);
(m, p)
};
assert_eq!(redump(&owned), (meta.clone(), pool.clone()));
assert_eq!(redump(&borrowed), (meta, pool));
}
#[test]
fn arena_borrowed_mutation_copies_up_and_spares_the_source() {
let mut a = Arena::<Rec>::new(ArenaCfg::new(2, ShardMode::Ordered)).unwrap();
for i in 0..50u64 {
a.insert(&Rec { k: i, v: i }).unwrap();
}
let (mut meta, mut pool) = (Vec::new(), Vec::new());
a.dump_meta(&mut meta);
a.dump_pool(&mut pool);
let snapshot = pool.clone();
let mut borrowed =
Arena::<Rec>::load_borrowed(ArenaCfg::new(2, ShardMode::Ordered), &meta, &pool).unwrap();
borrowed.insert(&Rec { k: 999, v: 999 }).unwrap();
assert_eq!(pool, snapshot, "the borrowed source pool was not mutated");
assert_eq!(
borrowed.get(&{
let mut k = [0u8; 8];
key::write_u64(&mut k, 999);
k
}),
Some(Rec { k: 999, v: 999 })
);
}
#[test]
fn blob_heap_borrowed_load_equals_owned() {
let mut h = BlobHeap::new(BlobHeapCfg::new());
let ids: Vec<_> = ["alpha", "", "a longer blob of bytes", "z"]
.iter()
.map(|s| h.push(s.as_bytes()).unwrap())
.collect();
let (mut index, mut pool) = (Vec::new(), Vec::new());
h.dump_index(&mut index);
h.dump_pool(&mut pool);
let owned = BlobHeap::load(BlobHeapCfg::new(), &index, &pool).unwrap();
let borrowed = BlobHeap::load_borrowed(BlobHeapCfg::new(), &index, &pool).unwrap();
for (i, &id) in ids.iter().enumerate() {
let want = h.get(id);
assert_eq!(owned.get(id), want, "owned blob {i}");
assert_eq!(borrowed.get(id), want, "borrowed blob {i}");
}
assert_eq!(borrowed.len(), h.len());
}
#[test]
fn chunk_pool_borrowed_load_equals_owned() {
let mut c = ChunkPool::new(ChunkPoolCfg::new());
let mut evens = ListHandle::EMPTY;
let mut odds = ListHandle::EMPTY;
for n in 0..80u32 {
let list = if n % 2 == 0 { &mut evens } else { &mut odds };
c.push(list, &n.to_be_bytes()).unwrap();
}
let (mut meta, mut pool) = (Vec::new(), Vec::new());
c.dump_meta(&mut meta);
c.dump_pool(&mut pool);
let owned = ChunkPool::load(ChunkPoolCfg::new(), &meta, &pool).unwrap();
let borrowed = ChunkPool::load_borrowed(ChunkPoolCfg::new(), &meta, &pool).unwrap();
let collect =
|p: &ChunkPool<'_>, h: &ListHandle| -> Vec<u8> { p.iter(h).flatten().copied().collect() };
assert_eq!(collect(&owned, &evens), collect(&c, &evens));
assert_eq!(collect(&borrowed, &evens), collect(&c, &evens));
assert_eq!(collect(&borrowed, &odds), collect(&c, &odds));
assert_eq!(borrowed.chunks(), c.chunks());
}
#[test]
fn interner_borrowed_load_equals_owned() {
let mut terms = Interner::new(BlobHeapCfg::new());
let words = ["tokio", "async", "runtime", "tokio", "wasm"];
let ids: Vec<_> = words.iter().map(|w| terms.intern(w).unwrap()).collect();
let (mut index, mut pool, mut table) = (Vec::new(), Vec::new(), Vec::new());
terms.dump_index(&mut index);
terms.dump_pool(&mut pool);
terms.dump_table(&mut table);
let owned = Interner::load(BlobHeapCfg::new(), &index, &pool, &table).unwrap();
let borrowed = Interner::load_borrowed(BlobHeapCfg::new(), &index, &pool, &table).unwrap();
for (w, &id) in words.iter().zip(&ids) {
assert_eq!(owned.lookup(w), Some(id));
assert_eq!(borrowed.lookup(w), Some(id));
assert_eq!(borrowed.resolve(id), *w);
}
assert_eq!(borrowed.len(), terms.len());
}