1use super::crc32::crc32;
30
31pub use reddb_file::PAGED_PAGE_SIZE as PAGE_SIZE;
33
34pub use reddb_file::PAGED_PAGE_HEADER_SIZE as HEADER_SIZE;
36
37pub const CONTENT_SIZE: usize = PAGE_SIZE - HEADER_SIZE;
39
40pub const MAX_CELLS: usize = (CONTENT_SIZE - 4) / 6; pub use reddb_file::{PAGE_FILE_MAGIC as MAGIC_BYTES, PAGE_FILE_VERSION as DB_VERSION};
44
45#[repr(u8)]
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum PageType {
51 Free = 0,
53 BTreeLeaf = 1,
55 BTreeInterior = 2,
57 Overflow = 3,
59 Vector = 4,
61 FreelistTrunk = 5,
63 Header = 6,
65 GraphNode = 7,
67 GraphEdge = 8,
69 GraphAdjacency = 9,
71 GraphMeta = 10,
73 NativeMeta = 11,
75 Vault = 12,
77 ColumnBlock = 13,
83}
84
85impl PageType {
86 pub fn from_u8(value: u8) -> Option<Self> {
88 match value {
89 0 => Some(Self::Free),
90 1 => Some(Self::BTreeLeaf),
91 2 => Some(Self::BTreeInterior),
92 3 => Some(Self::Overflow),
93 4 => Some(Self::Vector),
94 5 => Some(Self::FreelistTrunk),
95 6 => Some(Self::Header),
96 7 => Some(Self::GraphNode),
97 8 => Some(Self::GraphEdge),
98 9 => Some(Self::GraphAdjacency),
99 10 => Some(Self::GraphMeta),
100 11 => Some(Self::NativeMeta),
101 12 => Some(Self::Vault),
102 13 => Some(Self::ColumnBlock),
103 _ => None,
104 }
105 }
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub struct PageLocation {
117 pub page_id: u32,
119 pub offset: u32,
121 pub length: u32,
123}
124
125impl PageLocation {
126 pub fn new(page_id: u32, offset: u32, length: u32) -> Self {
127 Self {
128 page_id,
129 offset,
130 length,
131 }
132 }
133}
134
135#[repr(u8)]
137#[derive(Debug, Clone, Copy, PartialEq, Eq)]
138pub enum PageFlag {
139 Dirty = 0x01,
141 Locked = 0x02,
143 Loaded = 0x04,
145 Pinned = 0x08,
147 Encrypted = 0x10,
149}
150
151#[derive(Debug, Clone, Copy)]
169pub struct PageHeader {
170 pub page_type: PageType,
172 pub flags: u8,
174 pub cell_count: u16,
176 pub free_start: u16,
178 pub free_end: u16,
180 pub page_id: u32,
182 pub parent_id: u32,
184 pub right_child: u32,
186 pub lsn: u64,
188 pub checksum: u32,
190}
191
192impl PageHeader {
193 pub fn new(page_type: PageType, page_id: u32) -> Self {
195 Self {
196 page_type,
197 flags: 0,
198 cell_count: 0,
199 free_start: HEADER_SIZE as u16,
200 free_end: PAGE_SIZE as u16,
201 page_id,
202 parent_id: 0,
203 right_child: 0,
204 lsn: 0,
205 checksum: 0,
206 }
207 }
208
209 pub fn to_bytes(&self) -> [u8; HEADER_SIZE] {
211 reddb_file::encode_paged_page_header(&reddb_file::PagedPageHeader {
212 page_type: self.page_type as u8,
213 flags: self.flags,
214 cell_count: self.cell_count,
215 free_start: self.free_start,
216 free_end: self.free_end,
217 page_id: self.page_id,
218 parent_id: self.parent_id,
219 right_child: self.right_child,
220 lsn: self.lsn,
221 checksum: self.checksum,
222 })
223 }
224
225 pub fn from_bytes(buf: &[u8; HEADER_SIZE]) -> Result<Self, PageError> {
227 let raw = reddb_file::decode_paged_page_header(buf);
228 let page_type =
229 PageType::from_u8(raw.page_type).ok_or(PageError::InvalidPageType(raw.page_type))?;
230
231 Ok(Self {
232 page_type,
233 flags: raw.flags,
234 cell_count: raw.cell_count,
235 free_start: raw.free_start,
236 free_end: raw.free_end,
237 page_id: raw.page_id,
238 parent_id: raw.parent_id,
239 right_child: raw.right_child,
240 lsn: raw.lsn,
241 checksum: raw.checksum,
242 })
243 }
244
245 #[inline]
247 pub fn has_flag(&self, flag: PageFlag) -> bool {
248 self.flags & (flag as u8) != 0
249 }
250
251 #[inline]
253 pub fn set_flag(&mut self, flag: PageFlag) {
254 self.flags |= flag as u8;
255 }
256
257 #[inline]
259 pub fn clear_flag(&mut self, flag: PageFlag) {
260 self.flags &= !(flag as u8);
261 }
262
263 #[inline]
265 pub fn free_space(&self) -> usize {
266 if self.free_end <= self.free_start {
267 0
268 } else {
269 (self.free_end - self.free_start) as usize
270 }
271 }
272}
273
274#[derive(Debug, Clone)]
276pub enum PageError {
277 InvalidPageType(u8),
279 ChecksumMismatch { expected: u32, actual: u32 },
281 InvalidSize(usize),
283 PageFull,
285 CellOutOfBounds(usize),
287 InvalidCellPointer(u16),
289 OverflowRequired,
291}
292
293impl std::fmt::Display for PageError {
294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295 match self {
296 Self::InvalidPageType(t) => write!(f, "Invalid page type: {}", t),
297 Self::ChecksumMismatch { expected, actual } => {
298 write!(
299 f,
300 "Checksum mismatch: expected 0x{:08X}, got 0x{:08X}",
301 expected, actual
302 )
303 }
304 Self::InvalidSize(s) => write!(f, "Invalid page size: {} (expected {})", s, PAGE_SIZE),
305 Self::PageFull => write!(f, "Page is full"),
306 Self::CellOutOfBounds(i) => write!(f, "Cell index {} out of bounds", i),
307 Self::InvalidCellPointer(p) => write!(f, "Invalid cell pointer: {}", p),
308 Self::OverflowRequired => write!(f, "Value too large, overflow page required"),
309 }
310 }
311}
312
313impl std::error::Error for PageError {}
314
315#[derive(Clone)]
319pub struct Page {
320 data: [u8; PAGE_SIZE],
322}
323
324#[path = "page/impl.rs"]
325mod page_impl;
326impl Default for Page {
327 fn default() -> Self {
328 Self::new(PageType::Free, 0)
329 }
330}
331
332impl std::fmt::Debug for Page {
333 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334 if let Ok(header) = self.header() {
335 f.debug_struct("Page")
336 .field("page_type", &header.page_type)
337 .field("page_id", &header.page_id)
338 .field("cell_count", &header.cell_count)
339 .field("free_space", &header.free_space())
340 .field("lsn", &header.lsn)
341 .finish()
342 } else {
343 f.debug_struct("Page")
344 .field("data", &"[invalid header]")
345 .finish()
346 }
347 }
348}
349
350#[cfg(test)]
351mod tests {
352 use super::*;
353
354 #[test]
355 fn test_page_header_roundtrip() {
356 let header = PageHeader {
357 page_type: PageType::BTreeLeaf,
358 flags: 0x05,
359 cell_count: 42,
360 free_start: 100,
361 free_end: 4000,
362 page_id: 12345,
363 parent_id: 99,
364 right_child: 0,
365 lsn: 0xDEADBEEF,
366 checksum: 0x12345678,
367 };
368
369 let bytes = header.to_bytes();
370 let decoded = PageHeader::from_bytes(&bytes).unwrap();
371
372 assert_eq!(decoded.page_type, header.page_type);
373 assert_eq!(decoded.flags, header.flags);
374 assert_eq!(decoded.cell_count, header.cell_count);
375 assert_eq!(decoded.free_start, header.free_start);
376 assert_eq!(decoded.free_end, header.free_end);
377 assert_eq!(decoded.page_id, header.page_id);
378 assert_eq!(decoded.parent_id, header.parent_id);
379 assert_eq!(decoded.right_child, header.right_child);
380 assert_eq!(decoded.lsn, header.lsn);
381 assert_eq!(decoded.checksum, header.checksum);
382 }
383
384 #[test]
385 fn test_page_new() {
386 let page = Page::new(PageType::BTreeLeaf, 42);
387 let header = page.header().unwrap();
388
389 assert_eq!(header.page_type, PageType::BTreeLeaf);
390 assert_eq!(header.page_id, 42);
391 assert_eq!(header.cell_count, 0);
392 assert_eq!(header.free_start, HEADER_SIZE as u16);
393 assert_eq!(header.free_end, PAGE_SIZE as u16);
394 }
395
396 #[test]
397 fn test_page_checksum() {
398 let mut page = Page::new(PageType::BTreeLeaf, 1);
399 page.update_checksum();
400 assert!(page.verify_checksum().is_ok());
401
402 page.data[100] ^= 0xFF;
404 assert!(page.verify_checksum().is_err());
405 }
406
407 #[test]
408 fn test_page_insert_cell() {
409 let mut page = Page::new(PageType::BTreeLeaf, 1);
410
411 let key = b"hello";
412 let value = b"world";
413
414 let index = page.insert_cell(key, value).unwrap();
415 assert_eq!(index, 0);
416 assert_eq!(page.cell_count(), 1);
417
418 let (read_key, read_value) = page.read_cell(0).unwrap();
419 assert_eq!(read_key, key.to_vec());
420 assert_eq!(read_value, value.to_vec());
421 }
422
423 #[test]
424 fn test_page_multiple_cells() {
425 let mut page = Page::new(PageType::BTreeLeaf, 1);
426
427 for i in 0..10 {
428 let key = format!("key{:03}", i);
429 let value = format!("value{}", i);
430 page.insert_cell(key.as_bytes(), value.as_bytes()).unwrap();
431 }
432
433 assert_eq!(page.cell_count(), 10);
434
435 for i in 0..10 {
436 let (key, value) = page.read_cell(i).unwrap();
437 assert_eq!(key, format!("key{:03}", i).as_bytes());
438 assert_eq!(value, format!("value{}", i).as_bytes());
439 }
440 }
441
442 #[test]
443 fn test_page_search_key() {
444 let mut page = Page::new(PageType::BTreeLeaf, 1);
445
446 for i in [10, 20, 30, 40, 50] {
448 let key = format!("{:03}", i);
449 page.insert_cell(key.as_bytes(), b"v").unwrap();
450 }
451
452 assert_eq!(page.search_key(b"020"), Ok(1));
454 assert_eq!(page.search_key(b"040"), Ok(3));
455
456 assert_eq!(page.search_key(b"015"), Err(1));
458 assert_eq!(page.search_key(b"000"), Err(0));
459 assert_eq!(page.search_key(b"060"), Err(5));
460 }
461
462 #[test]
463 fn test_page_full() {
464 let mut page = Page::new(PageType::BTreeLeaf, 1);
465
466 let large_value = vec![0xAB; 500];
468 let mut count = 0;
469
470 loop {
471 let key = format!("key{:05}", count);
472 match page.insert_cell(key.as_bytes(), &large_value) {
473 Ok(_) => count += 1,
474 Err(PageError::PageFull) => break,
475 Err(e) => panic!("Unexpected error: {:?}", e),
476 }
477 }
478
479 assert!(count > 0);
480 assert!(count < 40); }
482
483 #[test]
484 fn test_header_page() {
485 let page = Page::new_header_page(100);
486
487 assert!(page.verify_header_page().is_ok());
488 assert_eq!(page.read_page_count(), 100);
489 assert_eq!(page.read_freelist_head(), 0);
490 }
491
492 #[test]
493 fn test_page_flags() {
494 let mut header = PageHeader::new(PageType::BTreeLeaf, 1);
495
496 assert!(!header.has_flag(PageFlag::Dirty));
497 assert!(!header.has_flag(PageFlag::Locked));
498
499 header.set_flag(PageFlag::Dirty);
500 assert!(header.has_flag(PageFlag::Dirty));
501 assert!(!header.has_flag(PageFlag::Locked));
502
503 header.set_flag(PageFlag::Locked);
504 assert!(header.has_flag(PageFlag::Dirty));
505 assert!(header.has_flag(PageFlag::Locked));
506
507 header.clear_flag(PageFlag::Dirty);
508 assert!(!header.has_flag(PageFlag::Dirty));
509 assert!(header.has_flag(PageFlag::Locked));
510 }
511
512 #[test]
513 fn test_free_space_calculation() {
514 let page = Page::new(PageType::BTreeLeaf, 1);
515 let header = page.header().unwrap();
516
517 assert_eq!(header.free_space(), PAGE_SIZE - HEADER_SIZE);
519 }
520
521 #[test]
526 fn test_all_page_types() {
527 let page_types = [
529 PageType::Free,
530 PageType::BTreeLeaf,
531 PageType::BTreeInterior,
532 PageType::Overflow,
533 PageType::Vector,
534 PageType::FreelistTrunk,
535 PageType::Header,
536 PageType::GraphNode,
537 PageType::GraphEdge,
538 PageType::GraphAdjacency,
539 PageType::GraphMeta,
540 PageType::NativeMeta,
541 PageType::Vault,
542 PageType::ColumnBlock,
543 ];
544
545 for (i, &pt) in page_types.iter().enumerate() {
546 let page = Page::new(pt, i as u32);
547 assert_eq!(page.page_type().unwrap(), pt);
548 assert_eq!(page.page_id(), i as u32);
549 }
550 }
551
552 #[test]
553 fn test_page_type_from_u8() {
554 assert_eq!(PageType::from_u8(0), Some(PageType::Free));
555 assert_eq!(PageType::from_u8(1), Some(PageType::BTreeLeaf));
556 assert_eq!(PageType::from_u8(2), Some(PageType::BTreeInterior));
557 assert_eq!(PageType::from_u8(10), Some(PageType::GraphMeta));
558 assert_eq!(PageType::from_u8(11), Some(PageType::NativeMeta));
559 assert_eq!(PageType::from_u8(12), Some(PageType::Vault));
560 assert_eq!(PageType::from_u8(13), Some(PageType::ColumnBlock));
561 assert_eq!(PageType::from_u8(14), None);
562 assert_eq!(PageType::from_u8(255), None);
563 }
564
565 #[test]
566 fn test_page_from_slice_valid() {
567 let original = Page::new(PageType::BTreeLeaf, 123);
568 let slice = original.as_bytes();
569 let restored = Page::from_slice(slice).unwrap();
570
571 assert_eq!(restored.page_id(), 123);
572 assert_eq!(restored.page_type().unwrap(), PageType::BTreeLeaf);
573 }
574
575 #[test]
576 fn test_page_from_slice_invalid_size() {
577 let short_slice = [0u8; 100];
578 let result = Page::from_slice(&short_slice);
579 assert!(matches!(result, Err(PageError::InvalidSize(100))));
580
581 let long_slice = [0u8; 5000];
582 let result = Page::from_slice(&long_slice);
583 assert!(matches!(result, Err(PageError::InvalidSize(5000))));
584 }
585
586 #[test]
587 fn test_page_parent_and_child() {
588 let mut page = Page::new(PageType::BTreeInterior, 10);
589
590 page.set_parent_id(5);
591 page.set_right_child(15);
592
593 assert_eq!(page.parent_id(), 5);
594 assert_eq!(page.right_child(), 15);
595
596 let header = page.header().unwrap();
598 assert_eq!(header.parent_id, 5);
599 assert_eq!(header.right_child, 15);
600 }
601
602 #[test]
603 fn test_cell_pointer_bounds() {
604 let page = Page::new(PageType::BTreeLeaf, 1);
605
606 let result = page.get_cell_pointer(0);
608 assert!(matches!(result, Err(PageError::CellOutOfBounds(0))));
609
610 let result = page.get_cell_pointer(100);
611 assert!(matches!(result, Err(PageError::CellOutOfBounds(100))));
612 }
613
614 #[test]
615 fn test_cell_pointer_invalid_value() {
616 let mut page = Page::new(PageType::BTreeLeaf, 1);
617
618 let result = page.set_cell_pointer(0, 10);
620 assert!(matches!(result, Err(PageError::InvalidCellPointer(10))));
621
622 let result = page.set_cell_pointer(0, PAGE_SIZE as u16 + 1);
624 assert!(matches!(result, Err(PageError::InvalidCellPointer(_))));
625 }
626
627 #[test]
628 fn test_empty_key_value() {
629 let mut page = Page::new(PageType::BTreeLeaf, 1);
630
631 page.insert_cell(b"", b"value").unwrap();
633 let (key, value) = page.read_cell(0).unwrap();
634 assert!(key.is_empty());
635 assert_eq!(value, b"value");
636
637 page.insert_cell(b"key", b"").unwrap();
639 let (key, value) = page.read_cell(1).unwrap();
640 assert_eq!(key, b"key");
641 assert!(value.is_empty());
642
643 page.insert_cell(b"", b"").unwrap();
645 let (key, value) = page.read_cell(2).unwrap();
646 assert!(key.is_empty());
647 assert!(value.is_empty());
648 }
649
650 #[test]
651 fn test_large_value_overflow() {
652 let mut page = Page::new(PageType::BTreeLeaf, 1);
653
654 let huge_value = vec![0xAB; CONTENT_SIZE];
656 let result = page.insert_cell(b"key", &huge_value);
657 assert!(matches!(result, Err(PageError::OverflowRequired)));
658 }
659
660 #[test]
661 fn test_checksum_stability() {
662 let mut page = Page::new(PageType::BTreeLeaf, 42);
663 page.insert_cell(b"test", b"data").unwrap();
664
665 page.update_checksum();
666 let checksum1 = page.header().unwrap().checksum;
667
668 page.update_checksum();
670 let checksum2 = page.header().unwrap().checksum;
671
672 assert_eq!(checksum1, checksum2);
673 }
674
675 #[test]
676 fn test_checksum_changes_with_content() {
677 let mut page1 = Page::new(PageType::BTreeLeaf, 1);
678 let mut page2 = Page::new(PageType::BTreeLeaf, 1);
679
680 page1.insert_cell(b"key1", b"value1").unwrap();
681 page2.insert_cell(b"key2", b"value2").unwrap();
682
683 page1.update_checksum();
684 page2.update_checksum();
685
686 assert_ne!(
687 page1.header().unwrap().checksum,
688 page2.header().unwrap().checksum
689 );
690 }
691
692 #[test]
693 fn test_free_space_decreases_with_cells() {
694 let mut page = Page::new(PageType::BTreeLeaf, 1);
695 let initial_free = page.header().unwrap().free_space();
696
697 page.insert_cell(b"key", b"value").unwrap();
698 let after_first = page.header().unwrap().free_space();
699
700 page.insert_cell(b"another_key", b"another_value").unwrap();
701 let after_second = page.header().unwrap().free_space();
702
703 assert!(after_first < initial_free);
704 assert!(after_second < after_first);
705 }
706
707 #[test]
708 fn test_search_empty_page() {
709 let page = Page::new(PageType::BTreeLeaf, 1);
710
711 assert_eq!(page.search_key(b"anything"), Err(0));
713 }
714
715 #[test]
716 fn test_search_single_cell() {
717 let mut page = Page::new(PageType::BTreeLeaf, 1);
718 page.insert_cell(b"middle", b"v").unwrap();
719
720 assert_eq!(page.search_key(b"middle"), Ok(0));
722
723 assert_eq!(page.search_key(b"aaa"), Err(0));
725
726 assert_eq!(page.search_key(b"zzz"), Err(1));
728 }
729
730 #[test]
731 fn test_binary_data() {
732 let mut page = Page::new(PageType::BTreeLeaf, 1);
733
734 let binary_key = [0x00, 0x01, 0x02, 0xFF, 0xFE];
736 let binary_value = [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x00];
737
738 page.insert_cell(&binary_key, &binary_value).unwrap();
739
740 let (key, value) = page.read_cell(0).unwrap();
741 assert_eq!(key, binary_key.to_vec());
742 assert_eq!(value, binary_value.to_vec());
743 }
744
745 #[test]
746 fn test_max_cells_stress() {
747 let mut page = Page::new(PageType::BTreeLeaf, 1);
748
749 let mut inserted = 0;
751 for i in 0..MAX_CELLS {
752 let key = format!("{:04}", i);
753 if page.insert_cell(key.as_bytes(), b"x").is_ok() {
754 inserted += 1;
755 } else {
756 break;
757 }
758 }
759
760 for i in 0..inserted {
762 let (key, _) = page.read_cell(i).unwrap();
763 assert_eq!(key, format!("{:04}", i).as_bytes());
764 }
765 }
766
767 #[test]
768 fn test_content_mut() {
769 let mut page = Page::new(PageType::BTreeLeaf, 1);
770
771 let content = page.content_mut();
773 content[0] = 0xAB;
774 content[1] = 0xCD;
775
776 let content = page.content();
778 assert_eq!(content[0], 0xAB);
779 assert_eq!(content[1], 0xCD);
780 }
781
782 #[test]
783 fn test_page_bytes_roundtrip() {
784 let mut page = Page::new(PageType::BTreeLeaf, 999);
785 page.insert_cell(b"key", b"value").unwrap();
786 page.update_checksum();
787
788 let bytes = *page.as_bytes();
790 let restored = Page::from_bytes(bytes);
791
792 assert_eq!(restored.page_id(), 999);
793 assert!(restored.verify_checksum().is_ok());
794
795 let (key, value) = restored.read_cell(0).unwrap();
796 assert_eq!(key, b"key");
797 assert_eq!(value, b"value");
798 }
799
800 #[test]
801 fn test_header_page_operations() {
802 let mut page = Page::new_header_page(1000);
803
804 assert!(page.verify_header_page().is_ok());
805 assert_eq!(page.read_page_count(), 1000);
806 assert_eq!(page.read_freelist_head(), 0);
807
808 page.write_page_count(2000);
810 assert_eq!(page.read_page_count(), 2000);
811
812 page.write_freelist_head(42);
814 assert_eq!(page.read_freelist_head(), 42);
815 }
816
817 #[test]
818 fn test_page_flags_multiple() {
819 let mut header = PageHeader::new(PageType::BTreeLeaf, 1);
820
821 header.set_flag(PageFlag::Dirty);
823 header.set_flag(PageFlag::Locked);
824 header.set_flag(PageFlag::Encrypted);
825
826 assert!(header.has_flag(PageFlag::Dirty));
827 assert!(header.has_flag(PageFlag::Locked));
828 assert!(header.has_flag(PageFlag::Encrypted));
829 assert!(!header.has_flag(PageFlag::Pinned));
830
831 header.clear_flag(PageFlag::Locked);
833 assert!(header.has_flag(PageFlag::Dirty));
834 assert!(!header.has_flag(PageFlag::Locked));
835 assert!(header.has_flag(PageFlag::Encrypted));
836 }
837
838 #[test]
839 fn test_page_error_display() {
840 let errors = [
841 PageError::InvalidPageType(99),
842 PageError::ChecksumMismatch {
843 expected: 0x1234,
844 actual: 0x5678,
845 },
846 PageError::InvalidSize(100),
847 PageError::PageFull,
848 PageError::CellOutOfBounds(5),
849 PageError::InvalidCellPointer(10),
850 PageError::OverflowRequired,
851 ];
852
853 for error in &errors {
854 let _msg = format!("{}", error);
856 }
857 }
858
859 #[test]
860 fn test_cell_count_consistency() {
861 let mut page = Page::new(PageType::BTreeLeaf, 1);
862
863 assert_eq!(page.cell_count(), 0);
864
865 page.insert_cell(b"a", b"1").unwrap();
866 assert_eq!(page.cell_count(), 1);
867
868 page.insert_cell(b"b", b"2").unwrap();
869 assert_eq!(page.cell_count(), 2);
870
871 page.insert_cell(b"c", b"3").unwrap();
872 assert_eq!(page.cell_count(), 3);
873
874 page.set_cell_count(0);
876 assert_eq!(page.cell_count(), 0);
877 }
878
879 #[test]
880 fn test_free_start_end_consistency() {
881 let mut page = Page::new(PageType::BTreeLeaf, 1);
882
883 let initial_start = page.free_start();
884 let initial_end = page.free_end();
885
886 assert_eq!(initial_start, HEADER_SIZE as u16);
887 assert_eq!(initial_end, PAGE_SIZE as u16);
888
889 page.insert_cell(b"test_key", b"test_value").unwrap();
890
891 let after_start = page.free_start();
892 let after_end = page.free_end();
893
894 assert!(after_start > initial_start);
896 assert!(after_end < initial_end);
898 }
899}