From 0828a60e9cd6d56e2d2322b2e2dfb1f7f5b85e14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=9E=97=E4=BC=9F?= Date: Wed, 7 Feb 2024 17:02:23 +0800 Subject: [PATCH] Split BPlusTreePageCodec --- bustubx/src/storage/codec/index_page.rs | 198 ++++++++++++++++-------- bustubx/src/storage/codec/mod.rs | 4 +- 2 files changed, 133 insertions(+), 69 deletions(-) diff --git a/bustubx/src/storage/codec/index_page.rs b/bustubx/src/storage/codec/index_page.rs index 63738ed..b72b7be 100644 --- a/bustubx/src/storage/codec/index_page.rs +++ b/bustubx/src/storage/codec/index_page.rs @@ -12,31 +12,8 @@ pub struct BPlusTreePageCodec; impl BPlusTreePageCodec { pub fn encode(page: &BPlusTreePage) -> Vec { match page { - BPlusTreePage::Leaf(page) => { - let mut bytes = vec![]; - bytes.extend(BPlusTreeLeafPageHeaderCodec::encode(&page.header)); - for (tuple, rid) in page.array.iter() { - bytes.extend(TupleCodec::encode(tuple)); - bytes.extend(RidCodec::encode(rid)); - } - // make sure length of bytes is BUSTUBX_PAGE_SIZE - assert!(bytes.len() <= BUSTUBX_PAGE_SIZE); - bytes.extend(vec![0; BUSTUBX_PAGE_SIZE - bytes.len()]); - bytes - } - - BPlusTreePage::Internal(page) => { - let mut bytes = vec![]; - bytes.extend(BPlusTreeInternalPageHeaderCodec::encode(&page.header)); - for (tuple, page_id) in page.array.iter() { - bytes.extend(TupleCodec::encode(tuple)); - bytes.extend(CommonCodec::encode_u32(*page_id)); - } - // make sure length of bytes is BUSTUBX_PAGE_SIZE - assert!(bytes.len() <= BUSTUBX_PAGE_SIZE); - bytes.extend(vec![0; BUSTUBX_PAGE_SIZE - bytes.len()]); - bytes - } + BPlusTreePage::Leaf(page) => BPlusTreeLeafPageCodec::encode(page), + BPlusTreePage::Internal(page) => BPlusTreeInternalPageCodec::encode(page), } } @@ -48,60 +25,145 @@ impl BPlusTreePageCodec { bytes.len() ))); } - let mut left_bytes = bytes; // not consume left_bytes - let (page_type, offset) = BPlusTreePageTypeCodec::decode(left_bytes)?; + let (page_type, _) = BPlusTreePageTypeCodec::decode(bytes)?; match page_type { BPlusTreePageType::LeafPage => { - let (header, offset) = BPlusTreeLeafPageHeaderCodec::decode(left_bytes)?; + let (page, offset) = BPlusTreeLeafPageCodec::decode(bytes, schema.clone())?; + Ok((BPlusTreePage::Leaf(page), offset)) + } + BPlusTreePageType::InternalPage => { + let (page, offset) = BPlusTreeInternalPageCodec::decode(bytes, schema.clone())?; + Ok((BPlusTreePage::Internal(page), offset)) + } + } + } +} + +pub struct BPlusTreeLeafPageCodec; + +impl BPlusTreeLeafPageCodec { + pub fn encode(page: &BPlusTreeLeafPage) -> Vec { + let mut bytes = vec![]; + bytes.extend(BPlusTreeLeafPageHeaderCodec::encode(&page.header)); + for (tuple, rid) in page.array.iter() { + bytes.extend(TupleCodec::encode(tuple)); + bytes.extend(RidCodec::encode(rid)); + } + // make sure length of bytes is BUSTUBX_PAGE_SIZE + assert!(bytes.len() <= BUSTUBX_PAGE_SIZE); + bytes.extend(vec![0; BUSTUBX_PAGE_SIZE - bytes.len()]); + bytes + } + + pub fn decode( + bytes: &[u8], + schema: SchemaRef, + ) -> BustubxResult> { + if bytes.len() != BUSTUBX_PAGE_SIZE { + return Err(BustubxError::Storage(format!( + "Index page size is not {} instead of {}", + BUSTUBX_PAGE_SIZE, + bytes.len() + ))); + } + let mut left_bytes = bytes; + + // not consume left_bytes + let (page_type, _) = BPlusTreePageTypeCodec::decode(left_bytes)?; + + if matches!(page_type, BPlusTreePageType::LeafPage) { + let (header, offset) = BPlusTreeLeafPageHeaderCodec::decode(left_bytes)?; + left_bytes = &left_bytes[offset..]; + + let mut array = vec![]; + for _ in 0..header.current_size { + let (tuple, offset) = TupleCodec::decode(left_bytes, schema.clone())?; left_bytes = &left_bytes[offset..]; - let mut array = vec![]; - for _ in 0..header.current_size { - let (tuple, offset) = TupleCodec::decode(left_bytes, schema.clone())?; - left_bytes = &left_bytes[offset..]; - - let (rid, offset) = RidCodec::decode(left_bytes)?; - left_bytes = &left_bytes[offset..]; - - array.push((tuple, rid)); - } - - Ok(( - BPlusTreePage::Leaf(BPlusTreeLeafPage { - schema, - header, - array, - }), - BUSTUBX_PAGE_SIZE, - )) + let (rid, offset) = RidCodec::decode(left_bytes)?; + left_bytes = &left_bytes[offset..]; + + array.push((tuple, rid)); } - BPlusTreePageType::InternalPage => { - let (header, offset) = BPlusTreeInternalPageHeaderCodec::decode(left_bytes)?; + + Ok(( + BPlusTreeLeafPage { + schema, + header, + array, + }, + BUSTUBX_PAGE_SIZE, + )) + } else { + Err(BustubxError::Storage( + "Index page type must be leaf page".to_string(), + )) + } + } +} + +pub struct BPlusTreeInternalPageCodec; + +impl BPlusTreeInternalPageCodec { + pub fn encode(page: &BPlusTreeInternalPage) -> Vec { + let mut bytes = vec![]; + bytes.extend(BPlusTreeInternalPageHeaderCodec::encode(&page.header)); + for (tuple, page_id) in page.array.iter() { + bytes.extend(TupleCodec::encode(tuple)); + bytes.extend(CommonCodec::encode_u32(*page_id)); + } + // make sure length of bytes is BUSTUBX_PAGE_SIZE + assert!(bytes.len() <= BUSTUBX_PAGE_SIZE); + bytes.extend(vec![0; BUSTUBX_PAGE_SIZE - bytes.len()]); + bytes + } + + pub fn decode( + bytes: &[u8], + schema: SchemaRef, + ) -> BustubxResult> { + if bytes.len() != BUSTUBX_PAGE_SIZE { + return Err(BustubxError::Storage(format!( + "Index page size is not {} instead of {}", + BUSTUBX_PAGE_SIZE, + bytes.len() + ))); + } + let mut left_bytes = bytes; + + // not consume left_bytes + let (page_type, _) = BPlusTreePageTypeCodec::decode(left_bytes)?; + + if matches!(page_type, BPlusTreePageType::InternalPage) { + let (header, offset) = BPlusTreeInternalPageHeaderCodec::decode(left_bytes)?; + left_bytes = &left_bytes[offset..]; + + let mut array = vec![]; + for _ in 0..header.current_size { + let (tuple, offset) = TupleCodec::decode(left_bytes, schema.clone())?; left_bytes = &left_bytes[offset..]; - let mut array = vec![]; - for _ in 0..header.current_size { - let (tuple, offset) = TupleCodec::decode(left_bytes, schema.clone())?; - left_bytes = &left_bytes[offset..]; - - let (page_id, offset) = CommonCodec::decode_u32(left_bytes)?; - left_bytes = &left_bytes[offset..]; - - array.push((tuple, page_id)); - } - - Ok(( - BPlusTreePage::Internal(BPlusTreeInternalPage { - schema, - header, - array, - }), - BUSTUBX_PAGE_SIZE, - )) + let (page_id, offset) = CommonCodec::decode_u32(left_bytes)?; + left_bytes = &left_bytes[offset..]; + + array.push((tuple, page_id)); } + + Ok(( + BPlusTreeInternalPage { + schema, + header, + array, + }, + BUSTUBX_PAGE_SIZE, + )) + } else { + Err(BustubxError::Storage( + "Index page type must be internal page".to_string(), + )) } } } diff --git a/bustubx/src/storage/codec/mod.rs b/bustubx/src/storage/codec/mod.rs index 0dbbb5a..b2ce8e4 100644 --- a/bustubx/src/storage/codec/mod.rs +++ b/bustubx/src/storage/codec/mod.rs @@ -5,7 +5,9 @@ mod table_page; mod tuple; pub use common::CommonCodec; -pub use index_page::BPlusTreePageTypeCodec; +pub use index_page::{ + BPlusTreeInternalPageCodec, BPlusTreeLeafPageCodec, BPlusTreePageCodec, BPlusTreePageTypeCodec, +}; pub use scalar::ScalarValueCodec; pub use table_page::{ RidCodec, TablePageCodec, TablePageHeaderCodec, TablePageHeaderTupleInfoCodec,