reddb_server/storage/engine/page/
impl.rs1use super::*;
2
3impl Page {
4 pub fn new(page_type: PageType, page_id: u32) -> Self {
6 let mut page = Self {
7 data: [0u8; PAGE_SIZE],
8 };
9
10 let header = PageHeader::new(page_type, page_id);
11 page.set_header(&header);
12 page
13 }
14
15 pub fn from_bytes(data: [u8; PAGE_SIZE]) -> Self {
17 Self { data }
18 }
19
20 pub fn from_slice(slice: &[u8]) -> Result<Self, PageError> {
22 if slice.len() != PAGE_SIZE {
23 return Err(PageError::InvalidSize(slice.len()));
24 }
25 let mut data = [0u8; PAGE_SIZE];
26 data.copy_from_slice(slice);
27 Ok(Self { data })
28 }
29
30 #[inline]
32 pub fn as_bytes(&self) -> &[u8; PAGE_SIZE] {
33 &self.data
34 }
35
36 #[inline]
38 pub fn as_bytes_mut(&mut self) -> &mut [u8; PAGE_SIZE] {
39 &mut self.data
40 }
41
42 pub fn header(&self) -> Result<PageHeader, PageError> {
44 let header_bytes: [u8; HEADER_SIZE] = self.data[..HEADER_SIZE]
45 .try_into()
46 .expect("header size mismatch");
47 PageHeader::from_bytes(&header_bytes)
48 }
49
50 pub fn set_header(&mut self, header: &PageHeader) {
52 let bytes = header.to_bytes();
53 self.data[..HEADER_SIZE].copy_from_slice(&bytes);
54 }
55
56 pub fn page_type(&self) -> Result<PageType, PageError> {
58 let page_type = reddb_file::paged_page_type(&self.data);
59 PageType::from_u8(page_type).ok_or(PageError::InvalidPageType(page_type))
60 }
61
62 pub fn page_id(&self) -> u32 {
64 reddb_file::paged_page_id(&self.data)
65 }
66
67 pub fn lsn(&self) -> u64 {
76 reddb_file::paged_page_lsn(&self.data)
77 }
78
79 pub fn set_lsn(&mut self, lsn: u64) {
88 reddb_file::set_paged_page_lsn(&mut self.data, lsn);
89 }
90
91 pub fn cell_count(&self) -> u16 {
93 reddb_file::paged_page_cell_count(&self.data)
94 }
95
96 pub fn set_cell_count(&mut self, count: u16) {
98 reddb_file::set_paged_page_cell_count(&mut self.data, count);
99 }
100
101 pub fn parent_id(&self) -> u32 {
103 reddb_file::paged_page_parent_id(&self.data)
104 }
105
106 pub fn set_parent_id(&mut self, parent_id: u32) {
108 reddb_file::set_paged_page_parent_id(&mut self.data, parent_id);
109 }
110
111 pub fn right_child(&self) -> u32 {
113 reddb_file::paged_page_right_child(&self.data)
114 }
115
116 pub fn set_right_child(&mut self, child_id: u32) {
118 reddb_file::set_paged_page_right_child(&mut self.data, child_id);
119 }
120
121 pub fn free_start(&self) -> u16 {
123 reddb_file::paged_page_free_start(&self.data)
124 }
125
126 pub fn set_free_start(&mut self, offset: u16) {
128 reddb_file::set_paged_page_free_start(&mut self.data, offset);
129 }
130
131 pub fn free_end(&self) -> u16 {
133 reddb_file::paged_page_free_end(&self.data)
134 }
135
136 pub fn set_free_end(&mut self, offset: u16) {
138 reddb_file::set_paged_page_free_end(&mut self.data, offset);
139 }
140
141 #[inline]
143 pub fn content(&self) -> &[u8] {
144 &self.data[HEADER_SIZE..]
145 }
146
147 #[inline]
149 pub fn content_mut(&mut self) -> &mut [u8] {
150 &mut self.data[HEADER_SIZE..]
151 }
152
153 pub fn update_checksum(&mut self) {
155 reddb_file::clear_paged_page_checksum(&mut self.data);
157 let checksum = crc32(&self.data);
159 reddb_file::set_paged_page_checksum(&mut self.data, checksum);
161 }
162
163 pub fn verify_checksum(&self) -> Result<(), PageError> {
165 let stored = reddb_file::paged_page_checksum(&self.data);
166
167 let mut temp = self.data;
169 reddb_file::clear_paged_page_checksum(&mut temp);
170 let calculated = crc32(&temp);
171
172 if stored != calculated {
173 Err(PageError::ChecksumMismatch {
174 expected: stored,
175 actual: calculated,
176 })
177 } else {
178 Ok(())
179 }
180 }
181
182 pub fn get_cell_pointer(&self, index: usize) -> Result<u16, PageError> {
186 let count = self.cell_count() as usize;
187 if index >= count {
188 return Err(PageError::CellOutOfBounds(index));
189 }
190
191 reddb_file::paged_cell_pointer(&self.data, index).ok_or(PageError::CellOutOfBounds(index))
192 }
193
194 pub fn set_cell_pointer(&mut self, index: usize, pointer: u16) -> Result<(), PageError> {
196 if !reddb_file::paged_cell_pointer_is_valid(pointer) {
197 return Err(PageError::InvalidCellPointer(pointer));
198 }
199
200 if !reddb_file::set_paged_cell_pointer(&mut self.data, index, pointer) {
201 return Err(PageError::CellOutOfBounds(index));
202 }
203 Ok(())
204 }
205
206 pub fn get_cell(&self, index: usize) -> Result<&[u8], PageError> {
208 let pointer = self.get_cell_pointer(index)? as usize;
209
210 reddb_file::paged_cell_bytes(&self.data, pointer as u16)
211 .ok_or(PageError::InvalidCellPointer(pointer as u16))
212 }
213
214 pub fn insert_cell(&mut self, key: &[u8], value: &[u8]) -> Result<usize, PageError> {
218 let key_len = key.len();
219 let value_len = value.len();
220
221 if key_len > u16::MAX as usize {
223 return Err(PageError::OverflowRequired);
224 }
225
226 let cell_size =
227 reddb_file::paged_cell_len(key_len, value_len).ok_or(PageError::OverflowRequired)?;
228
229 if cell_size > CONTENT_SIZE - 2 {
231 return Err(PageError::OverflowRequired);
232 }
233
234 let mut header = self.header()?;
236
237 let space_needed = 2 + cell_size;
239 if header.free_space() < space_needed {
240 return Err(PageError::PageFull);
241 }
242
243 let cell_offset = header.free_end as usize - cell_size;
245
246 if !reddb_file::write_paged_cell(&mut self.data, cell_offset as u16, key, value) {
248 return Err(PageError::InvalidCellPointer(cell_offset as u16));
249 }
250
251 let cell_index = header.cell_count as usize;
253 if !reddb_file::set_paged_cell_pointer(&mut self.data, cell_index, cell_offset as u16) {
254 return Err(PageError::CellOutOfBounds(cell_index));
255 }
256
257 header.cell_count += 1;
259 header.free_start += 2;
260 header.free_end = cell_offset as u16;
261 header.set_flag(PageFlag::Dirty);
262 self.set_header(&header);
263
264 Ok(cell_index)
265 }
266
267 pub fn read_cell(&self, index: usize) -> Result<(Vec<u8>, Vec<u8>), PageError> {
269 let cell = self.get_cell(index)?;
270
271 let (key, value) =
272 reddb_file::paged_cell_key_value(cell).ok_or(PageError::InvalidCellPointer(0))?;
273
274 Ok((key.to_vec(), value.to_vec()))
275 }
276
277 pub fn search_key(&self, key: &[u8]) -> Result<usize, usize> {
281 let count = self.cell_count() as usize;
282 if count == 0 {
283 return Err(0);
284 }
285
286 let mut low = 0;
287 let mut high = count;
288
289 while low < high {
290 let mid = (low + high) / 2;
291 let (cell_key, _) = self.read_cell(mid).map_err(|_| mid)?;
292
293 match cell_key.as_slice().cmp(key) {
294 std::cmp::Ordering::Less => low = mid + 1,
295 std::cmp::Ordering::Greater => high = mid,
296 std::cmp::Ordering::Equal => return Ok(mid),
297 }
298 }
299
300 Err(low)
301 }
302
303 pub fn new_header_page(page_count: u32) -> Self {
305 let mut page = Self::new(PageType::Header, 0);
306
307 reddb_file::init_database_header_page(&mut page.data, page_count)
308 .expect("fixed-size page can hold database header");
309
310 page.update_checksum();
311 page
312 }
313
314 pub fn read_page_count(&self) -> u32 {
316 reddb_file::database_header_page_count(&self.data).expect("fixed-size page has page count")
317 }
318
319 pub fn write_page_count(&mut self, count: u32) {
321 reddb_file::set_database_header_page_count(&mut self.data, count)
322 .expect("fixed-size page has page count");
323 }
324
325 pub fn read_freelist_head(&self) -> u32 {
327 reddb_file::database_header_freelist_head(&self.data)
328 .expect("fixed-size page has freelist head")
329 }
330
331 pub fn write_freelist_head(&mut self, page_id: u32) {
333 reddb_file::set_database_header_freelist_head(&mut self.data, page_id)
334 .expect("fixed-size page has freelist head");
335 }
336
337 pub fn verify_header_page(&self) -> Result<(), PageError> {
339 if !reddb_file::database_header_magic_matches(&self.data) {
341 return Err(PageError::InvalidPageType(self.data[0]));
342 }
343
344 let stored_page_size = reddb_file::database_header_page_size(&self.data)
346 .map_err(|_| PageError::InvalidSize(self.data.len()))?
347 as usize;
348
349 if stored_page_size != PAGE_SIZE {
350 return Err(PageError::InvalidSize(stored_page_size));
351 }
352
353 Ok(())
354 }
355}