add smaller slabs
This commit is contained in:
parent
2f3c46136b
commit
42eda592ff
264
src/allocator.rs
264
src/allocator.rs
@ -2,10 +2,11 @@ use std::mem::size_of;
|
|||||||
|
|
||||||
use zerocopy::{AsBytes, FromBytes, Unaligned};
|
use zerocopy::{AsBytes, FromBytes, Unaligned};
|
||||||
|
|
||||||
use crate::{Db, FilePointer, FileRange, Header, PAGE_SIZE, U32};
|
use crate::{Db, FilePointer, FileRange, PagePointer, PAGE_SIZE, U16, U32};
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
enum SlabKind {
|
enum SlabKind {
|
||||||
SplitFreeList,
|
SingleBytes,
|
||||||
RelativeFreeList,
|
RelativeFreeList,
|
||||||
AbsoluteFreeList,
|
AbsoluteFreeList,
|
||||||
}
|
}
|
||||||
@ -13,8 +14,8 @@ enum SlabKind {
|
|||||||
impl SlabKind {
|
impl SlabKind {
|
||||||
fn for_size(size: u32) -> Self {
|
fn for_size(size: u32) -> Self {
|
||||||
if size == 1 {
|
if size == 1 {
|
||||||
Self::SplitFreeList
|
Self::SingleBytes
|
||||||
} else if size < 8 {
|
} else if size < size_of::<FilePointer>() as u32 {
|
||||||
Self::RelativeFreeList
|
Self::RelativeFreeList
|
||||||
} else if (size as u64) <= PAGE_SIZE {
|
} else if (size as u64) <= PAGE_SIZE {
|
||||||
Self::AbsoluteFreeList
|
Self::AbsoluteFreeList
|
||||||
@ -60,6 +61,28 @@ pub struct SlabListHeader {
|
|||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct SlabListPointer(pub FilePointer);
|
pub struct SlabListPointer(pub FilePointer);
|
||||||
|
|
||||||
|
pub struct SlabListIterator<'db> {
|
||||||
|
position: u32,
|
||||||
|
db: &'db Db,
|
||||||
|
ptr: SlabListPointer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'db> Iterator for SlabListIterator<'db> {
|
||||||
|
type Item = SlabPointer;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if let Some(res) = self.ptr.get(self.db, self.position) {
|
||||||
|
self.position += 1;
|
||||||
|
Some(res)
|
||||||
|
} else if let Some(next) = self.ptr.next(self.db) {
|
||||||
|
self.ptr = next;
|
||||||
|
self.next()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl SlabListHeader {
|
impl SlabListHeader {
|
||||||
pub fn capacity(&self) -> u32 {
|
pub fn capacity(&self) -> u32 {
|
||||||
(self.size.get() - size_of::<SlabListHeader>() as u32) / size_of::<Slab>() as u32
|
(self.size.get() - size_of::<SlabListHeader>() as u32) / size_of::<Slab>() as u32
|
||||||
@ -67,49 +90,68 @@ impl SlabListHeader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SlabListPointer {
|
impl SlabListPointer {
|
||||||
pub fn set_next(&self, db: &mut Db, next: SlabListPointer) {
|
pub fn next(self, db: &Db) -> Option<SlabListPointer> {
|
||||||
db.write(self.0, next);
|
let ptr: SlabListPointer = self.read_header(db).next;
|
||||||
|
|
||||||
|
(!ptr.0.is_null()).then_some(ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_len(&self, db: &mut Db, len: u32) {
|
fn read_header(self, db: &Db) -> SlabListHeader {
|
||||||
db.write(self.0 + size_of::<SlabListPointer>() as u64, U32::from(len));
|
unsafe { db.read(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&self, db: &mut Db, size: u32) {
|
fn modify_header(self, db: &mut Db) -> &mut SlabListHeader {
|
||||||
db.write(
|
unsafe { db.modify(self.0) }
|
||||||
self.0,
|
|
||||||
SlabListHeader {
|
|
||||||
next: SlabListPointer(FilePointer::null()),
|
|
||||||
size: size.into(),
|
|
||||||
len: 0.into(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptr(&self, db: &Db, i: u32) -> FilePointer {
|
pub fn set_next(self, db: &mut Db, next: SlabListPointer) {
|
||||||
let this: SlabListHeader = db.read(self.0);
|
self.modify_header(db).next = next;
|
||||||
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) {
|
pub fn set_len(self, db: &mut Db, len: u32) {
|
||||||
let ptr = self.ptr(db, i);
|
self.modify_header(db).len = U32::from(len);
|
||||||
db.write(ptr, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, db: &Db, i: u32) -> SlabPointer {
|
pub fn init(self, db: &mut Db, size: u32) {
|
||||||
let ptr = self.ptr(db, i);
|
*self.modify_header(db) = SlabListHeader {
|
||||||
SlabPointer(ptr)
|
next: SlabListPointer(FilePointer::null()),
|
||||||
|
size: size.into(),
|
||||||
|
len: 0.into(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&self, db: &mut Db, slab_size: u32) -> SlabPointer {
|
pub fn ptr(self, db: &Db, i: u32) -> Option<FilePointer> {
|
||||||
let this: SlabListHeader = db.read(self.0);
|
let this = self.read_header(db);
|
||||||
|
(i < this.len.get()).then(|| {
|
||||||
|
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).unwrap();
|
||||||
|
unsafe { db.write(ptr, value) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(self, db: &Db, i: u32) -> Option<SlabPointer> {
|
||||||
|
self.ptr(db, i).map(SlabPointer)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(self, db: &Db) -> SlabListIterator {
|
||||||
|
SlabListIterator {
|
||||||
|
position: 0,
|
||||||
|
db,
|
||||||
|
ptr: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(self, db: &mut Db, slab_size: u32) -> SlabPointer {
|
||||||
|
let this = self.read_header(db);
|
||||||
let capacity = this.capacity();
|
let capacity = this.capacity();
|
||||||
let SlabListHeader { mut next, len, .. } = this;
|
let SlabListHeader { mut next, len, .. } = this;
|
||||||
|
|
||||||
if len.get() >= capacity {
|
if len.get() >= capacity {
|
||||||
if next.0 == FilePointer::null() {
|
if next.0.is_null() {
|
||||||
next = SlabListPointer(db.add_pages(1));
|
next = SlabListPointer(db.add_pages(1).start());
|
||||||
next.init(db, PAGE_SIZE as u32);
|
next.init(db, PAGE_SIZE as u32);
|
||||||
self.set_next(db, next);
|
self.set_next(db, next);
|
||||||
}
|
}
|
||||||
@ -128,7 +170,7 @@ impl SlabListPointer {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
SlabPointer(self.ptr(db, len))
|
SlabPointer(self.ptr(db, len).unwrap())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,51 +181,169 @@ pub struct Slab {
|
|||||||
size: U32,
|
size: U32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct RelativeFreeListHeader {
|
||||||
|
next_page: PagePointer,
|
||||||
|
first: U16,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelativeFreeListHeader {
|
||||||
|
const DATA_SIZE: u32 = PAGE_SIZE as u32 - size_of::<Self>() as u32;
|
||||||
|
|
||||||
|
fn capacity(size: u32) -> u32 {
|
||||||
|
debug_assert_eq!(SlabKind::for_size(size), SlabKind::RelativeFreeList);
|
||||||
|
Self::DATA_SIZE / size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct SlabPointer(FilePointer);
|
pub struct SlabPointer(FilePointer);
|
||||||
|
|
||||||
impl SlabPointer {
|
impl SlabPointer {
|
||||||
pub fn read(&self, db: &Db) -> Slab {
|
fn read(&self, db: &Db) -> Slab {
|
||||||
db.read(self.0)
|
unsafe { db.read(self.0) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, db: &mut Db) -> FileRange {
|
fn modify<'db>(&self, db: &'db mut Db) -> &'db mut Slab {
|
||||||
let Slab { head, size } = self.read(db);
|
unsafe { db.modify(self.0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc(&self, db: &mut Db) -> FileRange {
|
||||||
|
let Slab { mut head, size } = self.read(db);
|
||||||
|
|
||||||
|
if head.is_null() {
|
||||||
|
head = self.allocate_page(db);
|
||||||
|
}
|
||||||
|
|
||||||
let size = size.get();
|
let size = size.get();
|
||||||
|
|
||||||
match SlabKind::for_size(size) {
|
match SlabKind::for_size(size) {
|
||||||
SlabKind::SplitFreeList => todo!(),
|
SlabKind::SingleBytes => todo!(),
|
||||||
SlabKind::RelativeFreeList => todo!(),
|
SlabKind::RelativeFreeList => {
|
||||||
SlabKind::AbsoluteFreeList => {
|
let (page, offset) = head.page_offset();
|
||||||
let mut next = head;
|
assert_eq!(offset, 0);
|
||||||
|
|
||||||
if next == FilePointer::null() {
|
let RelativeFreeListHeader { first, .. } = unsafe { db.read(page.start()) };
|
||||||
next = self.allocate_page(db);
|
|
||||||
|
// the page should never be full if its in the free list
|
||||||
|
assert_ne!(first.get(), 0);
|
||||||
|
|
||||||
|
let ptr = FilePointer::from_page_offset(page, first.get());
|
||||||
|
|
||||||
|
let next: U16 = unsafe { db.read(ptr) };
|
||||||
|
|
||||||
|
let header = unsafe { db.modify::<RelativeFreeListHeader>(page.start()) };
|
||||||
|
|
||||||
|
header.first = next;
|
||||||
|
|
||||||
|
if next.get() == 0 {
|
||||||
|
// page is full
|
||||||
|
let next_page = header.next_page;
|
||||||
|
header.next_page = PagePointer::null();
|
||||||
|
self.modify(db).head = next_page.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_next = db.read(next);
|
ptr
|
||||||
|
}
|
||||||
|
SlabKind::AbsoluteFreeList => {
|
||||||
|
let next = unsafe { db.read(head) };
|
||||||
|
self.set_head(db, next);
|
||||||
|
head
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.range(size as u64)
|
||||||
|
}
|
||||||
|
|
||||||
self.set_next(db, new_next);
|
pub fn free(&self, db: &mut Db, range: FileRange) {
|
||||||
|
let Slab { head, size } = self.read(db);
|
||||||
|
|
||||||
next.range(size as u64)
|
assert_eq!(range.len(), size.get() as u64);
|
||||||
|
|
||||||
|
let size = size.get();
|
||||||
|
|
||||||
|
match SlabKind::for_size(size) {
|
||||||
|
SlabKind::SingleBytes => todo!(),
|
||||||
|
SlabKind::RelativeFreeList => {
|
||||||
|
let (page, offset) = range.start.page_offset();
|
||||||
|
|
||||||
|
let RelativeFreeListHeader { first, .. } = unsafe { db.read(page.start()) };
|
||||||
|
|
||||||
|
// update next pointer of new element in free list
|
||||||
|
unsafe { db.write(range.start, first) };
|
||||||
|
|
||||||
|
let header = unsafe { db.modify::<RelativeFreeListHeader>(page.start()) };
|
||||||
|
|
||||||
|
// point to new element
|
||||||
|
header.first = offset.into();
|
||||||
|
|
||||||
|
if first.get() == 0 {
|
||||||
|
// page was full
|
||||||
|
|
||||||
|
let (head_page, offset) = head.page_offset();
|
||||||
|
assert_eq!(offset, 0);
|
||||||
|
|
||||||
|
header.next_page = head_page;
|
||||||
|
|
||||||
|
self.modify(db).head = page.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SlabKind::AbsoluteFreeList => {
|
||||||
|
unsafe { db.write(range.start, head) };
|
||||||
|
self.set_head(db, range.start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_next(&self, db: &mut Db, next: FilePointer) {
|
pub fn set_head(&self, db: &mut Db, next: FilePointer) {
|
||||||
db.write(self.0, next);
|
self.modify(db).head = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocate_page(&self, db: &mut Db) -> FilePointer {
|
pub fn allocate_page(&self, db: &mut Db) -> FilePointer {
|
||||||
let Slab { head, size } = self.read(db);
|
let Slab { head, size } = self.read(db);
|
||||||
|
|
||||||
|
println!("allocate_page({size})");
|
||||||
|
|
||||||
let size = size.get();
|
let size = size.get();
|
||||||
|
|
||||||
match SlabKind::for_size(size) {
|
match SlabKind::for_size(size) {
|
||||||
SlabKind::SplitFreeList => todo!(),
|
SlabKind::SingleBytes => todo!(),
|
||||||
SlabKind::RelativeFreeList => todo!(),
|
SlabKind::RelativeFreeList => {
|
||||||
|
let page = db.add_pages(1);
|
||||||
|
|
||||||
|
let (next_page, offset) = head.page_offset();
|
||||||
|
assert_eq!(offset, 0);
|
||||||
|
|
||||||
|
let capacity = RelativeFreeListHeader::capacity(size);
|
||||||
|
|
||||||
|
let data_offset = size_of::<Self>() as u16;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
db.write(
|
||||||
|
page.start(),
|
||||||
|
RelativeFreeListHeader {
|
||||||
|
next_page,
|
||||||
|
first: data_offset.into(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut offset = 0;
|
||||||
|
for i in (0..capacity).rev() {
|
||||||
|
let next = data_offset + (i * size) as u16;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
db.write(FilePointer::from_page_offset(page, next), U16::from(offset))
|
||||||
|
};
|
||||||
|
|
||||||
|
offset = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_head(db, page.start());
|
||||||
|
|
||||||
|
page.start()
|
||||||
|
}
|
||||||
SlabKind::AbsoluteFreeList => {
|
SlabKind::AbsoluteFreeList => {
|
||||||
let n = PAGE_SIZE / size as u64;
|
let n = PAGE_SIZE / size as u64;
|
||||||
|
|
||||||
@ -191,12 +351,12 @@ impl SlabPointer {
|
|||||||
|
|
||||||
let mut next = head;
|
let mut next = head;
|
||||||
for i in (0..n).rev() {
|
for i in (0..n).rev() {
|
||||||
let current = page + i * size as u64;
|
let current = page.start() + i * size as u64;
|
||||||
db.write(current, next);
|
unsafe { db.write(current, next) };
|
||||||
next = current;
|
next = current;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.set_next(db, next);
|
self.set_head(db, next);
|
||||||
|
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
107
src/lib.rs
107
src/lib.rs
@ -12,18 +12,51 @@ const PAGE_SIZE: u64 = 4096;
|
|||||||
|
|
||||||
type U64 = zerocopy::byteorder::U64<LE>;
|
type U64 = zerocopy::byteorder::U64<LE>;
|
||||||
type U32 = zerocopy::byteorder::U32<LE>;
|
type U32 = zerocopy::byteorder::U32<LE>;
|
||||||
|
type U16 = zerocopy::byteorder::U16<LE>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned, Debug, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned, Debug, Hash, PartialEq, Eq)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct FilePointer(U64);
|
pub struct FilePointer(U64);
|
||||||
|
|
||||||
impl FilePointer {
|
impl FilePointer {
|
||||||
fn page(n: u64) -> Self {
|
fn page(self) -> PagePointer {
|
||||||
Self((n * PAGE_SIZE).into())
|
PagePointer(u32::try_from(self.0.get() / PAGE_SIZE).unwrap().into())
|
||||||
|
}
|
||||||
|
fn page_offset(self) -> (PagePointer, u16) {
|
||||||
|
(self.page(), (self.0.get() % PAGE_SIZE) as u16)
|
||||||
|
}
|
||||||
|
fn from_page_offset(page: PagePointer, offset: u16) -> Self {
|
||||||
|
debug_assert!(
|
||||||
|
offset < PAGE_SIZE as u16,
|
||||||
|
"offset 0x{offset:x} out for page bounds (0..0x{PAGE_SIZE:x})"
|
||||||
|
);
|
||||||
|
page.start() + offset as u64
|
||||||
}
|
}
|
||||||
fn null() -> Self {
|
fn null() -> Self {
|
||||||
Self(U64::ZERO)
|
Self(U64::ZERO)
|
||||||
}
|
}
|
||||||
|
fn is_null(self) -> bool {
|
||||||
|
self == Self::null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct PagePointer(U32);
|
||||||
|
|
||||||
|
impl PagePointer {
|
||||||
|
fn start(self) -> FilePointer {
|
||||||
|
FilePointer((self.0.get() as u64 * PAGE_SIZE).into())
|
||||||
|
}
|
||||||
|
fn range(self) -> FileRange {
|
||||||
|
self.start().range(PAGE_SIZE)
|
||||||
|
}
|
||||||
|
fn nth(n: u32) -> Self {
|
||||||
|
Self(n.into())
|
||||||
|
}
|
||||||
|
fn null() -> Self {
|
||||||
|
Self::nth(0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, FromBytes, AsBytes, Unaligned, Debug, PartialEq, Eq)]
|
||||||
@ -75,7 +108,7 @@ impl Default for Header {
|
|||||||
root: FilePointer::null(),
|
root: FilePointer::null(),
|
||||||
allocator_state: AllocatorState {
|
allocator_state: AllocatorState {
|
||||||
general: FreeList::empty(),
|
general: FreeList::empty(),
|
||||||
slabs: SlabListPointer(FilePointer::page(0) + size_of::<Header>() as u64),
|
slabs: SlabListPointer(FilePointer::null() + size_of::<Header>() as u64),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -203,7 +236,10 @@ impl Db {
|
|||||||
self.map.flush().unwrap();
|
self.map.flush().unwrap();
|
||||||
|
|
||||||
// update root pointer and immediately flush
|
// update root pointer and immediately flush
|
||||||
self.write(Self::root_ptr(), new_root);
|
unsafe {
|
||||||
|
self.write(Self::root_ptr(), new_root);
|
||||||
|
}
|
||||||
|
|
||||||
self.map
|
self.map
|
||||||
.flush_range(Self::root_ptr().0.get() as usize, size_of::<FilePointer>())
|
.flush_range(Self::root_ptr().0.get() as usize, size_of::<FilePointer>())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -215,41 +251,41 @@ impl Db {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read<T: FromBytes>(&self, at: FilePointer) -> T {
|
unsafe fn read<T: FromBytes>(&self, at: FilePointer) -> T {
|
||||||
self.read_range(at.range(size_of::<T>() as u64))
|
self.read_range(at.range(size_of::<T>() as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_range<T: FromBytes>(&self, range: FileRange) -> T {
|
unsafe fn read_range<T: FromBytes>(&self, range: FileRange) -> T {
|
||||||
LayoutVerified::<_, T>::new(&self.map[range.as_range()])
|
LayoutVerified::<_, T>::new(&self.map[range.as_range()])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.read()
|
.read()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write<T: AsBytes>(&mut self, at: FilePointer, data: T) {
|
unsafe fn write<T: AsBytes>(&mut self, at: FilePointer, data: T) {
|
||||||
self.write_range(at.range(size_of::<T>() as u64), data)
|
self.write_range(at.range(size_of::<T>() as u64), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_range<T: AsBytes>(&mut self, range: FileRange, data: T) {
|
unsafe fn write_range<T: AsBytes>(&mut self, range: FileRange, data: T) {
|
||||||
LayoutVerified::<_, T>::new(&mut self.map[range.as_range()])
|
LayoutVerified::<_, T>::new(&mut self.map[range.as_range()])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.write(data)
|
.write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify<T: FromBytes + AsBytes>(&mut self, at: FilePointer) -> &mut T {
|
unsafe fn modify<T: FromBytes + AsBytes>(&mut self, at: FilePointer) -> &mut T {
|
||||||
self.modify_range(at.range(size_of::<T>() as u64))
|
self.modify_range(at.range(size_of::<T>() as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify_range<T: FromBytes + AsBytes>(&mut self, range: FileRange) -> &mut T {
|
unsafe fn modify_range<T: FromBytes + AsBytes>(&mut self, range: FileRange) -> &mut T {
|
||||||
LayoutVerified::<_, T>::new(&mut self.map[range.as_range()])
|
LayoutVerified::<_, T>::new(&mut self.map[range.as_range()])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_mut()
|
.into_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reference<T: FromBytes + AsBytes>(&self, at: FilePointer) -> &T {
|
unsafe fn reference<T: FromBytes + AsBytes>(&self, at: FilePointer) -> &T {
|
||||||
self.reference_range(at.range(size_of::<T>() as u64))
|
self.reference_range(at.range(size_of::<T>() as u64))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reference_range<T: FromBytes + AsBytes>(&self, range: FileRange) -> &T {
|
unsafe fn reference_range<T: FromBytes + AsBytes>(&self, range: FileRange) -> &T {
|
||||||
LayoutVerified::<_, T>::new(&self.map[range.as_range()])
|
LayoutVerified::<_, T>::new(&self.map[range.as_range()])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.into_ref()
|
.into_ref()
|
||||||
@ -264,13 +300,11 @@ impl Db {
|
|||||||
unsafe { Mmap::map(&self.file) }.unwrap()
|
unsafe { Mmap::map(&self.file) }.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_pages(&mut self, n: u64) -> FilePointer {
|
fn add_pages(&mut self, n: u64) -> PagePointer {
|
||||||
let len = self.file.metadata().unwrap().len();
|
let len = self.file.metadata().unwrap().len();
|
||||||
self.file.set_len(len + PAGE_SIZE * n).unwrap();
|
self.file.set_len(len + PAGE_SIZE * n).unwrap();
|
||||||
|
|
||||||
self.remap();
|
self.remap();
|
||||||
|
PagePointer::nth((len / PAGE_SIZE).try_into().unwrap())
|
||||||
FilePointer::null() + len
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(file: File) -> Self {
|
pub fn new(file: File) -> Self {
|
||||||
@ -291,11 +325,13 @@ impl Db {
|
|||||||
header: Header::default(),
|
header: Header::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if len == 0 {
|
unsafe {
|
||||||
db.init_allocator();
|
if len == 0 {
|
||||||
db.write(Self::header_ptr(), db.header);
|
db.init_allocator();
|
||||||
} else {
|
db.write(Self::header_ptr(), db.header);
|
||||||
db.header = db.read(Self::header_ptr());
|
} else {
|
||||||
|
db.header = db.read(Self::header_ptr());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = db.state.swap(Arc::new(Snapshot {
|
let _ = db.state.swap(Arc::new(Snapshot {
|
||||||
@ -306,7 +342,7 @@ impl Db {
|
|||||||
db
|
db
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_allocator(&mut self) {
|
unsafe fn init_allocator(&mut self) {
|
||||||
let allocator_state = self.header.allocator_state;
|
let allocator_state = self.header.allocator_state;
|
||||||
allocator_state.slabs.init(
|
allocator_state.slabs.init(
|
||||||
self,
|
self,
|
||||||
@ -326,18 +362,31 @@ mod tests {
|
|||||||
fn it_works() {
|
fn it_works() {
|
||||||
let mut db = Db::new(tempfile::tempfile().unwrap());
|
let mut db = Db::new(tempfile::tempfile().unwrap());
|
||||||
|
|
||||||
let slab = db.add_slab(16);
|
fn alloc_and_free_many<const N: usize>(db: &mut Db, n: u64) {
|
||||||
|
let slab = db.add_slab(N as u32);
|
||||||
|
|
||||||
for i in 1..520 {
|
let mut ranges = Vec::new();
|
||||||
let range = slab.get(&mut db);
|
for i in 1..n {
|
||||||
let start = range.start.0.get();
|
let range = slab.alloc(db);
|
||||||
dbg!(start);
|
|
||||||
|
|
||||||
let data = [0; 16].map(|_| i as u8);
|
let data = [0; N].map(|_| i as u8);
|
||||||
|
|
||||||
db.write_range(range, data);
|
unsafe {
|
||||||
|
db.write_range(range, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
ranges.push(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
for range in ranges.into_iter().rev() {
|
||||||
|
slab.free(db, range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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::<16>(&mut db, PAGE_SIZE / 16 * 3);
|
||||||
|
|
||||||
let mut child = std::process::Command::new("hexdump")
|
let mut child = std::process::Command::new("hexdump")
|
||||||
.arg("-C")
|
.arg("-C")
|
||||||
.stdin(Stdio::piped())
|
.stdin(Stdio::piped())
|
||||||
|
Loading…
Reference in New Issue
Block a user