quill_sql/storage/page/
meta_page.rs1use crate::buffer::{PageId, INVALID_PAGE_ID, PAGE_SIZE};
2use crate::error::{QuillSQLError, QuillSQLResult};
3use crate::storage::codec::CommonCodec;
4use std::sync::LazyLock;
5
6pub static EMPTY_META_PAGE: MetaPage = MetaPage {
7 major_version: 0,
8 minor_version: 0,
9 freelist_page_id: 0,
10 information_schema_schemas_first_page_id: 0,
11 information_schema_tables_first_page_id: 0,
12 information_schema_columns_first_page_id: 0,
13 information_schema_indexes_first_page_id: 0,
14};
15
16pub static META_PAGE_SIZE: LazyLock<usize> = LazyLock::new(|| PAGE_SIZE);
17
18#[derive(Debug, Eq, PartialEq)]
19pub struct MetaPage {
20 pub major_version: u32,
21 pub minor_version: u32,
22 pub freelist_page_id: PageId,
23 pub information_schema_schemas_first_page_id: PageId,
24 pub information_schema_tables_first_page_id: PageId,
25 pub information_schema_columns_first_page_id: PageId,
26 pub information_schema_indexes_first_page_id: PageId,
27}
28
29impl MetaPage {
30 pub fn try_new() -> QuillSQLResult<Self> {
31 let version_str = env!("CARGO_PKG_VERSION");
32 let version_arr = version_str.split('.').collect::<Vec<&str>>();
33 if version_arr.len() < 2 {
34 return Err(QuillSQLError::Storage(format!(
35 "Package version is not xx.xx {}",
36 version_str
37 )));
38 }
39 let major_version = version_arr[0].parse::<u32>().map_err(|_| {
40 QuillSQLError::Storage(format!("Failed to parse major version {}", version_arr[0]))
41 })?;
42 let minor_version = version_arr[1].parse::<u32>().map_err(|_| {
43 QuillSQLError::Storage(format!("Failed to parse minor version {}", version_arr[1]))
44 })?;
45
46 Ok(Self {
47 major_version,
48 minor_version,
49 freelist_page_id: INVALID_PAGE_ID,
50 information_schema_schemas_first_page_id: INVALID_PAGE_ID,
51 information_schema_tables_first_page_id: INVALID_PAGE_ID,
52 information_schema_columns_first_page_id: INVALID_PAGE_ID,
53 information_schema_indexes_first_page_id: INVALID_PAGE_ID,
54 })
55 }
56}
57
58pub fn encode_meta_page(page: &MetaPage) -> Vec<u8> {
59 let mut bytes = Vec::with_capacity(PAGE_SIZE);
60 bytes.extend(CommonCodec::encode_u32(page.major_version));
61 bytes.extend(CommonCodec::encode_u32(page.minor_version));
62 bytes.extend(CommonCodec::encode_u32(page.freelist_page_id));
63 bytes.extend(CommonCodec::encode_u32(
64 page.information_schema_schemas_first_page_id,
65 ));
66 bytes.extend(CommonCodec::encode_u32(
67 page.information_schema_tables_first_page_id,
68 ));
69 bytes.extend(CommonCodec::encode_u32(
70 page.information_schema_columns_first_page_id,
71 ));
72 bytes.extend(CommonCodec::encode_u32(
73 page.information_schema_indexes_first_page_id,
74 ));
75 bytes.resize(PAGE_SIZE, 0);
76 bytes
77}
78
79pub fn decode_meta_page(bytes: &[u8]) -> QuillSQLResult<(MetaPage, usize)> {
80 if bytes.len() != PAGE_SIZE {
81 return Err(QuillSQLError::Storage(format!(
82 "Meta page size is not {} instead of {}",
83 PAGE_SIZE,
84 bytes.len()
85 )));
86 }
87
88 let mut left_bytes = bytes;
89
90 let (major_version, offset) = CommonCodec::decode_u32(left_bytes)?;
91 left_bytes = &left_bytes[offset..];
92 let (minor_version, offset) = CommonCodec::decode_u32(left_bytes)?;
93 left_bytes = &left_bytes[offset..];
94 let (freelist_page_id, offset) = CommonCodec::decode_u32(left_bytes)?;
95 left_bytes = &left_bytes[offset..];
96 let (information_schema_schemas_first_page_id, offset) = CommonCodec::decode_u32(left_bytes)?;
97 left_bytes = &left_bytes[offset..];
98 let (information_schema_tables_first_page_id, offset) = CommonCodec::decode_u32(left_bytes)?;
99 left_bytes = &left_bytes[offset..];
100 let (information_schema_columns_first_page_id, offset) = CommonCodec::decode_u32(left_bytes)?;
101 left_bytes = &left_bytes[offset..];
102 let (information_schema_indexes_first_page_id, offset) = CommonCodec::decode_u32(left_bytes)?;
103 left_bytes = &left_bytes[offset..];
104
105 Ok((
106 MetaPage {
107 major_version,
108 minor_version,
109 freelist_page_id,
110 information_schema_schemas_first_page_id,
111 information_schema_tables_first_page_id,
112 information_schema_columns_first_page_id,
113 information_schema_indexes_first_page_id,
114 },
115 PAGE_SIZE - left_bytes.len(),
116 ))
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn meta_page_codec_roundtrip() {
125 let page = MetaPage::try_new().unwrap();
126 let (decoded, _) = decode_meta_page(&encode_meta_page(&page)).unwrap();
127 assert_eq!(page, decoded);
128 }
129}