hook up slabs and general allocator to Db methods
This commit is contained in:
parent
1525b3f466
commit
43f85073ef
92
src/lib.rs
92
src/lib.rs
@ -247,6 +247,7 @@ impl Db {
|
|||||||
unsafe { self.modify_range_unchecked(Self::header_ptr().range(size_of::<Header>() as u64)) }
|
unsafe { self.modify_range_unchecked(Self::header_ptr().range(size_of::<Header>() as u64)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: only allowed before any data of `size` has been allocated
|
||||||
fn add_slab(&mut self, size: u32) -> SlabPointer {
|
fn add_slab(&mut self, size: u32) -> SlabPointer {
|
||||||
let allocator_state = self.header().allocator_state;
|
let allocator_state = self.header().allocator_state;
|
||||||
let slab = allocator_state.slabs.add_slab(self, size);
|
let slab = allocator_state.slabs.add_slab(self, size);
|
||||||
@ -254,7 +255,8 @@ impl Db {
|
|||||||
slab
|
slab
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_slab(&mut self, size: u32) -> SlabPointer {
|
// NOTE: only allowed before any data of `size` has been allocated
|
||||||
|
fn ensure_slab(&mut self, size: u32) -> SlabPointer {
|
||||||
self.slabs
|
self.slabs
|
||||||
.get(&size)
|
.get(&size)
|
||||||
.copied()
|
.copied()
|
||||||
@ -392,11 +394,10 @@ impl Db {
|
|||||||
PagePointer::nth((len / PAGE_SIZE).try_into().unwrap())
|
PagePointer::nth((len / PAGE_SIZE).try_into().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(file: File) -> Self {
|
pub fn create(file: File, slabs: &[u32]) -> Self {
|
||||||
let len = file.metadata().unwrap().len();
|
// clear file
|
||||||
if len == 0 {
|
file.set_len(0).unwrap();
|
||||||
file.set_len(PAGE_SIZE).unwrap();
|
file.set_len(PAGE_SIZE).unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
let map = unsafe { MmapMut::map_mut(&file) }.unwrap();
|
let map = unsafe { MmapMut::map_mut(&file) }.unwrap();
|
||||||
|
|
||||||
@ -410,22 +411,9 @@ impl Db {
|
|||||||
slabs: BTreeMap::new(),
|
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 {
|
unsafe {
|
||||||
if len == 0 {
|
*db.header_mut() = Header::default();
|
||||||
*db.header_mut() = Header::default();
|
db.init_allocator(slabs);
|
||||||
db.init_allocator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = db.state.swap(Arc::new(Snapshot {
|
let _ = db.state.swap(Arc::new(Snapshot {
|
||||||
@ -436,17 +424,65 @@ impl Db {
|
|||||||
db
|
db
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn init_allocator(&mut self) {
|
pub fn open(file: File) -> Self {
|
||||||
|
let map = unsafe { MmapMut::map_mut(&file) }.unwrap();
|
||||||
|
|
||||||
|
let mut db = Self {
|
||||||
|
state: Arc::new(AtomicArc::new(Arc::new(Snapshot {
|
||||||
|
root: FilePointer::null(),
|
||||||
|
map: unsafe { Mmap::map(&file).unwrap() },
|
||||||
|
}))),
|
||||||
|
file,
|
||||||
|
map,
|
||||||
|
slabs: BTreeMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = db.state.swap(Arc::new(Snapshot {
|
||||||
|
root: db.header().root,
|
||||||
|
map: unsafe { Mmap::map(&db.file).unwrap() },
|
||||||
|
}));
|
||||||
|
|
||||||
|
db
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn init_allocator(&mut self, slabs: &[u32]) {
|
||||||
let allocator_state = self.header().allocator_state;
|
let allocator_state = self.header().allocator_state;
|
||||||
allocator_state.slabs.init(
|
allocator_state.slabs.init(
|
||||||
self,
|
self,
|
||||||
(PAGE_SIZE - size_of::<Header>() as u64).try_into().unwrap(),
|
(PAGE_SIZE - size_of::<Header>() as u64).try_into().unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
for &size in slabs {
|
||||||
|
self.ensure_slab(size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end_of_file(&self) -> FilePointer {
|
fn end_of_file(&self) -> FilePointer {
|
||||||
FilePointer::null() + self.file.metadata().unwrap().len()
|
FilePointer::null() + self.file.metadata().unwrap().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_slab(&self, size: u64) -> Option<SlabPointer> {
|
||||||
|
u32::try_from(size)
|
||||||
|
.ok()
|
||||||
|
.and_then(|size| self.slabs.get(&size))
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate(&mut self, size: u64) -> FileRange {
|
||||||
|
if let Some(slab) = self.get_slab(size) {
|
||||||
|
slab.alloc(self)
|
||||||
|
} else {
|
||||||
|
Db::general_purpose_allocator().allocate(self, size)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn free(&mut self, range: FileRange) {
|
||||||
|
if let Some(slab) = self.get_slab(range.len()) {
|
||||||
|
slab.free(self, range)
|
||||||
|
} else {
|
||||||
|
Db::general_purpose_allocator().free(self, range)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -454,8 +490,6 @@ mod tests {
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::process::Stdio;
|
use std::process::Stdio;
|
||||||
|
|
||||||
use rand::{thread_rng, Rng};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Operation {
|
enum Operation {
|
||||||
@ -464,7 +498,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn causes_fragmentation(sequence: &[Operation], print: bool) -> bool {
|
fn causes_fragmentation(sequence: &[Operation], print: bool) -> bool {
|
||||||
let mut db = Db::new(tempfile::tempfile().unwrap());
|
let mut db = Db::create(tempfile::tempfile().unwrap(), &[]);
|
||||||
let allocator = Db::general_purpose_allocator();
|
let allocator = Db::general_purpose_allocator();
|
||||||
|
|
||||||
let mut ranges = Vec::new();
|
let mut ranges = Vec::new();
|
||||||
@ -618,14 +652,12 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn it_works() {
|
||||||
let mut db = Db::new(tempfile::tempfile().unwrap());
|
let mut db = Db::create(tempfile::tempfile().unwrap(), &[4, 16]);
|
||||||
|
|
||||||
fn alloc_and_free_many<const N: usize>(db: &mut Db, n: u64) {
|
fn alloc_and_free_many<const N: usize>(db: &mut Db, n: u64) {
|
||||||
let slab = db.add_slab(N as u32);
|
|
||||||
|
|
||||||
let mut ranges = Vec::new();
|
let mut ranges = Vec::new();
|
||||||
for i in 1..n {
|
for i in 1..n {
|
||||||
let range = slab.alloc(db);
|
let range = db.allocate(N as u64);
|
||||||
|
|
||||||
let data = [0; N].map(|_| i as u8);
|
let data = [0; N].map(|_| i as u8);
|
||||||
|
|
||||||
@ -637,7 +669,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for range in ranges.into_iter().rev() {
|
for range in ranges.into_iter().rev() {
|
||||||
slab.free(db, range);
|
db.free(range);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user