basic layout of allocator
This commit is contained in:
parent
c762d6b18f
commit
2f3c46136b
187
src/allocator.rs
187
src/allocator.rs
@ -2,7 +2,30 @@ use std::mem::size_of;
|
||||
|
||||
use zerocopy::{AsBytes, FromBytes, Unaligned};
|
||||
|
||||
use crate::{Db, FilePointer, Header, PAGE_SIZE, U32};
|
||||
use crate::{Db, FilePointer, FileRange, Header, PAGE_SIZE, U32};
|
||||
|
||||
enum SlabKind {
|
||||
SplitFreeList,
|
||||
RelativeFreeList,
|
||||
AbsoluteFreeList,
|
||||
}
|
||||
|
||||
impl SlabKind {
|
||||
fn for_size(size: u32) -> Self {
|
||||
if size == 1 {
|
||||
Self::SplitFreeList
|
||||
} else if size < 8 {
|
||||
Self::RelativeFreeList
|
||||
} else if (size as u64) <= PAGE_SIZE {
|
||||
Self::AbsoluteFreeList
|
||||
} else {
|
||||
panic!("invalid size")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Best bitmap sizes in bytes for a 4096 Byte slab
|
||||
// const BITMAP_SIZE: [u32; 8] = [456, 241, 164, 125, 100, 84, 72, 63];
|
||||
|
||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||
#[repr(transparent)]
|
||||
@ -22,43 +45,161 @@ impl FreeList {
|
||||
#[repr(C)]
|
||||
pub struct AllocatorState {
|
||||
pub general: FreeList,
|
||||
pub slabs: FilePointer,
|
||||
pub slabs: SlabListPointer,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||
#[repr(C)]
|
||||
pub struct PoolListHeader {
|
||||
next: FilePointer,
|
||||
size: U32,
|
||||
pub struct SlabListHeader {
|
||||
next: SlabListPointer,
|
||||
len: U32,
|
||||
}
|
||||
|
||||
impl PoolListHeader {
|
||||
fn capacity(&self) -> u32 {
|
||||
(self.size.get() - size_of::<PoolListHeader>() as u32) / size_of::<SizedFreeList>() as u32
|
||||
}
|
||||
size: U32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||
#[repr(C)]
|
||||
pub struct SizedFreeList {
|
||||
element_size: U32,
|
||||
head: FreeList,
|
||||
#[repr(transparent)]
|
||||
pub struct SlabListPointer(pub FilePointer);
|
||||
|
||||
impl SlabListHeader {
|
||||
pub fn capacity(&self) -> u32 {
|
||||
(self.size.get() - size_of::<SlabListHeader>() as u32) / size_of::<Slab>() as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl AllocatorState {
|
||||
pub fn init(&self, db: &mut Db, size: U32) {
|
||||
impl SlabListPointer {
|
||||
pub fn set_next(&self, db: &mut Db, next: SlabListPointer) {
|
||||
db.write(self.0, next);
|
||||
}
|
||||
|
||||
pub fn set_len(&self, db: &mut Db, len: u32) {
|
||||
db.write(self.0 + size_of::<SlabListPointer>() as u64, U32::from(len));
|
||||
}
|
||||
|
||||
pub fn init(&self, db: &mut Db, size: u32) {
|
||||
db.write(
|
||||
self.slabs,
|
||||
PoolListHeader {
|
||||
next: FilePointer::null(),
|
||||
size,
|
||||
self.0,
|
||||
SlabListHeader {
|
||||
next: SlabListPointer(FilePointer::null()),
|
||||
size: size.into(),
|
||||
len: 0.into(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn slabs_mut<'db>(&self, db: &'db mut Db) -> &'db mut PoolListHeader {
|
||||
db.modify(self.slabs)
|
||||
pub fn ptr(&self, db: &Db, i: u32) -> FilePointer {
|
||||
let this: SlabListHeader = db.read(self.0);
|
||||
assert!(i < this.len.get());
|
||||
self.0 + size_of::<SlabListHeader>() as u64 + i as u64 * size_of::<Slab>() as u64
|
||||
}
|
||||
|
||||
pub fn write(&self, db: &mut Db, i: u32, value: Slab) {
|
||||
let ptr = self.ptr(db, i);
|
||||
db.write(ptr, value);
|
||||
}
|
||||
|
||||
pub fn get(&self, db: &Db, i: u32) -> SlabPointer {
|
||||
let ptr = self.ptr(db, i);
|
||||
SlabPointer(ptr)
|
||||
}
|
||||
|
||||
pub fn add(&self, db: &mut Db, slab_size: u32) -> SlabPointer {
|
||||
let this: SlabListHeader = db.read(self.0);
|
||||
let capacity = this.capacity();
|
||||
let SlabListHeader { mut next, len, .. } = this;
|
||||
|
||||
if len.get() >= capacity {
|
||||
if next.0 == FilePointer::null() {
|
||||
next = SlabListPointer(db.add_pages(1));
|
||||
next.init(db, PAGE_SIZE as u32);
|
||||
self.set_next(db, next);
|
||||
}
|
||||
|
||||
return next.add(db, slab_size);
|
||||
}
|
||||
|
||||
let len = len.get();
|
||||
self.set_len(db, len + 1);
|
||||
self.write(
|
||||
db,
|
||||
len,
|
||||
Slab {
|
||||
head: FilePointer::null(),
|
||||
size: slab_size.into(),
|
||||
},
|
||||
);
|
||||
|
||||
SlabPointer(self.ptr(db, len))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||
#[repr(C)]
|
||||
pub struct Slab {
|
||||
head: FilePointer,
|
||||
size: U32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||
#[repr(transparent)]
|
||||
pub struct SlabPointer(FilePointer);
|
||||
|
||||
impl SlabPointer {
|
||||
pub fn read(&self, db: &Db) -> Slab {
|
||||
db.read(self.0)
|
||||
}
|
||||
|
||||
pub fn get(&self, db: &mut Db) -> FileRange {
|
||||
let Slab { head, size } = self.read(db);
|
||||
|
||||
let size = size.get();
|
||||
|
||||
match SlabKind::for_size(size) {
|
||||
SlabKind::SplitFreeList => todo!(),
|
||||
SlabKind::RelativeFreeList => todo!(),
|
||||
SlabKind::AbsoluteFreeList => {
|
||||
let mut next = head;
|
||||
|
||||
if next == FilePointer::null() {
|
||||
next = self.allocate_page(db);
|
||||
}
|
||||
|
||||
let new_next = db.read(next);
|
||||
|
||||
self.set_next(db, new_next);
|
||||
|
||||
next.range(size as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_next(&self, db: &mut Db, next: FilePointer) {
|
||||
db.write(self.0, next);
|
||||
}
|
||||
|
||||
pub fn allocate_page(&self, db: &mut Db) -> FilePointer {
|
||||
let Slab { head, size } = self.read(db);
|
||||
|
||||
let size = size.get();
|
||||
|
||||
match SlabKind::for_size(size) {
|
||||
SlabKind::SplitFreeList => todo!(),
|
||||
SlabKind::RelativeFreeList => todo!(),
|
||||
SlabKind::AbsoluteFreeList => {
|
||||
let n = PAGE_SIZE / size as u64;
|
||||
|
||||
let page = db.add_pages(1);
|
||||
|
||||
let mut next = head;
|
||||
for i in (0..n).rev() {
|
||||
let current = page + i * size as u64;
|
||||
db.write(current, next);
|
||||
next = current;
|
||||
}
|
||||
|
||||
self.set_next(db, next);
|
||||
|
||||
next
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ mod tests {
|
||||
let first = atomic_arc.get();
|
||||
assert_eq!(*first, 1);
|
||||
|
||||
atomic_arc.swap(Arc::new(2));
|
||||
_ = atomic_arc.swap(Arc::new(2));
|
||||
|
||||
assert_eq!(*first, 1);
|
||||
|
||||
|
36
src/lib.rs
36
src/lib.rs
@ -3,7 +3,7 @@ use std::{borrow::BorrowMut, collections::HashMap, fs::File, mem::size_of, ops::
|
||||
mod allocator;
|
||||
mod atomic_arc;
|
||||
|
||||
use allocator::{AllocatorState, FreeList};
|
||||
use allocator::{AllocatorState, FreeList, SlabListPointer, SlabPointer};
|
||||
use atomic_arc::AtomicArc;
|
||||
use memmap::{Mmap, MmapMut};
|
||||
use zerocopy::{AsBytes, FromBytes, LayoutVerified, Unaligned, LE};
|
||||
@ -75,7 +75,7 @@ impl Default for Header {
|
||||
root: FilePointer::null(),
|
||||
allocator_state: AllocatorState {
|
||||
general: FreeList::empty(),
|
||||
slabs: FilePointer::page(0) + size_of::<Header>() as u64,
|
||||
slabs: SlabListPointer(FilePointer::page(0) + size_of::<Header>() as u64),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -172,7 +172,12 @@ impl<'t> TransactionHandle<'t> {
|
||||
}
|
||||
|
||||
impl Db {
|
||||
fn transaction(f: fn(TransactionHandle)) {
|
||||
pub fn add_slab(&mut self, size: u32) -> SlabPointer {
|
||||
let allocator_state = self.header.allocator_state;
|
||||
allocator_state.slabs.add(self, size)
|
||||
}
|
||||
|
||||
fn transaction(f: impl FnOnce(TransactionHandle)) {
|
||||
// let handle = TransactionHandle {};
|
||||
}
|
||||
|
||||
@ -259,12 +264,13 @@ impl Db {
|
||||
unsafe { Mmap::map(&self.file) }.unwrap()
|
||||
}
|
||||
|
||||
fn add_pages(&mut self, n: u64) {
|
||||
self.file
|
||||
.set_len(self.file.metadata().unwrap().len() + PAGE_SIZE * n)
|
||||
.unwrap();
|
||||
fn add_pages(&mut self, n: u64) -> FilePointer {
|
||||
let len = self.file.metadata().unwrap().len();
|
||||
self.file.set_len(len + PAGE_SIZE * n).unwrap();
|
||||
|
||||
self.remap();
|
||||
|
||||
FilePointer::null() + len
|
||||
}
|
||||
|
||||
pub fn new(file: File) -> Self {
|
||||
@ -302,7 +308,7 @@ impl Db {
|
||||
|
||||
fn init_allocator(&mut self) {
|
||||
let allocator_state = self.header.allocator_state;
|
||||
allocator_state.init(
|
||||
allocator_state.slabs.init(
|
||||
self,
|
||||
(PAGE_SIZE - size_of::<Header>() as u64).try_into().unwrap(),
|
||||
);
|
||||
@ -318,7 +324,19 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let db = Db::new(tempfile::tempfile().unwrap());
|
||||
let mut db = Db::new(tempfile::tempfile().unwrap());
|
||||
|
||||
let slab = db.add_slab(16);
|
||||
|
||||
for i in 1..520 {
|
||||
let range = slab.get(&mut db);
|
||||
let start = range.start.0.get();
|
||||
dbg!(start);
|
||||
|
||||
let data = [0; 16].map(|_| i as u8);
|
||||
|
||||
db.write_range(range, data);
|
||||
}
|
||||
|
||||
let mut child = std::process::Command::new("hexdump")
|
||||
.arg("-C")
|
||||
|
Loading…
Reference in New Issue
Block a user