small_db/btree/page/
root_pointer_page.rs

1use log::debug;
2
3use super::{
4    BTreeBasePage, BTreePage, BTreePageID, PageCategory,
5    EMPTY_PAGE_ID,
6};
7use crate::{
8    btree::{page_cache::PageCache, tuple::Schema},
9    io::{SmallReader, SmallWriter, Vaporizable},
10};
11
12/// # Binary Layout
13///
14/// - 4 bytes: page category
15/// - 4 bytes: root page index
16/// - 4 bytes: root page category (leaf/internal)
17/// - 4 bytes: header page index
18pub struct BTreeRootPointerPage {
19    base: BTreeBasePage,
20
21    /// The type of this field is `BTreePageID` instead of
22    /// `Option<BTreePageID>` because the root page is always
23    /// present in the B+ tree.
24    ///
25    /// This decision also simplified the code.
26    root_pid: BTreePageID,
27
28    /// TODO: mandatory the presence of a header page?
29    header_page_index: u32,
30
31    /// Migrated from java version.
32    ///
33    /// TODO: Figure out what this is used for, and if it's needed.
34    old_data: Vec<u8>,
35}
36
37impl BTreeRootPointerPage {
38    fn new(pid: &BTreePageID, bytes: &[u8]) -> Self {
39        let mut reader = SmallReader::new(&bytes);
40
41        // read page category
42        let page_category = PageCategory::read_from(&mut reader);
43        if page_category != PageCategory::RootPointer {
44            panic!("invalid page category: {:?}", page_category);
45        }
46
47        // read root page index
48        let root_page_index = u32::read_from(&mut reader);
49
50        // read root page category
51        let root_page_category = PageCategory::read_from(&mut reader);
52
53        // read header page index
54        let header_page_index = u32::read_from(&mut reader);
55
56        let root_pid = BTreePageID {
57            category: root_page_category,
58            page_index: root_page_index,
59            table_id: pid.get_table_id(),
60        };
61
62        let mut instance = Self {
63            base: BTreeBasePage::new(pid),
64            root_pid,
65            header_page_index,
66            old_data: Vec::new(),
67        };
68
69        instance.set_before_image();
70        return instance;
71    }
72
73    pub fn new_empty_page(pid: &BTreePageID) -> Self {
74        // set the root pid to 1
75        let root_pid = BTreePageID {
76            category: PageCategory::Leaf,
77            page_index: 1,
78            table_id: pid.get_table_id(),
79        };
80
81        Self {
82            base: BTreeBasePage::new(pid),
83            root_pid,
84            header_page_index: EMPTY_PAGE_ID,
85            old_data: Vec::new(),
86        }
87    }
88
89    pub fn get_root_pid(&self) -> BTreePageID {
90        self.root_pid
91    }
92
93    pub fn set_root_pid(&mut self, pid: &BTreePageID) {
94        self.root_pid = *pid;
95    }
96
97    /// Get the id of the first header page
98    pub fn get_header_pid(&self) -> Option<BTreePageID> {
99        if self.header_page_index == EMPTY_PAGE_ID {
100            None
101        } else {
102            Some(BTreePageID::new(
103                PageCategory::Header,
104                self.get_pid().table_id,
105                self.header_page_index,
106            ))
107        }
108    }
109
110    /// Set the page id of the first header page
111    pub fn set_header_pid(&mut self, pid: &BTreePageID) {
112        self.header_page_index = pid.page_index;
113    }
114}
115
116impl BTreePage for BTreeRootPointerPage {
117    fn new(
118        pid: &BTreePageID,
119        bytes: &[u8],
120        _tuple_scheme: &Schema,
121        _key_field: usize,
122    ) -> Self {
123        Self::new(pid, bytes)
124    }
125
126    fn get_pid(&self) -> BTreePageID {
127        self.base.get_pid()
128    }
129
130    fn get_parent_pid(&self) -> BTreePageID {
131        self.base.get_parent_pid()
132    }
133
134    fn set_parent_pid(&mut self, pid: &BTreePageID) {
135        self.base.set_parent_pid(pid)
136    }
137
138    fn get_page_data(&self) -> Vec<u8> {
139        let mut writer = SmallWriter::new();
140
141        // write page category
142        writer.write(&self.get_pid().category);
143
144        // write root page index
145        writer.write(&self.root_pid.page_index);
146
147        // write root page category
148        writer.write(&self.root_pid.category);
149
150        // write header page index
151        writer.write(&self.header_page_index);
152
153        return writer.to_padded_bytes(PageCache::get_page_size());
154    }
155
156    fn set_before_image(&mut self) {
157        self.old_data = self.get_page_data();
158    }
159
160    fn get_before_image(&self) -> Vec<u8> {
161        if self.old_data.is_empty() {
162            panic!("no before image");
163        }
164        return self.old_data.clone();
165    }
166
167    fn peek(&self) {
168        debug!("BTreeRootPointerPage {{");
169        debug!("  pid: {:?}", self.get_pid());
170        debug!("  root_pid: {:?}", self.root_pid);
171        debug!("  header_page_index: {}", self.header_page_index);
172        debug!("}}");
173    }
174}