1use std::cmp::Ordering;
33use std::sync::{Arc, RwLock};
34
35use super::page::{Page, PageType, HEADER_SIZE, PAGE_SIZE};
36use super::page_store::PageStore;
37use super::pager::PagerError;
38
39pub const MAX_KEY_SIZE: usize = 1024;
41
42pub const MAX_VALUE_SIZE: usize = value_layout::MAX_VALUE_SIZE;
55
56pub const MIN_FILL_FACTOR: usize = 25;
58
59const LEAF_PREV_OFFSET: usize = HEADER_SIZE;
61
62const LEAF_NEXT_OFFSET: usize = HEADER_SIZE + 4;
64
65const LEAF_SLOT_ARRAY_OFFSET: usize = HEADER_SIZE + 8;
80
81const LEAF_DATA_OFFSET: usize = LEAF_SLOT_ARRAY_OFFSET;
84
85const INTERIOR_DATA_OFFSET: usize = HEADER_SIZE;
87
88#[derive(Debug, Clone)]
90pub enum BTreeError {
91 NotFound,
93 DuplicateKey,
95 KeyTooLarge(usize),
97 ValueTooLarge(usize),
99 Corrupted(String),
101 Pager(String),
103 LockPoisoned(String),
105 ValueLayout(String),
107}
108
109impl std::fmt::Display for BTreeError {
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 match self {
112 Self::NotFound => write!(f, "Key not found"),
113 Self::DuplicateKey => write!(f, "Key already exists"),
114 Self::KeyTooLarge(size) => {
115 write!(f, "Key too large: {} bytes (max {})", size, MAX_KEY_SIZE)
116 }
117 Self::ValueTooLarge(size) => write!(
118 f,
119 "Value too large: {} bytes (max {})",
120 size, MAX_VALUE_SIZE
121 ),
122 Self::Corrupted(msg) => write!(f, "B-tree corrupted: {}", msg),
123 Self::Pager(msg) => write!(f, "Pager error: {}", msg),
124 Self::LockPoisoned(msg) => write!(f, "Lock poisoned: {}", msg),
125 Self::ValueLayout(msg) => write!(f, "Value layout: {}", msg),
126 }
127 }
128}
129
130impl From<value_layout::ValueLayoutError> for BTreeError {
131 fn from(e: value_layout::ValueLayoutError) -> Self {
132 match e {
133 value_layout::ValueLayoutError::ValueTooLarge(n) => Self::ValueTooLarge(n),
134 other => Self::ValueLayout(other.to_string()),
135 }
136 }
137}
138
139impl std::error::Error for BTreeError {}
140
141impl From<PagerError> for BTreeError {
142 fn from(e: PagerError) -> Self {
143 Self::Pager(e.to_string())
144 }
145}
146
147impl From<super::page::PageError> for BTreeError {
148 fn from(e: super::page::PageError) -> Self {
149 Self::Corrupted(e.to_string())
150 }
151}
152
153pub type BTreeResult<T> = Result<T, BTreeError>;
155
156pub struct BTreeCursor<P: PageStore> {
158 _retirement_pin: Arc<()>,
160 leaf_page_id: u32,
162 position: usize,
164 pager: Arc<P>,
166 prefetched_next: bool,
170}
171
172impl<P: PageStore> BTreeCursor<P> {
173 pub fn next(&mut self) -> BTreeResult<Option<(Vec<u8>, Vec<u8>)>> {
175 if self.leaf_page_id == 0 {
176 return Ok(None);
177 }
178
179 let page = self.pager.read_page(self.leaf_page_id)?;
180 if page.page_type()? != PageType::BTreeLeaf {
181 return Err(BTreeError::Corrupted(
182 "cursor reached a non-leaf page".into(),
183 ));
184 }
185 let cell_count = page.cell_count() as usize;
186
187 if !self.prefetched_next && self.position >= cell_count / 2 && cell_count > 0 {
193 let next_leaf = read_next_leaf(&page);
194 if next_leaf != 0 {
195 self.pager.prefetch_hint(next_leaf);
196 }
197 self.prefetched_next = true;
198 }
199
200 if self.position < cell_count {
202 let (key, stored) = read_leaf_cell(&page, self.position)?;
203 let value = value_layout::decode(self.pager.as_ref(), &stored)?;
204 self.position += 1;
205 return Ok(Some((key, value)));
206 }
207
208 let next_leaf = read_next_leaf(&page);
210 if next_leaf == 0 {
211 self.leaf_page_id = 0;
212 return Ok(None);
213 }
214 let previous_high_key = leaf_high_key(&page)?;
215
216 self.leaf_page_id = next_leaf;
217 self.position = 0;
218 self.prefetched_next = false; let page = self.pager.read_page(self.leaf_page_id)?;
222 if page.page_type()? != PageType::BTreeLeaf {
223 return Err(BTreeError::Corrupted(
224 "leaf chain reached a non-leaf page".into(),
225 ));
226 }
227 if page.cell_count() == 0 {
228 return Ok(None);
229 }
230
231 let (key, stored) = read_leaf_cell(&page, 0)?;
232 if previous_high_key
236 .as_ref()
237 .is_some_and(|previous| key <= *previous)
238 {
239 self.leaf_page_id = 0;
240 return Err(BTreeError::Corrupted(
241 "leaf chain does not advance its key range".into(),
242 ));
243 }
244 let value = value_layout::decode(self.pager.as_ref(), &stored)?;
245 self.position = 1;
246 Ok(Some((key, value)))
247 }
248
249 pub fn peek(&self) -> BTreeResult<Option<(Vec<u8>, Vec<u8>)>> {
251 if self.leaf_page_id == 0 {
252 return Ok(None);
253 }
254
255 let page = self.pager.read_page(self.leaf_page_id)?;
256 let cell_count = page.cell_count() as usize;
257
258 if self.position >= cell_count {
259 return Ok(None);
260 }
261
262 let (key, stored) = read_leaf_cell(&page, self.position)?;
263 let value = value_layout::decode(self.pager.as_ref(), &stored)?;
264 Ok(Some((key, value)))
265 }
266}
267
268pub struct BTree<P: PageStore> {
270 retirement_pin: Arc<()>,
271 pager: Arc<P>,
273 root_page_id: RwLock<u32>,
275 rightmost_leaf: RwLock<Option<(u32, Vec<u8>)>>,
284 writer: parking_lot::ReentrantMutex<()>,
292}
293
294#[path = "btree/impl.rs"]
295mod btree_impl;
296
297#[path = "btree/reclaim.rs"]
298mod reclaim;
299
300#[path = "btree/lehman_yao.rs"]
301pub mod lehman_yao;
302
303#[path = "btree/value_layout.rs"]
304pub mod value_layout;
305enum SearchResult {
308 Found(usize),
309 NotFound(usize),
310}
311
312fn search_leaf(page: &Page, key: &[u8]) -> BTreeResult<SearchResult> {
313 let cell_count = page.cell_count() as usize;
314
315 let mut low = 0;
317 let mut high = cell_count;
318
319 while low < high {
320 let mid = (low + high) / 2;
321 let (cell_key, _) = read_leaf_cell(page, mid)?;
322
323 match cell_key.as_slice().cmp(key) {
324 Ordering::Less => low = mid + 1,
325 Ordering::Greater => high = mid,
326 Ordering::Equal => return Ok(SearchResult::Found(mid)),
327 }
328 }
329
330 Ok(SearchResult::NotFound(low))
331}
332
333fn find_child(page: &Page, key: &[u8]) -> BTreeResult<u32> {
334 let cell_count = page.cell_count() as usize;
335
336 for i in 0..cell_count {
338 let (cell_key, child) = read_interior_cell(page, i)?;
339 if key < cell_key.as_slice() {
340 return Ok(child);
341 }
342 }
343
344 Ok(page.right_child())
346}
347
348fn find_first_child(page: &Page) -> BTreeResult<u32> {
349 if page.cell_count() == 0 {
350 return Ok(page.right_child());
351 }
352 let (_, child) = read_interior_cell(page, 0)?;
353 Ok(child)
354}
355
356fn leaf_min_bytes() -> usize {
357 (PAGE_SIZE - LEAF_DATA_OFFSET) * MIN_FILL_FACTOR / 100
358}
359
360fn interior_min_bytes() -> usize {
361 (PAGE_SIZE - INTERIOR_DATA_OFFSET) * MIN_FILL_FACTOR / 100
362}
363
364fn leaf_entry_size(entry: &(Vec<u8>, Vec<u8>)) -> usize {
368 2 + 4 + entry.0.len() + entry.1.len()
369}
370
371fn leaf_entries_size(entries: &[(Vec<u8>, Vec<u8>)]) -> usize {
372 entries.iter().map(leaf_entry_size).sum()
373}
374
375#[inline]
376fn leaf_slot_offset_for(index: usize) -> usize {
377 LEAF_SLOT_ARRAY_OFFSET + index * 2
378}
379
380#[inline]
381fn leaf_read_slot(page: &Page, index: usize) -> BTreeResult<usize> {
382 let data = page.as_bytes();
383 let slot_pos = leaf_slot_offset_for(index);
384 if slot_pos + 2 > PAGE_SIZE {
385 return Err(BTreeError::Corrupted("slot array overflows page".into()));
386 }
387 Ok(u16::from_le_bytes([data[slot_pos], data[slot_pos + 1]]) as usize)
388}
389
390#[inline]
391fn leaf_write_slot(page: &mut Page, index: usize, cell_offset: u16) -> BTreeResult<()> {
392 let data = page.as_bytes_mut();
393 let slot_pos = leaf_slot_offset_for(index);
394 if slot_pos + 2 > PAGE_SIZE {
395 return Err(BTreeError::Corrupted("slot array overflows page".into()));
396 }
397 data[slot_pos..slot_pos + 2].copy_from_slice(&cell_offset.to_le_bytes());
398 Ok(())
399}
400
401#[inline]
402fn leaf_slots_end(page: &Page) -> usize {
403 LEAF_SLOT_ARRAY_OFFSET + (page.cell_count() as usize) * 2
404}
405
406#[inline]
407fn leaf_cells_start(page: &Page) -> usize {
408 let end = page.free_end() as usize;
409 if end == 0 {
410 PAGE_SIZE
411 } else {
412 end
413 }
414}
415
416#[inline]
417fn leaf_free_bytes(page: &Page) -> usize {
418 let slot_end = leaf_slots_end(page);
419 let cells = leaf_cells_start(page);
420 cells.saturating_sub(slot_end)
421}
422
423fn interior_key_size(key: &[u8]) -> usize {
424 2 + key.len() + 4
425}
426
427fn interior_entries_size(keys: &[Vec<u8>]) -> usize {
428 keys.iter().map(|k| interior_key_size(k)).sum()
429}
430
431fn read_leaf_cell(page: &Page, index: usize) -> BTreeResult<(Vec<u8>, Vec<u8>)> {
437 let cell_count = page.cell_count() as usize;
438 if index >= cell_count {
439 return Err(BTreeError::Corrupted("Cell index out of range".into()));
440 }
441 let offset = leaf_read_slot(page, index)?;
442 let data = page.as_bytes();
443 if offset + 4 > PAGE_SIZE {
444 return Err(BTreeError::Corrupted("cell header out of range".into()));
445 }
446 let key_len = u16::from_le_bytes([data[offset], data[offset + 1]]) as usize;
447 let val_len = u16::from_le_bytes([data[offset + 2], data[offset + 3]]) as usize;
448 let end = offset + 4 + key_len + val_len;
449 if end > PAGE_SIZE {
450 return Err(BTreeError::Corrupted("cell body out of range".into()));
451 }
452 let key = data[offset + 4..offset + 4 + key_len].to_vec();
453 let value = data[offset + 4 + key_len..end].to_vec();
454 Ok((key, value))
455}
456
457fn read_leaf_entries(page: &Page) -> BTreeResult<Vec<(Vec<u8>, Vec<u8>)>> {
458 let cell_count = page.cell_count() as usize;
459 let mut entries = Vec::with_capacity(cell_count);
460 for i in 0..cell_count {
461 entries.push(read_leaf_cell(page, i)?);
462 }
463 Ok(entries)
464}
465
466fn write_leaf_entries(page: &mut Page, entries: &[(Vec<u8>, Vec<u8>)]) -> BTreeResult<()> {
472 clear_leaf_cells(page);
473 for (i, (k, v)) in entries.iter().enumerate() {
474 let cell_size = 4 + k.len() + v.len();
475 let cells_start = leaf_cells_start(page);
476 let slot_end = LEAF_SLOT_ARRAY_OFFSET + (i + 1) * 2;
477 if slot_end + cell_size > cells_start {
478 return Err(BTreeError::Corrupted("leaf rebuild overflowed page".into()));
479 }
480 let cell_offset = cells_start - cell_size;
481 {
482 let data = page.as_bytes_mut();
483 data[cell_offset..cell_offset + 2].copy_from_slice(&(k.len() as u16).to_le_bytes());
484 data[cell_offset + 2..cell_offset + 4].copy_from_slice(&(v.len() as u16).to_le_bytes());
485 data[cell_offset + 4..cell_offset + 4 + k.len()].copy_from_slice(k);
486 data[cell_offset + 4 + k.len()..cell_offset + 4 + k.len() + v.len()].copy_from_slice(v);
487 }
488 page.set_free_end(cell_offset as u16);
489 leaf_write_slot(page, i, cell_offset as u16)?;
490 }
491 page.set_cell_count(entries.len() as u16);
492 page.set_free_start((LEAF_SLOT_ARRAY_OFFSET + entries.len() * 2) as u16);
493 Ok(())
494}
495
496fn can_insert_leaf(page: &Page, key: &[u8], value: &[u8]) -> bool {
497 let needed = 2 + 4 + key.len() + value.len();
498 leaf_free_bytes(page) >= needed
499}
500
501pub(crate) fn overwrite_leaf_value(
517 page: &mut Page,
518 index: usize,
519 new_value: &[u8],
520) -> BTreeResult<()> {
521 let cell_offset = leaf_read_slot(page, index)?;
522 let data = page.as_bytes();
523 if cell_offset + 4 > data.len() {
524 return Err(BTreeError::Corrupted(
525 "leaf cell header out of bounds".into(),
526 ));
527 }
528 let k_len = u16::from_le_bytes([data[cell_offset], data[cell_offset + 1]]) as usize;
529 let old_v_len = u16::from_le_bytes([data[cell_offset + 2], data[cell_offset + 3]]) as usize;
530 if new_value.len() > old_v_len {
531 return Err(BTreeError::Corrupted(
532 "overwrite_leaf_value: new value larger than slot".into(),
533 ));
534 }
535 let value_start = cell_offset + 4 + k_len;
536 if value_start + new_value.len() > data.len() {
537 return Err(BTreeError::Corrupted(
538 "leaf cell value out of bounds".into(),
539 ));
540 }
541 let data = page.as_bytes_mut();
542 if new_value.len() != old_v_len {
545 let new_len = new_value.len() as u16;
546 data[cell_offset + 2..cell_offset + 4].copy_from_slice(&new_len.to_le_bytes());
547 }
548 data[value_start..value_start + new_value.len()].copy_from_slice(new_value);
549 Ok(())
550}
551
552fn insert_into_leaf(page: &mut Page, key: &[u8], value: &[u8]) -> BTreeResult<()> {
554 let cell_count = page.cell_count() as usize;
556 let mut low = 0;
557 let mut high = cell_count;
558 while low < high {
559 let mid = (low + high) / 2;
560 let (cell_key, _) = read_leaf_cell(page, mid)?;
561 match cell_key.as_slice().cmp(key) {
562 Ordering::Less => low = mid + 1,
563 Ordering::Greater => high = mid,
564 Ordering::Equal => {
565 low = mid + 1;
568 break;
569 }
570 }
571 }
572 let insert_pos = low;
573
574 let cell_size = 4 + key.len() + value.len();
576 let slot_end_after = LEAF_SLOT_ARRAY_OFFSET + (cell_count + 1) * 2;
577 let cells_start = leaf_cells_start(page);
578 if slot_end_after + cell_size > cells_start {
579 return Err(BTreeError::Corrupted("leaf page full".into()));
580 }
581 let cell_offset = cells_start - cell_size;
582 {
583 let data = page.as_bytes_mut();
584 data[cell_offset..cell_offset + 2].copy_from_slice(&(key.len() as u16).to_le_bytes());
585 data[cell_offset + 2..cell_offset + 4].copy_from_slice(&(value.len() as u16).to_le_bytes());
586 data[cell_offset + 4..cell_offset + 4 + key.len()].copy_from_slice(key);
587 data[cell_offset + 4 + key.len()..cell_offset + 4 + key.len() + value.len()]
588 .copy_from_slice(value);
589 }
590 page.set_free_end(cell_offset as u16);
591
592 {
596 let shift_from = leaf_slot_offset_for(insert_pos);
597 let shift_to = shift_from + 2;
598 let shift_len = (cell_count - insert_pos) * 2;
599 if shift_len > 0 {
600 let data = page.as_bytes_mut();
601 data.copy_within(shift_from..shift_from + shift_len, shift_to);
602 }
603 }
604 leaf_write_slot(page, insert_pos, cell_offset as u16)?;
605
606 page.set_cell_count((cell_count + 1) as u16);
608 page.set_free_start((LEAF_SLOT_ARRAY_OFFSET + (cell_count + 1) * 2) as u16);
609 Ok(())
610}
611
612fn delete_from_leaf(page: &mut Page, index: usize) -> BTreeResult<()> {
617 let cell_count = page.cell_count() as usize;
618 if index >= cell_count {
619 return Err(BTreeError::Corrupted("delete index out of range".into()));
620 }
621 if index + 1 < cell_count {
622 let shift_from = leaf_slot_offset_for(index + 1);
623 let shift_to = leaf_slot_offset_for(index);
624 let shift_len = (cell_count - index - 1) * 2;
625 let data = page.as_bytes_mut();
626 data.copy_within(shift_from..shift_from + shift_len, shift_to);
627 }
628 page.set_cell_count((cell_count - 1) as u16);
629 page.set_free_start((LEAF_SLOT_ARRAY_OFFSET + (cell_count - 1) * 2) as u16);
630 Ok(())
631}
632
633fn clear_leaf_cells(page: &mut Page) {
637 {
638 let data = page.as_bytes_mut();
639 for byte in &mut data[LEAF_SLOT_ARRAY_OFFSET..] {
640 *byte = 0;
641 }
642 }
643 page.set_cell_count(0);
644 page.set_free_start(LEAF_SLOT_ARRAY_OFFSET as u16);
645 page.set_free_end(PAGE_SIZE as u16);
646}
647
648fn init_leaf_links(page: &mut Page, prev: u32, next: u32) {
649 let data = page.as_bytes_mut();
650 data[LEAF_PREV_OFFSET..LEAF_PREV_OFFSET + 4].copy_from_slice(&prev.to_le_bytes());
651 data[LEAF_NEXT_OFFSET..LEAF_NEXT_OFFSET + 4].copy_from_slice(&next.to_le_bytes());
652}
653
654fn read_next_leaf(page: &Page) -> u32 {
655 let data = page.as_bytes();
656 u32::from_le_bytes([
657 data[LEAF_NEXT_OFFSET],
658 data[LEAF_NEXT_OFFSET + 1],
659 data[LEAF_NEXT_OFFSET + 2],
660 data[LEAF_NEXT_OFFSET + 3],
661 ])
662}
663
664#[inline]
667fn leaf_right_sibling(page: &Page) -> u32 {
668 read_next_leaf(page)
669}
670
671fn leaf_high_key(page: &Page) -> BTreeResult<Option<Vec<u8>>> {
675 let cell_count = page.cell_count() as usize;
676 if cell_count == 0 {
677 return Ok(None);
678 }
679 let (key, _) = read_leaf_cell(page, cell_count - 1)?;
680 Ok(Some(key))
681}
682
683fn set_prev_leaf(page: &mut Page, prev: u32) {
684 let data = page.as_bytes_mut();
685 data[LEAF_PREV_OFFSET..LEAF_PREV_OFFSET + 4].copy_from_slice(&prev.to_le_bytes());
686}
687
688fn set_next_leaf(page: &mut Page, next: u32) {
689 let data = page.as_bytes_mut();
690 data[LEAF_NEXT_OFFSET..LEAF_NEXT_OFFSET + 4].copy_from_slice(&next.to_le_bytes());
691}
692
693#[inline]
708fn interior_slot_offset_for(index: usize) -> usize {
709 INTERIOR_DATA_OFFSET + index * 2
710}
711
712#[inline]
713fn interior_read_slot(page: &Page, index: usize) -> BTreeResult<usize> {
714 let data = page.as_bytes();
715 let slot_pos = interior_slot_offset_for(index);
716 if slot_pos + 2 > PAGE_SIZE {
717 return Err(BTreeError::Corrupted(
718 "interior slot array overflows page".into(),
719 ));
720 }
721 Ok(u16::from_le_bytes([data[slot_pos], data[slot_pos + 1]]) as usize)
722}
723
724#[inline]
725fn interior_write_slot(page: &mut Page, index: usize, cell_offset: u16) -> BTreeResult<()> {
726 let data = page.as_bytes_mut();
727 let slot_pos = interior_slot_offset_for(index);
728 if slot_pos + 2 > PAGE_SIZE {
729 return Err(BTreeError::Corrupted(
730 "interior slot array overflows page".into(),
731 ));
732 }
733 data[slot_pos..slot_pos + 2].copy_from_slice(&cell_offset.to_le_bytes());
734 Ok(())
735}
736
737#[inline]
738fn interior_cells_start(page: &Page) -> usize {
739 let end = page.free_end() as usize;
740 if end == 0 {
741 PAGE_SIZE
742 } else {
743 end
744 }
745}
746
747#[inline]
748fn interior_free_bytes(page: &Page) -> usize {
749 let slot_end = INTERIOR_DATA_OFFSET + (page.cell_count() as usize) * 2;
750 interior_cells_start(page).saturating_sub(slot_end)
751}
752
753fn read_interior_cell(page: &Page, index: usize) -> BTreeResult<(Vec<u8>, u32)> {
754 let cell_count = page.cell_count() as usize;
755 if index >= cell_count {
756 return Err(BTreeError::Corrupted("Cell index out of range".into()));
757 }
758 let offset = interior_read_slot(page, index)?;
759 let data = page.as_bytes();
760 if offset + 2 > PAGE_SIZE {
761 return Err(BTreeError::Corrupted(
762 "interior cell header out of range".into(),
763 ));
764 }
765 let key_len = u16::from_le_bytes([data[offset], data[offset + 1]]) as usize;
766 let end = offset + 2 + key_len + 4;
767 if end > PAGE_SIZE {
768 return Err(BTreeError::Corrupted(
769 "interior cell body out of range".into(),
770 ));
771 }
772 let key = data[offset + 2..offset + 2 + key_len].to_vec();
773 let child = u32::from_le_bytes([
774 data[offset + 2 + key_len],
775 data[offset + 2 + key_len + 1],
776 data[offset + 2 + key_len + 2],
777 data[offset + 2 + key_len + 3],
778 ]);
779 Ok((key, child))
780}
781
782fn read_interior_keys_children(page: &Page) -> BTreeResult<(Vec<Vec<u8>>, Vec<u32>)> {
783 let cell_count = page.cell_count() as usize;
784 let mut keys = Vec::with_capacity(cell_count);
785 let mut children = Vec::with_capacity(cell_count + 1);
786
787 for i in 0..cell_count {
788 let (key, child) = read_interior_cell(page, i)?;
789 keys.push(key);
790 children.push(child);
791 }
792
793 if cell_count == 0 {
794 let right_child = page.right_child();
795 if right_child != 0 {
796 children.push(right_child);
797 }
798 } else {
799 children.push(page.right_child());
800 }
801
802 Ok((keys, children))
803}
804
805fn write_interior_entries(page: &mut Page, keys: &[Vec<u8>], children: &[u32]) -> BTreeResult<()> {
810 if !keys.is_empty() && children.len() != keys.len() + 1 {
811 return Err(BTreeError::Corrupted(
812 "Interior keys/children length mismatch".into(),
813 ));
814 }
815
816 clear_interior_cells(page);
817 if keys.is_empty() {
818 let right_child = children.first().copied().unwrap_or(0);
819 page.set_right_child(right_child);
820 return Ok(());
821 }
822
823 for (i, key) in keys.iter().enumerate() {
824 let cell_size = 2 + key.len() + 4;
825 let cells_start = interior_cells_start(page);
826 let slot_end = INTERIOR_DATA_OFFSET + (i + 1) * 2;
827 if slot_end + cell_size > cells_start {
828 return Err(BTreeError::Corrupted(
829 "interior rebuild overflowed page".into(),
830 ));
831 }
832 let cell_offset = cells_start - cell_size;
833 {
834 let data = page.as_bytes_mut();
835 data[cell_offset..cell_offset + 2].copy_from_slice(&(key.len() as u16).to_le_bytes());
836 data[cell_offset + 2..cell_offset + 2 + key.len()].copy_from_slice(key);
837 data[cell_offset + 2 + key.len()..cell_offset + 2 + key.len() + 4]
838 .copy_from_slice(&children[i].to_le_bytes());
839 }
840 page.set_free_end(cell_offset as u16);
841 interior_write_slot(page, i, cell_offset as u16)?;
842 }
843 page.set_cell_count(keys.len() as u16);
844 page.set_free_start((INTERIOR_DATA_OFFSET + keys.len() * 2) as u16);
845 page.set_right_child(*children.last().ok_or_else(|| {
846 BTreeError::Corrupted("write_interior_entries: children empty with non-empty keys".into())
847 })?);
848 Ok(())
849}
850
851fn can_insert_interior(page: &Page, key: &[u8]) -> bool {
852 let needed = 2 + 2 + key.len() + 4;
853 interior_free_bytes(page) >= needed
854}
855
856fn insert_into_interior(
861 page: &mut Page,
862 key: &[u8],
863 left_child: u32,
864 right_child: u32,
865) -> BTreeResult<()> {
866 let cell_count = page.cell_count() as usize;
868 let mut low = 0;
869 let mut high = cell_count;
870 while low < high {
871 let mid = (low + high) / 2;
872 let (cell_key, _) = read_interior_cell(page, mid)?;
873 match cell_key.as_slice().cmp(key) {
874 Ordering::Less => low = mid + 1,
875 Ordering::Greater | Ordering::Equal => high = mid,
876 }
877 }
878 let insert_pos = low;
879
880 if insert_pos < cell_count {
885 let old_offset = interior_read_slot(page, insert_pos)?;
886 let data = page.as_bytes();
887 let key_len = u16::from_le_bytes([data[old_offset], data[old_offset + 1]]) as usize;
888 let child_pos = old_offset + 2 + key_len;
889 let data = page.as_bytes_mut();
890 data[child_pos..child_pos + 4].copy_from_slice(&right_child.to_le_bytes());
891 } else {
892 page.set_right_child(right_child);
893 }
894
895 let cell_size = 2 + key.len() + 4;
897 let slot_end_after = INTERIOR_DATA_OFFSET + (cell_count + 1) * 2;
898 let cells_start = interior_cells_start(page);
899 if slot_end_after + cell_size > cells_start {
900 return Err(BTreeError::Corrupted("interior page full".into()));
901 }
902 let cell_offset = cells_start - cell_size;
903 {
904 let data = page.as_bytes_mut();
905 data[cell_offset..cell_offset + 2].copy_from_slice(&(key.len() as u16).to_le_bytes());
906 data[cell_offset + 2..cell_offset + 2 + key.len()].copy_from_slice(key);
907 data[cell_offset + 2 + key.len()..cell_offset + 2 + key.len() + 4]
908 .copy_from_slice(&left_child.to_le_bytes());
909 }
910 page.set_free_end(cell_offset as u16);
911
912 {
915 let shift_from = interior_slot_offset_for(insert_pos);
916 let shift_to = shift_from + 2;
917 let shift_len = (cell_count - insert_pos) * 2;
918 if shift_len > 0 {
919 let data = page.as_bytes_mut();
920 data.copy_within(shift_from..shift_from + shift_len, shift_to);
921 }
922 }
923 interior_write_slot(page, insert_pos, cell_offset as u16)?;
924 page.set_cell_count((cell_count + 1) as u16);
925 page.set_free_start((INTERIOR_DATA_OFFSET + (cell_count + 1) * 2) as u16);
926 Ok(())
927}
928
929fn clear_interior_cells(page: &mut Page) {
930 {
931 let data = page.as_bytes_mut();
932 for byte in &mut data[INTERIOR_DATA_OFFSET..] {
933 *byte = 0;
934 }
935 }
936 page.set_cell_count(0);
937 page.set_free_start(INTERIOR_DATA_OFFSET as u16);
938 page.set_free_end(PAGE_SIZE as u16);
939}