#[cfg(test)]
mod tests;
use fnv::FnvHasher;
use std::hash::Hasher;
use crate::bucket::IBucket;
use crate::consts::{MAGIC, PGID, TXID, VERSION};
use crate::errors::Error;
use crate::page::{Page, PageData};
#[derive(Clone, Debug)]
#[repr(C)]
pub struct Meta {
pub magic: u32,
pub version: u32,
pub page_size: u32,
pub flags: u32,
pub root: IBucket,
pub freelist: PGID,
pub pgid: PGID,
pub txid: TXID,
pub checksum: u64,
}
impl Default for Meta {
fn default() -> Self {
Self {
magic: MAGIC,
version: VERSION,
page_size: page_size::get() as u32,
flags: 0,
root: IBucket::new(),
freelist: 0,
pgid: 0,
txid: 0,
checksum: 0,
}
}
}
impl Meta {
pub(crate) const SIZE: usize = std::mem::size_of::<Self>();
pub fn validate(&self) -> Result<(), Error> {
if self.magic != MAGIC {
return Err(Error::Invalid);
} else if self.version != VERSION {
return Err(Error::VersionMismatch);
} else if self.checksum != 0 && self.checksum != self.sum64() {
return Err(Error::Checksum);
};
Ok(())
}
pub(crate) fn write(&mut self, p: &mut Page) -> Result<(), Error> {
if self.root.root >= self.pgid {
return Err(format!(
"root bucket pgid ({}) above high water mark ({})",
self.root.root, self.pgid
)
.into());
} else if self.freelist >= self.pgid {
return Err(format!(
"freelist pgid ({}) above high water mark ({})",
self.freelist, self.pgid
)
.into());
}
p.id = self.txid % 2;
self.checksum = self.sum64();
p.copy_data_from(PageData::Meta(self));
Ok(())
}
pub 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()
}
}