basic layout of allocator
This commit is contained in:
parent
c762d6b18f
commit
2f3c46136b
185
src/allocator.rs
185
src/allocator.rs
@ -2,7 +2,30 @@ use std::mem::size_of;
|
|||||||
|
|
||||||
use zerocopy::{AsBytes, FromBytes, Unaligned};
|
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)]
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
@ -22,43 +45,161 @@ impl FreeList {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct AllocatorState {
|
pub struct AllocatorState {
|
||||||
pub general: FreeList,
|
pub general: FreeList,
|
||||||
pub slabs: FilePointer,
|
pub slabs: SlabListPointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct PoolListHeader {
|
pub struct SlabListHeader {
|
||||||
next: FilePointer,
|
next: SlabListPointer,
|
||||||
size: U32,
|
|
||||||
len: U32,
|
len: U32,
|
||||||
|
size: U32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PoolListHeader {
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||||
fn capacity(&self) -> u32 {
|
#[repr(transparent)]
|
||||||
(self.size.get() - size_of::<PoolListHeader>() as u32) / size_of::<SizedFreeList>() as u32
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
impl SlabListPointer {
|
||||||
#[repr(C)]
|
pub fn set_next(&self, db: &mut Db, next: SlabListPointer) {
|
||||||
pub struct SizedFreeList {
|
db.write(self.0, next);
|
||||||
element_size: U32,
|
}
|
||||||
head: FreeList,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AllocatorState {
|
pub fn set_len(&self, db: &mut Db, len: u32) {
|
||||||
pub fn init(&self, db: &mut Db, size: U32) {
|
db.write(self.0 + size_of::<SlabListPointer>() as u64, U32::from(len));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(&self, db: &mut Db, size: u32) {
|
||||||
db.write(
|
db.write(
|
||||||
self.slabs,
|
self.0,
|
||||||
PoolListHeader {
|
SlabListHeader {
|
||||||
next: FilePointer::null(),
|
next: SlabListPointer(FilePointer::null()),
|
||||||
size,
|
size: size.into(),
|
||||||
len: 0.into(),
|
len: 0.into(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn slabs_mut<'db>(&self, db: &'db mut Db) -> &'db mut PoolListHeader {
|
pub fn ptr(&self, db: &Db, i: u32) -> FilePointer {
|
||||||
db.modify(self.slabs)
|
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();
|
let first = atomic_arc.get();
|
||||||
assert_eq!(*first, 1);
|
assert_eq!(*first, 1);
|
||||||
|
|
||||||
atomic_arc.swap(Arc::new(2));
|
_ = atomic_arc.swap(Arc::new(2));
|
||||||
|
|
||||||
assert_eq!(*first, 1);
|
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 allocator;
|
||||||
mod atomic_arc;
|
mod atomic_arc;
|
||||||
|
|
||||||
use allocator::{AllocatorState, FreeList};
|
use allocator::{AllocatorState, FreeList, SlabListPointer, SlabPointer};
|
||||||
use atomic_arc::AtomicArc;
|
use atomic_arc::AtomicArc;
|
||||||
use memmap::{Mmap, MmapMut};
|
use memmap::{Mmap, MmapMut};
|
||||||
use zerocopy::{AsBytes, FromBytes, LayoutVerified, Unaligned, LE};
|
use zerocopy::{AsBytes, FromBytes, LayoutVerified, Unaligned, LE};
|
||||||
@ -75,7 +75,7 @@ impl Default for Header {
|
|||||||
root: FilePointer::null(),
|
root: FilePointer::null(),
|
||||||
allocator_state: AllocatorState {
|
allocator_state: AllocatorState {
|
||||||
general: FreeList::empty(),
|
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 {
|
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 {};
|
// let handle = TransactionHandle {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,12 +264,13 @@ impl Db {
|
|||||||
unsafe { Mmap::map(&self.file) }.unwrap()
|
unsafe { Mmap::map(&self.file) }.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_pages(&mut self, n: u64) {
|
fn add_pages(&mut self, n: u64) -> FilePointer {
|
||||||
self.file
|
let len = self.file.metadata().unwrap().len();
|
||||||
.set_len(self.file.metadata().unwrap().len() + PAGE_SIZE * n)
|
self.file.set_len(len + PAGE_SIZE * n).unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
self.remap();
|
self.remap();
|
||||||
|
|
||||||
|
FilePointer::null() + len
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(file: File) -> Self {
|
pub fn new(file: File) -> Self {
|
||||||
@ -302,7 +308,7 @@ impl Db {
|
|||||||
|
|
||||||
fn init_allocator(&mut self) {
|
fn init_allocator(&mut self) {
|
||||||
let allocator_state = self.header.allocator_state;
|
let allocator_state = self.header.allocator_state;
|
||||||
allocator_state.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(),
|
||||||
);
|
);
|
||||||
@ -318,7 +324,19 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
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")
|
let mut child = std::process::Command::new("hexdump")
|
||||||
.arg("-C")
|
.arg("-C")
|
||||||
|
Loading…
Reference in New Issue
Block a user