small_db/btree/page/
header_page.rs

1use bit_vec::BitVec;
2use log::debug;
3
4use super::{BTreeBasePage, BTreePage, BTreePageID, PageCategory};
5use crate::{
6    btree::{page_cache::PageCache, tuple::Schema},
7    io::{SmallReader, SmallWriter, Vaporizable},
8};
9
10/// # Binary Layout
11///
12/// - 4 bytes: page category
13/// - n bytes: header
14pub struct BTreeHeaderPage {
15    base: BTreeBasePage,
16
17    // indicate slots' status: true means occupied, false means empty
18    header: BitVec<u32>,
19
20    slot_count: usize,
21
22    old_data: Vec<u8>,
23}
24
25impl BTreeHeaderPage {
26    pub fn new(pid: &BTreePageID, bytes: &[u8]) -> BTreeHeaderPage {
27        let mut instance: Self;
28
29        if BTreeBasePage::is_empty_page(&bytes) {
30            instance = Self::new_empty_page(pid);
31        } else {
32            let mut reader = SmallReader::new(&bytes);
33
34            // read page category
35            let page_category = PageCategory::read_from(&mut reader);
36            if page_category != PageCategory::Header {
37                panic!("invalid page category: {:?}", page_category);
38            }
39
40            // read header
41            let header = BitVec::read_from(&mut reader);
42
43            let slot_count = header.len();
44
45            instance = BTreeHeaderPage {
46                base: BTreeBasePage::new(pid),
47                header,
48                slot_count,
49                old_data: Vec::new(),
50            };
51        }
52
53        instance.set_before_image();
54        return instance;
55    }
56
57    pub fn new_empty_page(pid: &BTreePageID) -> BTreeHeaderPage {
58        let slot_count = 1000;
59
60        let mut header = BitVec::new();
61        header.grow(slot_count, false);
62
63        BTreeHeaderPage {
64            base: BTreeBasePage::new(pid),
65            header,
66            slot_count,
67            old_data: Vec::new(),
68        }
69    }
70
71    // mark the slot as empty/filled.
72    pub fn mark_slot_status(
73        &mut self,
74        slot_index: usize,
75        used: bool,
76    ) {
77        self.header.set(slot_index, used);
78    }
79
80    pub fn get_slots_count(&self) -> usize {
81        self.slot_count
82    }
83
84    pub fn get_empty_slot(&self) -> Option<u32> {
85        for i in 0..self.slot_count {
86            if !self.header[i] {
87                return Some(i as u32);
88            }
89        }
90        None
91    }
92}
93
94impl BTreePage for BTreeHeaderPage {
95    fn new(
96        pid: &BTreePageID,
97        bytes: &[u8],
98        _tuple_scheme: &Schema,
99        _key_field: usize,
100    ) -> Self {
101        Self::new(pid, bytes)
102    }
103
104    fn get_pid(&self) -> BTreePageID {
105        self.base.get_pid()
106    }
107
108    fn get_parent_pid(&self) -> BTreePageID {
109        self.base.get_parent_pid()
110    }
111
112    fn set_parent_pid(&mut self, pid: &BTreePageID) {
113        self.base.set_parent_pid(pid)
114    }
115
116    fn get_page_data(&self) -> Vec<u8> {
117        let mut writer = SmallWriter::new();
118
119        // write page category
120        writer.write(&self.get_pid().category);
121
122        // write header
123        writer.write(&self.header);
124
125        return writer.to_padded_bytes(PageCache::get_page_size());
126    }
127
128    fn set_before_image(&mut self) {
129        self.old_data = self.get_page_data();
130    }
131
132    fn get_before_image(&self) -> Vec<u8> {
133        if self.old_data.is_empty() {
134            panic!("before image is not set");
135        }
136        return self.old_data.clone();
137    }
138
139    fn peek(&self) {
140        debug!("header page: {:?}", self.get_pid())
141    }
142}