diff --git a/bustubx/src/storage/codec/index_page.rs b/bustubx/src/storage/codec/index_page.rs new file mode 100644 index 0000000..db8ac3e --- /dev/null +++ b/bustubx/src/storage/codec/index_page.rs @@ -0,0 +1,23 @@ +use crate::storage::codec::{CommonCodec, DecodedData}; +use crate::storage::index_page::BPlusTreePageType; +use crate::{BustubxError, BustubxResult}; + +pub struct BPlusTreePageTypeCodec; + +impl BPlusTreePageTypeCodec { + pub fn encode(page_type: &BPlusTreePageType) -> Vec { + match page_type { + BPlusTreePageType::LeafPage => CommonCodec::encode_u32(1), + BPlusTreePageType::InternalPage => CommonCodec::encode_u32(2), + } + } + + pub fn decode(bytes: &[u8]) -> BustubxResult> { + let (flag, offset) = CommonCodec::decode_u32(bytes)?; + match flag { + 1 => Ok((BPlusTreePageType::LeafPage, offset)), + 2 => Ok((BPlusTreePageType::InternalPage, offset)), + _ => Err(BustubxError::Storage("Invalid page type".to_string())), + } + } +} diff --git a/bustubx/src/storage/codec/mod.rs b/bustubx/src/storage/codec/mod.rs index d1c8538..bc742ca 100644 --- a/bustubx/src/storage/codec/mod.rs +++ b/bustubx/src/storage/codec/mod.rs @@ -1,9 +1,11 @@ mod common; +mod index_page; mod scalar; mod table_page; mod tuple; pub use common::CommonCodec; +pub use index_page::BPlusTreePageTypeCodec; pub use scalar::ScalarValueCodec; pub use table_page::{TablePageCodec, TablePageHeaderCodec, TablePageHeaderTupleInfoCodec}; pub use tuple::TupleCodec; diff --git a/bustubx/src/storage/codec/table_page.rs b/bustubx/src/storage/codec/table_page.rs index 57a73c7..c9f14c5 100644 --- a/bustubx/src/storage/codec/table_page.rs +++ b/bustubx/src/storage/codec/table_page.rs @@ -3,7 +3,7 @@ use crate::catalog::SchemaRef; use crate::storage::codec::{CommonCodec, DecodedData}; use crate::storage::table_page::{TablePageHeader, TupleInfo}; use crate::storage::{TablePage, TupleMeta}; -use crate::BustubxResult; +use crate::{BustubxError, BustubxResult}; pub struct TablePageCodec; @@ -16,6 +16,13 @@ impl TablePageCodec { } pub fn decode(bytes: &[u8], schema: SchemaRef) -> BustubxResult> { + if bytes.len() != BUSTUBX_PAGE_SIZE { + return Err(BustubxError::Storage(format!( + "Table page size is not {} instead of {}", + BUSTUBX_PAGE_SIZE, + bytes.len() + ))); + } let (header, offset) = TablePageHeaderCodec::decode(bytes)?; let mut data = [0u8; BUSTUBX_PAGE_SIZE]; data.copy_from_slice(&bytes[0..BUSTUBX_PAGE_SIZE]); diff --git a/bustubx/src/storage/index_page.rs b/bustubx/src/storage/index_page.rs index d6fb96a..4d64d72 100644 --- a/bustubx/src/storage/index_page.rs +++ b/bustubx/src/storage/index_page.rs @@ -3,6 +3,7 @@ use std::mem::size_of; use super::Tuple; use crate::buffer::{PageId, BUSTUBX_PAGE_SIZE, INVALID_PAGE_ID}; use crate::catalog::SchemaRef; +use crate::storage::codec::BPlusTreePageTypeCodec; use crate::{catalog::Schema, common::rid::Rid}; pub const INTERNAL_PAGE_HEADER_SIZE: usize = 4 + 4 + 4; @@ -25,7 +26,6 @@ impl BPlusTreePage { BPlusTreePageType::LeafPage => { Self::Leaf(BPlusTreeLeafPage::from_bytes(raw, key_schema.clone())) } - BPlusTreePageType::InvalidPage => panic!("Invalid b+ tree page type"), }; } pub fn to_bytes(&self) -> [u8; BUSTUBX_PAGE_SIZE] { @@ -71,14 +71,12 @@ impl BPlusTreePage { #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BPlusTreePageType { - InvalidPage, LeafPage, InternalPage, } impl BPlusTreePageType { pub fn from_bytes(raw: &[u8; 4]) -> Self { match u32::from_be_bytes(*raw) { - 0 => Self::InvalidPage, 1 => Self::LeafPage, 2 => Self::InternalPage, _ => panic!("Invalid page type"), @@ -86,7 +84,6 @@ impl BPlusTreePageType { } pub fn to_bytes(&self) -> [u8; 4] { match self { - Self::InvalidPage => 0u32.to_be_bytes(), Self::LeafPage => 1u32.to_be_bytes(), Self::InternalPage => 2u32.to_be_bytes(), } @@ -322,7 +319,7 @@ impl BPlusTreeInternalPage { } pub fn from_bytes(raw: &[u8; BUSTUBX_PAGE_SIZE], key_schema: SchemaRef) -> Self { - let page_type = BPlusTreePageType::from_bytes(&raw[0..4].try_into().unwrap()); + let (page_type, _) = BPlusTreePageTypeCodec::decode(raw).unwrap(); let current_size = u32::from_be_bytes(raw[4..8].try_into().unwrap()); let max_size = u32::from_be_bytes(raw[8..12].try_into().unwrap()); let mut array = Vec::with_capacity(max_size as usize); @@ -347,7 +344,7 @@ impl BPlusTreeInternalPage { pub fn to_bytes(&self) -> [u8; BUSTUBX_PAGE_SIZE] { let mut buf = [0; BUSTUBX_PAGE_SIZE]; - buf[0..4].copy_from_slice(&self.page_type.to_bytes()); + buf[0..4].copy_from_slice(&BPlusTreePageTypeCodec::encode(&self.page_type)); buf[4..8].copy_from_slice(&self.current_size.to_be_bytes()); buf[8..12].copy_from_slice(&self.max_size.to_be_bytes()); if self.current_size == 0 { diff --git a/bustubx/src/storage/table_page.rs b/bustubx/src/storage/table_page.rs index bf7f148..06b68f5 100644 --- a/bustubx/src/storage/table_page.rs +++ b/bustubx/src/storage/table_page.rs @@ -39,7 +39,6 @@ pub struct TablePage { pub schema: SchemaRef, pub header: TablePageHeader, // 整个页原始数据 - // TODO 可以通过memmove、memcpy优化,参考bustub pub data: [u8; BUSTUBX_PAGE_SIZE], }