diff --git a/bustubx/src/storage/codec/mod.rs b/bustubx/src/storage/codec/mod.rs index a164796..d1c8538 100644 --- a/bustubx/src/storage/codec/mod.rs +++ b/bustubx/src/storage/codec/mod.rs @@ -5,7 +5,7 @@ mod tuple; pub use common::CommonCodec; pub use scalar::ScalarValueCodec; -pub use table_page::TablePageCodec; +pub use table_page::{TablePageCodec, TablePageHeaderCodec, TablePageHeaderTupleInfoCodec}; pub use tuple::TupleCodec; // data + consumed offset diff --git a/bustubx/src/storage/codec/table_page.rs b/bustubx/src/storage/codec/table_page.rs index 2e09ade..57a73c7 100644 --- a/bustubx/src/storage/codec/table_page.rs +++ b/bustubx/src/storage/codec/table_page.rs @@ -39,11 +39,7 @@ impl TablePageHeaderCodec { bytes.extend(CommonCodec::encode_u16(header.num_tuples)); bytes.extend(CommonCodec::encode_u16(header.num_deleted_tuples)); for tuple_info in header.tuple_infos.iter() { - bytes.extend(CommonCodec::encode_u16(tuple_info.offset)); - bytes.extend(CommonCodec::encode_u16(tuple_info.size)); - bytes.extend(CommonCodec::encode_u32(tuple_info.meta.insert_txn_id)); - bytes.extend(CommonCodec::encode_u32(tuple_info.meta.delete_txn_id)); - bytes.extend(CommonCodec::encode_bool(tuple_info.meta.is_deleted)); + bytes.extend(TablePageHeaderTupleInfoCodec::encode(tuple_info)); } bytes } @@ -62,25 +58,9 @@ impl TablePageHeaderCodec { let mut tuple_infos = vec![]; for _ in 0..num_tuples { - let (tuple_offset, offset) = CommonCodec::decode_u16(left_bytes)?; + let (tuple_info, offset) = TablePageHeaderTupleInfoCodec::decode(left_bytes)?; left_bytes = &left_bytes[offset..]; - let (size, offset) = CommonCodec::decode_u16(left_bytes)?; - left_bytes = &left_bytes[offset..]; - let (insert_txn_id, offset) = CommonCodec::decode_u32(left_bytes)?; - left_bytes = &left_bytes[offset..]; - let (delete_txn_id, offset) = CommonCodec::decode_u32(left_bytes)?; - left_bytes = &left_bytes[offset..]; - let (is_deleted, offset) = CommonCodec::decode_bool(left_bytes)?; - left_bytes = &left_bytes[offset..]; - tuple_infos.push(TupleInfo { - offset: tuple_offset, - size, - meta: TupleMeta { - insert_txn_id, - delete_txn_id, - is_deleted, - }, - }); + tuple_infos.push(tuple_info); } Ok(( TablePageHeader { @@ -94,6 +74,46 @@ impl TablePageHeaderCodec { } } +pub struct TablePageHeaderTupleInfoCodec; + +impl TablePageHeaderTupleInfoCodec { + pub fn encode(tuple_info: &TupleInfo) -> Vec { + let mut bytes = Vec::new(); + bytes.extend(CommonCodec::encode_u16(tuple_info.offset)); + bytes.extend(CommonCodec::encode_u16(tuple_info.size)); + bytes.extend(CommonCodec::encode_u32(tuple_info.meta.insert_txn_id)); + bytes.extend(CommonCodec::encode_u32(tuple_info.meta.delete_txn_id)); + bytes.extend(CommonCodec::encode_bool(tuple_info.meta.is_deleted)); + bytes + } + + pub fn decode(bytes: &[u8]) -> BustubxResult> { + let mut left_bytes = bytes; + let (tuple_offset, offset) = CommonCodec::decode_u16(left_bytes)?; + left_bytes = &left_bytes[offset..]; + let (size, offset) = CommonCodec::decode_u16(left_bytes)?; + left_bytes = &left_bytes[offset..]; + let (insert_txn_id, offset) = CommonCodec::decode_u32(left_bytes)?; + left_bytes = &left_bytes[offset..]; + let (delete_txn_id, offset) = CommonCodec::decode_u32(left_bytes)?; + left_bytes = &left_bytes[offset..]; + let (is_deleted, offset) = CommonCodec::decode_bool(left_bytes)?; + left_bytes = &left_bytes[offset..]; + Ok(( + TupleInfo { + offset: tuple_offset, + size, + meta: TupleMeta { + insert_txn_id, + delete_txn_id, + is_deleted, + }, + }, + bytes.len() - left_bytes.len(), + )) + } +} + #[cfg(test)] mod tests { use crate::buffer::INVALID_PAGE_ID; diff --git a/bustubx/src/storage/table_page.rs b/bustubx/src/storage/table_page.rs index dabccbc..bf7f148 100644 --- a/bustubx/src/storage/table_page.rs +++ b/bustubx/src/storage/table_page.rs @@ -1,12 +1,21 @@ -use crate::buffer::{PageId, BUSTUBX_PAGE_SIZE, INVALID_PAGE_ID}; +use crate::buffer::{PageId, BUSTUBX_PAGE_SIZE}; use crate::catalog::SchemaRef; use crate::common::rid::Rid; -use crate::storage::codec::{CommonCodec, TupleCodec}; +use crate::storage::codec::{TablePageHeaderCodec, TablePageHeaderTupleInfoCodec, TupleCodec}; use super::tuple::{Tuple, TupleMeta}; -pub const TABLE_PAGE_HEADER_SIZE: usize = 4 + 2 + 2; -pub const TABLE_PAGE_TUPLE_INFO_SIZE: usize = 2 + 2 + (4 + 4 + 4); +lazy_static::lazy_static! { + pub static ref EMPTY_TUPLE_INFO: TupleInfo = TupleInfo { + offset: 0, + size: 0, + meta: TupleMeta { + insert_txn_id: 0, + delete_txn_id: 0, + is_deleted: false, + } + }; +} /** * Slotted page format: @@ -21,7 +30,7 @@ pub const TABLE_PAGE_TUPLE_INFO_SIZE: usize = 2 + 2 + (4 + 4 + 4); * | NextPageId (4)| NumTuples(2) | NumDeletedTuples(2) | * ---------------------------------------------------------------------------- * ---------------------------------------------------------------- - * | Tuple_1 offset+size (4) + TupleMeta(12) | Tuple_2 offset+size (4) + TupleMeta(12) | ... | + * | Tuple_1 offset+size + TupleMeta | Tuple_2 offset+size + TupleMeta | ... | * ---------------------------------------------------------------- * */ @@ -42,7 +51,7 @@ impl TablePage { next_page_id, num_tuples: 0, num_deleted_tuples: 0, - tuple_infos: Vec::with_capacity(BUSTUBX_PAGE_SIZE / TABLE_PAGE_TUPLE_INFO_SIZE), + tuple_infos: Vec::new(), }, data: [0; BUSTUBX_PAGE_SIZE], } @@ -69,9 +78,9 @@ impl TablePage { // Calculate the minimum valid tuple insertion offset, including the table page header size, // the total size of each tuple info (existing tuple infos and newly added tuple info). - let min_tuple_offset = TABLE_PAGE_HEADER_SIZE as u16 - + (self.header.num_tuples as u16 + 1) * TABLE_PAGE_TUPLE_INFO_SIZE as u16; - if tuple_offset < min_tuple_offset { + let min_tuple_offset = TablePageHeaderCodec::encode(&self.header).len() + + TablePageHeaderTupleInfoCodec::encode(&EMPTY_TUPLE_INFO).len(); + if (tuple_offset as usize) < min_tuple_offset { return None; } @@ -173,9 +182,7 @@ pub struct TupleInfo { #[cfg(test)] mod tests { - use crate::buffer::BUSTUBX_PAGE_SIZE; use crate::catalog::{Column, DataType, Schema}; - use crate::storage::codec::{TablePageCodec, TupleCodec}; use crate::storage::Tuple; use std::sync::Arc;