use crate::common::{PageID, Tsn};
use crate::slice_reader::SliceReader;
use std::io::{Cursor, Write};
use umadb_dcb::{DcbError, DcbResult};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FreeListLeafNode {
pub keys: Vec<Tsn>,
pub values: Vec<FreeListLeafValue>,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct FreeListLeafValue {
pub page_ids: Vec<PageID>,
pub root_id: PageID,
}
impl FreeListLeafNode {
pub fn calc_serialized_size(&self) -> usize {
let mut total_size = 2;
total_size += self.keys.len() * 8;
for value in &self.values {
total_size += 2;
total_size += value.page_ids.len() * 8;
total_size += 8;
}
total_size
}
pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
let mut cursor = Cursor::new(buf);
let klen = self.keys.len() as u16;
cursor.write_all(&klen.to_le_bytes())?;
for key in &self.keys {
cursor.write_all(&key.0.to_le_bytes())?;
}
for value in &self.values {
let plen = value.page_ids.len() as u16;
cursor.write_all(&plen.to_le_bytes())?;
for page_id in &value.page_ids {
cursor.write_all(&page_id.0.to_le_bytes())?;
}
cursor.write_all(&value.root_id.0.to_le_bytes())?;
}
Ok(cursor.position() as usize)
}
pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
let mut reader = SliceReader::new(slice);
let keys_len = reader.read_u16()? as usize;
let mut keys = Vec::with_capacity(keys_len);
for _ in 0..keys_len {
keys.push(reader.read_tsn()?);
}
let mut values = Vec::with_capacity(keys_len);
for _ in 0..keys_len {
let page_ids_len = reader.read_u16()? as usize;
let mut page_ids = Vec::with_capacity(page_ids_len);
for _ in 0..page_ids_len {
page_ids.push(reader.read_page_id()?);
}
let root_id = reader.read_page_id()?;
values.push(FreeListLeafValue { page_ids, root_id });
}
Ok(FreeListLeafNode { keys, values })
}
pub fn would_fit_new_tsn_and_page_id(&self, max_node_size: usize) -> bool {
self.calc_serialized_size() + 8 + 2 + 8 + 8 <= max_node_size
}
pub fn push_new_key_and_value(&mut self, tsn: Tsn, page_id: PageID) {
self.keys.push(tsn);
self.values.push(FreeListLeafValue {
page_ids: vec![page_id],
root_id: PageID(0),
});
}
pub fn would_fit_new_page_id(&self, max_node_size: usize) -> bool {
self.calc_serialized_size() + 8 <= max_node_size
}
pub fn push_new_page_id(&mut self, idx: usize, page_id: PageID) {
self.values[idx].page_ids.push(page_id);
}
pub fn pop_last_key_and_value(&mut self) -> DcbResult<(Tsn, FreeListLeafValue)> {
let last_key = self
.keys
.pop()
.expect("FreeListLeafNode should have at least one key");
let last_value = self
.values
.pop()
.expect("FreeListLeafNode should have at least one value");
Ok((last_key, last_value))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FreeListInternalNode {
pub keys: Vec<Tsn>,
pub child_ids: Vec<PageID>,
}
impl FreeListInternalNode {
pub fn calc_serialized_size(&self) -> usize {
let mut total_size = 2;
total_size += self.keys.len() * 8;
total_size += 2;
total_size += self.child_ids.len() * 8;
total_size
}
pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
let mut cursor = Cursor::new(buf);
let klen = self.keys.len() as u16;
cursor.write_all(&klen.to_le_bytes())?;
for key in &self.keys {
cursor.write_all(&key.0.to_le_bytes())?;
}
let clen = self.child_ids.len() as u16;
cursor.write_all(&clen.to_le_bytes())?;
for child_id in &self.child_ids {
cursor.write_all(&child_id.0.to_le_bytes())?;
}
Ok(cursor.position() as usize)
}
pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
let mut reader = SliceReader::new(slice);
let keys_len = reader.read_u16()? as usize;
let mut keys = Vec::with_capacity(keys_len);
for _ in 0..keys_len {
keys.push(reader.read_tsn()?);
}
let child_ids_len = reader.read_u16()? as usize;
let mut child_ids = Vec::with_capacity(child_ids_len);
for _ in 0..child_ids_len {
child_ids.push(reader.read_page_id()?);
}
Ok(FreeListInternalNode { keys, child_ids })
}
pub fn replace_last_child_id(&mut self, old_id: PageID, new_id: PageID) -> DcbResult<()> {
let last_idx = self.child_ids.len() - 1;
if self.child_ids[last_idx] == old_id {
self.child_ids[last_idx] = new_id;
} else {
return Err(DcbError::DatabaseCorrupted("Child ID mismatch".to_string()));
}
Ok(())
}
pub fn append_promoted_key_and_page_id(
&mut self,
promoted_key: Tsn,
promoted_page_id: PageID,
) -> DcbResult<()> {
self.keys.push(promoted_key);
self.child_ids.push(promoted_page_id);
Ok(())
}
pub(crate) fn split_off(&mut self) -> DcbResult<(Tsn, Vec<Tsn>, Vec<PageID>)> {
let middle_idx = self.keys.len() - 2;
let promoted_key = self.keys.remove(middle_idx);
let new_keys = self.keys.split_off(middle_idx);
let new_child_ids = self.child_ids.split_off(middle_idx + 1);
Ok((promoted_key, new_keys, new_child_ids))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FreeListTsnLeafNode {
pub page_ids: Vec<PageID>,
}
impl FreeListTsnLeafNode {
pub fn calc_serialized_size(&self) -> usize {
2 + self.page_ids.len() * 8
}
pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
let mut cursor = Cursor::new(buf);
let plen = self.page_ids.len() as u16;
cursor.write_all(&plen.to_le_bytes())?;
for page_id in &self.page_ids {
cursor.write_all(&page_id.0.to_le_bytes())?;
}
Ok(cursor.position() as usize)
}
pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
let mut reader = SliceReader::new(slice);
let plen = reader.read_u16()? as usize;
let mut page_ids = Vec::with_capacity(plen);
for _ in 0..plen {
page_ids.push(reader.read_page_id()?);
}
Ok(FreeListTsnLeafNode { page_ids })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FreeListTsnInternalNode {
pub keys: Vec<PageID>,
pub child_ids: Vec<PageID>,
}
impl FreeListTsnInternalNode {
pub fn calc_serialized_size(&self) -> usize {
2 + self.keys.len() * 8 + 2 + self.child_ids.len() * 8
}
pub fn serialize_into(&self, buf: &mut [u8]) -> DcbResult<usize> {
let mut cursor = Cursor::new(buf);
let klen = self.keys.len() as u16;
cursor.write_all(&klen.to_le_bytes())?;
for key in &self.keys {
cursor.write_all(&key.0.to_le_bytes())?;
}
let clen = self.child_ids.len() as u16;
cursor.write_all(&clen.to_le_bytes())?;
for child_id in &self.child_ids {
cursor.write_all(&child_id.0.to_le_bytes())?;
}
Ok(cursor.position() as usize)
}
pub fn from_slice(slice: &[u8]) -> DcbResult<Self> {
let mut reader = SliceReader::new(slice);
let klen = reader.read_u16()? as usize;
let mut keys = Vec::with_capacity(klen);
for _ in 0..klen {
keys.push(reader.read_page_id()?);
}
let clen = reader.read_u16()? as usize;
let mut child_ids = Vec::with_capacity(clen);
for _ in 0..clen {
child_ids.push(reader.read_page_id()?);
}
Ok(FreeListTsnInternalNode { keys, child_ids })
}
pub fn would_fit_new_key_and_child(&self, max_node_size: usize) -> bool {
self.calc_serialized_size() + 16 <= max_node_size
}
}
#[cfg(test)]
mod tests {
use crate::common::{PageID, Tsn};
use crate::free_lists_tree_nodes::{
FreeListInternalNode, FreeListLeafNode, FreeListLeafValue, FreeListTsnInternalNode,
FreeListTsnLeafNode,
};
#[test]
fn test_freelist_leaf_serialize() {
let leaf_node = FreeListLeafNode {
keys: vec![Tsn(10), Tsn(20), Tsn(30)],
values: vec![
FreeListLeafValue {
page_ids: vec![PageID(100), PageID(101)],
root_id: PageID(200),
},
FreeListLeafValue {
page_ids: vec![PageID(102), PageID(103), PageID(104)],
root_id: PageID(0),
},
FreeListLeafValue {
page_ids: vec![PageID(105)],
root_id: PageID(300),
},
],
};
let mut serialized = vec![0u8; leaf_node.calc_serialized_size()];
leaf_node.serialize_into(&mut serialized).unwrap();
assert!(!serialized.is_empty());
let deserialized = FreeListLeafNode::from_slice(&serialized)
.expect("Failed to deserialize FreeListLeafNode");
assert_eq!(leaf_node, deserialized);
assert_eq!(3, deserialized.keys.len());
assert_eq!(3, deserialized.values.len());
assert_eq!(Tsn(10), deserialized.keys[0]);
assert_eq!(Tsn(20), deserialized.keys[1]);
assert_eq!(Tsn(30), deserialized.keys[2]);
assert_eq!(2, deserialized.values[0].page_ids.len());
assert_eq!(PageID(100), deserialized.values[0].page_ids[0]);
assert_eq!(PageID(101), deserialized.values[0].page_ids[1]);
assert_eq!(PageID(200), deserialized.values[0].root_id);
assert_eq!(3, deserialized.values[1].page_ids.len());
assert_eq!(PageID(102), deserialized.values[1].page_ids[0]);
assert_eq!(PageID(103), deserialized.values[1].page_ids[1]);
assert_eq!(PageID(104), deserialized.values[1].page_ids[2]);
assert_eq!(PageID(0), deserialized.values[1].root_id);
assert_eq!(1, deserialized.values[2].page_ids.len());
assert_eq!(PageID(105), deserialized.values[2].page_ids[0]);
assert_eq!(PageID(300), deserialized.values[2].root_id);
}
#[test]
fn test_freelist_internal_serialize() {
let internal_node = FreeListInternalNode {
keys: vec![Tsn(10), Tsn(20), Tsn(30)],
child_ids: vec![PageID(100), PageID(200), PageID(300), PageID(400)],
};
let mut serialized = vec![0u8; internal_node.calc_serialized_size()];
internal_node.serialize_into(&mut serialized).unwrap();
assert!(!serialized.is_empty());
assert_eq!(&[3, 0], &serialized[0..2]);
assert_eq!(&10u64.to_le_bytes(), &serialized[2..10]);
assert_eq!(&20u64.to_le_bytes(), &serialized[10..18]);
assert_eq!(&30u64.to_le_bytes(), &serialized[18..26]);
assert_eq!(&[4, 0], &serialized[26..28]);
assert_eq!(&100u64.to_le_bytes(), &serialized[28..36]);
assert_eq!(&200u64.to_le_bytes(), &serialized[36..44]);
assert_eq!(&300u64.to_le_bytes(), &serialized[44..52]);
assert_eq!(&400u64.to_le_bytes(), &serialized[52..60]);
let deserialized = FreeListInternalNode::from_slice(&serialized)
.expect("Failed to deserialize FreeListInternalNode");
assert_eq!(internal_node, deserialized);
assert_eq!(3, deserialized.keys.len());
assert_eq!(4, deserialized.child_ids.len());
assert_eq!(Tsn(10), deserialized.keys[0]);
assert_eq!(Tsn(20), deserialized.keys[1]);
assert_eq!(Tsn(30), deserialized.keys[2]);
assert_eq!(PageID(100), deserialized.child_ids[0]);
assert_eq!(PageID(200), deserialized.child_ids[1]);
assert_eq!(PageID(300), deserialized.child_ids[2]);
assert_eq!(PageID(400), deserialized.child_ids[3]);
}
#[test]
fn test_freelist_tsn_leaf_serialize() {
let node = FreeListTsnLeafNode {
page_ids: vec![PageID(11), PageID(22), PageID(33), PageID(44)],
};
let mut serialized = vec![0u8; node.calc_serialized_size()];
node.serialize_into(&mut serialized).unwrap();
assert_eq!(&[4, 0], &serialized[0..2]);
assert_eq!(&11u64.to_le_bytes(), &serialized[2..10]);
assert_eq!(&22u64.to_le_bytes(), &serialized[10..18]);
assert_eq!(&33u64.to_le_bytes(), &serialized[18..26]);
assert_eq!(&44u64.to_le_bytes(), &serialized[26..34]);
let deserialized = FreeListTsnLeafNode::from_slice(&serialized)
.expect("Failed to deserialize FreeListTsnLeafNode");
assert_eq!(node, deserialized);
assert_eq!(4, deserialized.page_ids.len());
assert_eq!(PageID(11), deserialized.page_ids[0]);
assert_eq!(PageID(22), deserialized.page_ids[1]);
assert_eq!(PageID(33), deserialized.page_ids[2]);
assert_eq!(PageID(44), deserialized.page_ids[3]);
}
#[test]
fn test_freelist_tsn_internal_serialize() {
let node = FreeListTsnInternalNode {
keys: vec![PageID(5), PageID(15), PageID(25)],
child_ids: vec![PageID(1000), PageID(2000), PageID(3000), PageID(4000)],
};
let mut serialized = vec![0u8; node.calc_serialized_size()];
node.serialize_into(&mut serialized).unwrap();
assert_eq!(&[3, 0], &serialized[0..2]);
assert_eq!(&5u64.to_le_bytes(), &serialized[2..10]);
assert_eq!(&15u64.to_le_bytes(), &serialized[10..18]);
assert_eq!(&25u64.to_le_bytes(), &serialized[18..26]);
assert_eq!(&[4, 0], &serialized[26..28]);
assert_eq!(&1000u64.to_le_bytes(), &serialized[28..36]);
assert_eq!(&2000u64.to_le_bytes(), &serialized[36..44]);
assert_eq!(&3000u64.to_le_bytes(), &serialized[44..52]);
assert_eq!(&4000u64.to_le_bytes(), &serialized[52..60]);
let deserialized = FreeListTsnInternalNode::from_slice(&serialized)
.expect("Failed to deserialize FreeListTsnInternalNode");
assert_eq!(node, deserialized);
assert_eq!(3, deserialized.keys.len());
assert_eq!(PageID(5), deserialized.keys[0]);
assert_eq!(PageID(15), deserialized.keys[1]);
assert_eq!(PageID(25), deserialized.keys[2]);
assert_eq!(4, deserialized.child_ids.len());
assert_eq!(PageID(1000), deserialized.child_ids[0]);
assert_eq!(PageID(2000), deserialized.child_ids[1]);
assert_eq!(PageID(3000), deserialized.child_ids[2]);
assert_eq!(PageID(4000), deserialized.child_ids[3]);
}
}