use crate::{
error::{Error, Result},
types::StorageBackendType,
};
pub const RANGE_INDEX_STUB_SIZE: usize = 35;
#[inline]
fn le<const N: usize>(buf: &[u8; RANGE_INDEX_STUB_SIZE], off: usize) -> [u8; N] {
buf[off..off + N].try_into().unwrap()
}
const TREE_HANDLE_OFFSET: usize = 0;
const CACHE_SIZE_OFFSET: usize = 8;
const MIN_RECORD_SIZE_OFFSET: usize = 16;
const MAX_RECORD_SIZE_OFFSET: usize = 20;
const MAX_KEY_LEN_OFFSET: usize = 24;
const LEAF_PAGE_SIZE_OFFSET: usize = 28;
const STORAGE_BACKEND_OFFSET: usize = 32;
const FLAGS_OFFSET: usize = 33;
const SERIALIZATION_PHASE_OFFSET: usize = 34;
const FLUSHED_BIT_MASK: u8 = 1 << 0;
const RECOVERED_BIT_MASK: u8 = 1 << 1;
const TRANSFERRED_BIT_MASK: u8 = 1 << 2;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub struct RangeIndexStub {
pub tree_handle: u64,
pub cache_size: u64,
pub min_record_size: u32,
pub max_record_size: u32,
pub max_key_len: u32,
pub leaf_page_size: u32,
pub storage_backend: u8,
pub flags: u8,
pub serialization_phase: u8,
}
impl RangeIndexStub {
pub fn new(
tree_handle: u64,
cache_size: u64,
min_record_size: u32,
max_record_size: u32,
max_key_len: u32,
leaf_page_size: u32,
storage_backend: impl Into<StorageBackendType>,
) -> Self {
Self {
tree_handle,
cache_size,
min_record_size,
max_record_size,
max_key_len,
leaf_page_size,
storage_backend: storage_backend.into().to_u8(),
flags: 0,
serialization_phase: 0,
}
}
#[inline]
pub const fn is_flushed(&self) -> bool {
(self.flags & FLUSHED_BIT_MASK) != 0
}
#[inline]
pub fn set_flushed(&mut self, flushed: bool) {
if flushed {
self.flags |= FLUSHED_BIT_MASK;
} else {
self.flags &= !FLUSHED_BIT_MASK;
}
}
#[inline]
pub const fn is_recovered(&self) -> bool {
(self.flags & RECOVERED_BIT_MASK) != 0
}
#[inline]
pub fn set_recovered(&mut self, recovered: bool) {
if recovered {
self.flags |= RECOVERED_BIT_MASK;
} else {
self.flags &= !RECOVERED_BIT_MASK;
}
}
#[inline]
pub const fn is_transferred(&self) -> bool {
(self.flags & TRANSFERRED_BIT_MASK) != 0
}
#[inline]
pub fn set_transferred(&mut self, transferred: bool) {
if transferred {
self.flags |= TRANSFERRED_BIT_MASK;
} else {
self.flags &= !TRANSFERRED_BIT_MASK;
}
}
#[inline]
pub fn reset_flags(&mut self) {
self.flags = 0;
}
#[inline]
pub fn clear_tree_handle(&mut self) {
self.tree_handle = 0;
}
#[inline]
pub fn mark_recovered_from_checkpoint(&mut self) {
self.tree_handle = 0;
self.set_recovered(true);
}
#[inline]
pub fn recreate_index(&mut self, new_tree_handle: u64) {
self.tree_handle = new_tree_handle;
self.set_recovered(false);
}
pub fn encode(&self) -> [u8; RANGE_INDEX_STUB_SIZE] {
let mut buf = [0u8; RANGE_INDEX_STUB_SIZE];
buf[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].copy_from_slice(&self.tree_handle.to_le_bytes());
buf[CACHE_SIZE_OFFSET..MIN_RECORD_SIZE_OFFSET].copy_from_slice(&self.cache_size.to_le_bytes());
buf[MIN_RECORD_SIZE_OFFSET..MAX_RECORD_SIZE_OFFSET]
.copy_from_slice(&self.min_record_size.to_le_bytes());
buf[MAX_RECORD_SIZE_OFFSET..MAX_KEY_LEN_OFFSET]
.copy_from_slice(&self.max_record_size.to_le_bytes());
buf[MAX_KEY_LEN_OFFSET..LEAF_PAGE_SIZE_OFFSET].copy_from_slice(&self.max_key_len.to_le_bytes());
buf[LEAF_PAGE_SIZE_OFFSET..STORAGE_BACKEND_OFFSET]
.copy_from_slice(&self.leaf_page_size.to_le_bytes());
buf[STORAGE_BACKEND_OFFSET] = self.storage_backend;
buf[FLAGS_OFFSET] = self.flags;
buf[SERIALIZATION_PHASE_OFFSET] = self.serialization_phase;
buf
}
pub fn encode_into(&self, out: &mut [u8]) -> Result<()> {
if out.len() < RANGE_INDEX_STUB_SIZE {
return Err(Error::InvalidArgument(format!(
"输出切片长度不足 {RANGE_INDEX_STUB_SIZE} 字节: {}",
out.len()
)));
}
out[..RANGE_INDEX_STUB_SIZE].copy_from_slice(&self.encode());
Ok(())
}
pub fn decode(bytes: &[u8]) -> Result<Self> {
let buf: &[u8; RANGE_INDEX_STUB_SIZE] = bytes
.get(..RANGE_INDEX_STUB_SIZE)
.and_then(|s| s.try_into().ok())
.ok_or_else(|| {
Error::InvalidArgument(format!(
"RangeIndexStub 切片长度不足 {RANGE_INDEX_STUB_SIZE} 字节: {}",
bytes.len()
))
})?;
Ok(Self {
tree_handle: u64::from_le_bytes(le(buf, TREE_HANDLE_OFFSET)),
cache_size: u64::from_le_bytes(le(buf, CACHE_SIZE_OFFSET)),
min_record_size: u32::from_le_bytes(le(buf, MIN_RECORD_SIZE_OFFSET)),
max_record_size: u32::from_le_bytes(le(buf, MAX_RECORD_SIZE_OFFSET)),
max_key_len: u32::from_le_bytes(le(buf, MAX_KEY_LEN_OFFSET)),
leaf_page_size: u32::from_le_bytes(le(buf, LEAF_PAGE_SIZE_OFFSET)),
storage_backend: buf[STORAGE_BACKEND_OFFSET],
flags: buf[FLAGS_OFFSET],
serialization_phase: buf[SERIALIZATION_PHASE_OFFSET],
})
}
#[inline]
pub fn slice_clear_tree_handle(slice: &mut [u8]) -> Result<()> {
if slice.len() < CACHE_SIZE_OFFSET {
return Err(Error::InvalidArgument("切片长度不足 8 字节".into()));
}
slice[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].fill(0);
Ok(())
}
#[inline]
pub fn slice_set_flushed(slice: &mut [u8], flushed: bool) -> Result<()> {
Self::validate_slice(slice)?;
if flushed {
slice[FLAGS_OFFSET] |= FLUSHED_BIT_MASK;
} else {
slice[FLAGS_OFFSET] &= !FLUSHED_BIT_MASK;
}
Ok(())
}
#[inline]
pub fn slice_set_transferred(slice: &mut [u8], transferred: bool) -> Result<()> {
Self::validate_slice(slice)?;
if transferred {
slice[FLAGS_OFFSET] |= TRANSFERRED_BIT_MASK;
} else {
slice[FLAGS_OFFSET] &= !TRANSFERRED_BIT_MASK;
}
Ok(())
}
#[inline]
pub fn slice_mark_recovered_from_checkpoint(slice: &mut [u8]) -> Result<()> {
Self::validate_slice(slice)?;
slice[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].fill(0);
slice[FLAGS_OFFSET] |= RECOVERED_BIT_MASK;
Ok(())
}
#[inline]
pub fn slice_recreate_index(slice: &mut [u8], new_tree_handle: u64) -> Result<()> {
Self::validate_slice(slice)?;
slice[TREE_HANDLE_OFFSET..CACHE_SIZE_OFFSET].copy_from_slice(&new_tree_handle.to_le_bytes());
slice[FLAGS_OFFSET] &= !RECOVERED_BIT_MASK;
Ok(())
}
#[inline]
fn validate_slice(slice: &[u8]) -> Result<()> {
if slice.len() < RANGE_INDEX_STUB_SIZE {
return Err(Error::InvalidArgument(format!(
"切片长度不足 {RANGE_INDEX_STUB_SIZE} 字节: {}",
slice.len()
)));
}
Ok(())
}
}