diff --git a/src/allocator.rs b/src/allocator.rs index a55d37e..f638248 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -18,6 +18,9 @@ impl SlabKind { } else if size < size_of::() as u32 { Self::RelativeFreeList } else if (size as u64) <= PAGE_SIZE { + // TODO + // slabs of really big object are very inefficient. + // find a better way/ allocate more pages at once e.g. at least 10 elements? Self::AbsoluteFreeList } else { panic!("invalid size") @@ -469,6 +472,10 @@ impl SlabPointer { unsafe { db.modify(self.0) } } + pub fn size(&self, db: &Db) -> u32 { + self.read(db).size.get() + } + pub fn alloc(&self, db: &mut Db) -> FileRange { let Slab { mut head, size } = self.read(db); diff --git a/src/lib.rs b/src/lib.rs index 9502e40..6a93665 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,10 @@ use std::{ - borrow::BorrowMut, collections::HashMap, fmt::Debug, fs::File, mem::size_of, ops::Range, + borrow::BorrowMut, + collections::{BTreeMap, HashMap}, + fmt::Debug, + fs::File, + mem::size_of, + ops::Range, sync::Arc, }; @@ -153,6 +158,7 @@ pub struct Reader { pub struct Db { file: File, map: MmapMut, + slabs: BTreeMap, state: Arc>, } @@ -241,9 +247,18 @@ impl Db { unsafe { self.modify_range_unchecked(Self::header_ptr().range(size_of::
() as u64)) } } - pub fn add_slab(&mut self, size: u32) -> SlabPointer { + fn add_slab(&mut self, size: u32) -> SlabPointer { let allocator_state = self.header().allocator_state; - allocator_state.slabs.add_slab(self, size) + let slab = allocator_state.slabs.add_slab(self, size); + assert!(self.slabs.insert(size, slab).is_none()); + slab + } + + pub fn ensure_slab(&mut self, size: u32) -> SlabPointer { + self.slabs + .get(&size) + .copied() + .unwrap_or_else(|| self.add_slab(size)) } fn transaction(f: impl FnOnce(TransactionHandle)) { @@ -392,8 +407,20 @@ impl Db { }))), file, map, + slabs: BTreeMap::new(), }; + let allocator_state = db.header().allocator_state; + + let mut slabs = BTreeMap::new(); + + for slab in allocator_state.slabs.iter(&db) { + let size = slab.size(&db); + slabs.insert(size, slab); + } + + db.slabs = slabs; + unsafe { if len == 0 { *db.header_mut() = Header::default(); @@ -616,6 +643,7 @@ mod tests { // alloc_and_free_many::<1>(&mut db, 3 * PAGE_SIZE); alloc_and_free_many::<4>(&mut db, PAGE_SIZE / 4 * 3); + alloc_and_free_many::<4>(&mut db, PAGE_SIZE / 4 * 3); alloc_and_free_many::<16>(&mut db, PAGE_SIZE / 16 * 3); let mut child = std::process::Command::new("hexdump")