use std::mem::size_of;
use crate::{
error::io_invalid_input,
repr::{header_cast, header_cast_mut, HeaderProvider, PageHeader, PageId},
Bytes, Error, ReservedPageHeader, PAGE_SIZE,
};
#[derive(Debug)]
pub struct Page<const CLONE: bool = true> {
pub dirty: bool,
pub compressed_page: Option<(PageId, u32)>,
#[debug(skip)]
pub raw_data: Bytes,
}
impl Clone for Page<true> {
fn clone(&self) -> Self {
Self {
dirty: self.dirty,
compressed_page: self.compressed_page,
raw_data: self.raw_data.clone(),
}
}
}
impl<const CLONE: bool> Page<CLONE> {
pub fn from_bytes(raw_data: Bytes) -> Result<Self, Error> {
let page = Self {
compressed_page: None,
dirty: false,
raw_data,
};
let total_page_size = size_of::<ReservedPageHeader>() + page.raw_data.len();
if !(page.raw_data.as_ptr() as usize).is_multiple_of(8) {
Err(io_invalid_input!("Bad page alignment"))
} else if !total_page_size.is_multiple_of(PAGE_SIZE as usize)
|| page.span() != ((total_page_size / PAGE_SIZE as usize) as PageId)
{
Err(io_invalid_input!("Bad page len"))
} else {
Ok(page)
}
}
pub fn new(id: PageId, dirty: bool, span: PageId) -> Self {
assert!(span > 0);
let mut page = Self {
compressed_page: None,
dirty,
raw_data: Bytes::new_zeroed(
span as usize * PAGE_SIZE as usize - size_of::<ReservedPageHeader>(),
),
};
*page.header_mut() = PageHeader {
id,
span: span.try_into().unwrap(),
..Default::default()
};
page
}
fn calc_checksum(&self) -> u32 {
let checksum = xxhash_rust::xxh3::xxh3_64(&self.raw_data[size_of::<u32>()..]) as u32;
if checksum == u32::default() {
!u32::default()
} else {
checksum
}
}
pub fn check_checksum(&self) -> Option<bool> {
if self.header().checksum == u32::default() {
None
} else {
Some(self.header().checksum == self.calc_checksum())
}
}
pub fn set_checksum(&mut self, real: bool) {
self.header_mut().checksum = if real {
self.calc_checksum()
} else {
u32::default()
}
}
pub unsafe fn set_checksum_non_mut(&self, real: bool) {
let checksum_ptr = &self.header().checksum as *const u32 as *mut u32;
checksum_ptr.write(if real {
self.calc_checksum()
} else {
u32::default()
})
}
#[inline]
pub fn header(&self) -> &PageHeader {
header_cast(self)
}
#[inline]
pub fn header_mut(&mut self) -> &mut PageHeader {
header_cast_mut(self)
}
#[inline]
pub fn span(&self) -> PageId {
let span = ((size_of::<ReservedPageHeader>() + self.raw_data.len()) / PAGE_SIZE as usize)
as PageId;
debug_assert_eq!(span, PageId::from(self.header().span));
span
}
#[inline]
pub fn id(&self) -> PageId {
self.header().id
}
#[inline]
pub fn data(&self) -> &[u8] {
self.raw_data.as_ref()
}
#[inline]
pub fn data_mut(&mut self) -> &mut [u8] {
self.raw_data.as_mut()
}
#[inline]
pub fn usable_data(&self) -> &[u8] {
self.split_off::<PageHeader>()
}
#[inline]
pub fn usable_data_mut(&mut self) -> &mut [u8] {
self.split_off_mut::<PageHeader>()
}
}