use crate::bucket::IBucket;
use crate::tx::Txid;
use crate::{error::NKError, error::NKResult};
use crate::{magic, version};
use fnv::FnvHasher;
use memoffset::offset_of;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::mem::size_of;
pub(crate) const MetaSize: usize = size_of::<Meta>();
pub(crate) const LeafPageElementSize: usize = size_of::<LeafPageElement>();
pub(crate) const BranchPageElementSize: usize = size_of::<BranchPageElement>();
pub(crate) type Pgid = u64;
pub(crate) type PageFlag = u16;
pub(crate) const BranchPageFlag: u16 = 0x01;
pub(crate) const LeafPageFlag: u16 = 0x02;
pub(crate) const MetaPageFlag: u16 = 0x04;
pub(crate) const FreeListPageFlag: u16 = 0x10;
pub(crate) const BucketLeafFlag: u32 = 0x01;
pub(crate) const MIN_KEY_PERPAGE: usize = 2;
#[repr(C)]
pub(crate) struct Page {
pub(crate) id: Pgid,
pub(crate) flags: u16,
pub(crate) count: u16,
pub(crate) overflow: u32, ptr: PhantomData<u8>,
}
pub(crate) struct OwnerPage {
pub(crate) value: Vec<u8>,
}
impl OwnerPage {
pub(crate) fn from_vec(value: Vec<u8>) -> Self {
Self { value: value }
}
pub(crate) fn to_page_mut(&mut self) -> &mut Page {
crate::u8_to_struct_mut(&mut self.value)
}
pub(crate) fn to_page(&self) -> &Page {
crate::u8_to_struct(&self.value)
}
}
#[repr(C)]
pub(crate) struct BranchPageElement {
pub(crate) pos: u32, pub(crate) ksize: u32,
pub(crate) pgid: Pgid,
}
impl BranchPageElement {
pub(crate) fn key(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(
(self as *const Self as *const u8).add(self.pos as usize),
self.ksize as usize,
)
}
}
pub(crate) fn as_ptr(&self) -> *const u8 {
self as *const BranchPageElement as *const u8
}
}
#[repr(C)]
pub(crate) struct LeafPageElement {
pub(crate) flags: u32, pub(crate) pos: u32, pub(crate) ksize: u32,
pub(crate) vsize: u32,
}
impl LeafPageElement {
pub(crate) fn key(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(
(self as *const Self as *const u8).add(self.pos as usize),
self.ksize as usize,
)
}
}
pub(crate) fn value(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(
(self as *const Self as *const u8).add((self.pos + self.ksize) as usize),
self.vsize as usize,
)
}
}
pub(crate) fn as_ptr(&self) -> *const u8 {
self as *const LeafPageElement as *const u8
}
}
#[repr(C)]
#[derive(Clone, Copy)]
pub(crate) struct Meta {
pub(crate) magic: u32,
pub(crate) version: u32,
pub(crate) page_size: usize,
pub(crate) flags: u32,
pub(crate) root: IBucket,
pub(crate) freelist: Pgid,
pub(crate) pgid: Pgid,
pub(crate) txid: Txid,
pub(crate) checksum: u64,
}
impl Meta {
pub(crate) fn sum64(&self) -> u64 {
let mut h = FnvHasher::default();
let bytes = unsafe {
std::slice::from_raw_parts(self as *const Self as *const u8, offset_of!(Meta, checksum))
};
h.write(bytes);
h.finish()
}
pub(crate) fn validate(&self) -> NKResult<()> {
if self.magic != magic {
return Err(NKError::ErrInvalid);
} else if self.version != version {
return Err(NKError::ErrVersionMismatch);
} else if self.checksum != self.sum64() {
return Err(NKError::ErrChecksum);
}
Ok(())
}
pub(crate) fn write(&mut self, p: &mut Page) {
p.id = self.txid % 2;
p.flags |= MetaPageFlag;
self.checksum = self.sum64();
let meta = p.meta_mut();
*meta = *self;
}
}
impl Page {
pub(crate) fn header_size() -> usize {
offset_of!(Page, ptr)
}
pub(crate) fn from_buf_mut(buf: &mut [u8]) -> &mut Page {
crate::u8_to_struct_mut::<Page>(buf)
}
pub(crate) fn from_buf(buf: &[u8]) -> &Page {
crate::u8_to_struct::<Page>(buf)
}
pub(crate) fn meta_mut(&mut self) -> &mut Meta {
self.element_mut::<Meta>()
}
pub(crate) fn meta(&self) -> &Meta {
self.element::<Meta>()
}
fn elements<T>(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(self.data_ptr() as *const T, self.count as usize) }
}
fn elements_mut<T>(&mut self) -> &mut [T] {
unsafe {
std::slice::from_raw_parts_mut(self.data_ptr_mut() as *mut T, self.count as usize)
}
}
fn element<T>(&self) -> &T {
unsafe { &*(self.data_ptr() as *const T) }
}
fn element_mut<T>(&mut self) -> &mut T {
unsafe { &mut *(self.data_ptr_mut() as *mut T) }
}
fn leaf_page_elements_mut(&mut self) -> &mut [LeafPageElement] {
self.elements_mut::<LeafPageElement>()
}
fn branch_page_elements_mut(&mut self) -> &mut [BranchPageElement] {
self.elements_mut::<BranchPageElement>()
}
pub(crate) fn branch_page_elements(&self) -> &[BranchPageElement] {
self.elements::<BranchPageElement>()
}
pub(crate) fn leaf_page_elements(&self) -> &[LeafPageElement] {
self.elements::<LeafPageElement>()
}
pub(crate) fn freelist(&self) -> &[Pgid] {
self.elements::<Pgid>()
}
pub(crate) fn freelist_mut(&mut self) -> &mut [Pgid] {
self.elements_mut::<Pgid>()
}
pub(crate) fn leaf_page_element(&self, index: usize) -> &LeafPageElement {
self.leaf_page_elements().get(index).unwrap()
}
pub(crate) fn branch_page_element(&self, index: usize) -> &BranchPageElement {
self.branch_page_elements().get(index).unwrap()
}
pub(crate) fn leaf_page_element_mut(&mut self, index: usize) -> &mut LeafPageElement {
self.leaf_page_elements_mut().get_mut(index).unwrap()
}
pub(crate) fn branch_page_element_mut(&mut self, index: usize) -> &mut BranchPageElement {
self.branch_page_elements_mut().get_mut(index).unwrap()
}
pub(crate) fn data_ptr_mut(&mut self) -> *mut u8 {
&mut self.ptr as *mut PhantomData<u8> as *mut u8
}
pub(crate) fn data_ptr(&self) -> *const u8 {
&self.ptr as *const PhantomData<u8> as *const u8
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_struct_to_slice() {
let mut b = vec![0u8; 4 * 1024];
let a = Page::from_buf_mut(&mut b);
a.id = 100;
println!("id:{:?}", a.id);
let mut v = a.leaf_page_elements_mut();
v[0].pos = 200;
assert!(v[0].pos == 200);
let mut b1 = b.clone();
let a1 = Page::from_buf_mut(&mut b1);
let v1 = a1.leaf_page_elements_mut();
println!("v1[0].pos:{:?}", v1[0].pos);
assert!(v1[0].pos == 200);
}
#[test]
fn test_page_size() {
let size = Page::header_size();
println!("size:{}", size);
}
#[test]
fn test_meta_len() {
println!("meta_size:{}", MetaSize);
}
}