1use crate::common::Position;
3use crate::common::{PageID, Tsn};
4use crate::events_tree_nodes::EventLeafNode;
5use crate::free_lists_tree_nodes::{
6 FreeListInternalNode, FreeListLeafNode, FreeListLeafValue, FreeListTsnLeafNode,
7};
8use crate::header_node::HeaderNode;
9use crate::node::Node;
10use crate::page::{PAGE_HEADER_SIZE, Page, serialize_page_into};
11use crate::pager::Pager;
12use crate::tags_tree_nodes::TagsLeafNode;
13use umadb_dcb::{DCBError, DCBResult};
14use dashmap::DashMap;
17use std::collections::HashMap;
18use std::collections::VecDeque;
19use std::path::Path;
20use std::sync::atomic::{AtomicUsize, Ordering};
21use std::sync::{Arc, Mutex};
22use std::thread::sleep;
23use std::time::Duration;
24const GET_LATEST_HEADER_RETRIES: usize = 5;
27const GET_LATEST_HEADER_DELAY: Duration = Duration::from_millis(10);
28const HEADER_PAGE_ID_0: PageID = PageID(0);
29const HEADER_PAGE_ID_1: PageID = PageID(1);
30
31pub struct Mvcc {
37 pub pager: Pager,
38 pub reader_tsns: Arc<DashMap<usize, Tsn>>,
39 pub writer_lock: Mutex<()>,
40 pub page_size: usize,
41 pub max_node_size: usize,
42 pub headers: Mutex<Vec<Page>>,
44 pub header_page_buf: Mutex<Vec<u8>>,
46 pub page_buf: Mutex<Vec<u8>>,
48 reader_id_counter: AtomicUsize,
49 pub verbose: bool,
50}
51
52impl Mvcc {
53 pub fn new(path: &Path, page_size: usize, verbose: bool) -> DCBResult<Self> {
54 let pager = Pager::new(path, page_size)?;
55
56 let mvcc = Self {
57 pager,
58 reader_tsns: Arc::new(DashMap::new()),
59 writer_lock: Mutex::new(()),
60 page_size,
61 max_node_size: page_size - PAGE_HEADER_SIZE,
62 headers: Mutex::new(vec![
63 Page {
64 page_id: PageID(0),
65 node: Node::Header(HeaderNode::default()),
66 },
67 Page {
68 page_id: PageID(1),
69 node: Node::Header(HeaderNode::default()),
70 },
71 ]),
72 header_page_buf: Mutex::new(vec![0u8; page_size]),
73 page_buf: Mutex::new(vec![0u8; page_size]),
74 reader_id_counter: AtomicUsize::new(0),
75 verbose,
76 };
77
78 if mvcc.pager.is_file_new {
79 let initial_tsn = Tsn(0);
81 let initial_free_lists_tree_root_id = PageID(2);
82 let initial_events_tree_root_id = PageID(3);
83 let initial_tags_tree_root_id = PageID(4);
84 let initial_next_page_id = PageID(5);
85 let initial_next_position = Position(1);
86 mvcc.update_header(
87 HEADER_PAGE_ID_0,
88 initial_tsn,
89 initial_free_lists_tree_root_id,
90 initial_events_tree_root_id,
91 initial_tags_tree_root_id,
92 initial_next_page_id,
93 initial_next_position,
94 )?;
95 mvcc.update_header(
96 HEADER_PAGE_ID_1,
97 initial_tsn,
98 initial_free_lists_tree_root_id,
99 initial_events_tree_root_id,
100 initial_tags_tree_root_id,
101 initial_next_page_id,
102 initial_next_position,
103 )?;
104
105 let free_list_leaf = FreeListLeafNode {
107 keys: Vec::new(),
108 values: Vec::new(),
109 };
110 let free_list_page = Page::new(
111 initial_free_lists_tree_root_id,
112 Node::FreeListLeaf(free_list_leaf),
113 );
114
115 let event_leaf = EventLeafNode {
117 keys: Vec::new(),
118 values: Vec::new(),
119 };
120 let position_page = Page::new(initial_events_tree_root_id, Node::EventLeaf(event_leaf));
121
122 let tags_leaf = TagsLeafNode {
124 keys: Vec::new(),
125 values: Vec::new(),
126 };
127 let tags_page = Page::new(initial_tags_tree_root_id, Node::TagsLeaf(tags_leaf));
128
129 let _ = mvcc.write_pages([&free_list_page, &position_page, &tags_page].into_iter())?;
131
132 mvcc.flush()?;
133 }
134
135 Ok(mvcc)
136 }
137
138 pub fn get_latest_header(&self) -> DCBResult<(PageID, HeaderNode)> {
139 for attempt in 0..GET_LATEST_HEADER_RETRIES {
140 let h0 = self.read_header(HEADER_PAGE_ID_0);
141 let h1 = self.read_header(HEADER_PAGE_ID_1);
142
143 match (h0, h1) {
144 (Ok(header0), Ok(header1)) => {
145 if header1.tsn > header0.tsn {
146 return Ok((HEADER_PAGE_ID_1, header1));
147 } else {
148 return Ok((HEADER_PAGE_ID_0, header0));
149 }
150 }
151 (Ok(header0), Err(_)) => {
152 return Ok((HEADER_PAGE_ID_0, header0));
153 }
154 (Err(_), Ok(header1)) => {
155 return Ok((HEADER_PAGE_ID_1, header1));
156 }
157 (Err(e0), Err(e1)) => {
158 if attempt + 1 < GET_LATEST_HEADER_RETRIES {
159 if self.verbose {
160 println!(
161 "Both headers invalid on attempt {}: {:?} | {:?}. Retrying...",
162 attempt + 1,
163 e0,
164 e1
165 );
166 }
167 sleep(GET_LATEST_HEADER_DELAY);
168 continue;
169 } else {
170 return Err(DCBError::DatabaseCorrupted(format!(
171 "Both header pages appear corrupted after {} attempts: ({:?}) and ({:?})",
172 GET_LATEST_HEADER_RETRIES, e0, e1
173 )));
174 }
175 }
176 }
177 }
178 Err(DCBError::DatabaseCorrupted(
180 "Unable to read a valid header".to_string(),
181 ))
182 }
183
184 pub fn read_header(&self, page_id: PageID) -> DCBResult<HeaderNode> {
185 let page = self.read_page(page_id)?;
186 match page.node {
187 Node::Header(node) => Ok(node),
188 _ => Err(DCBError::DatabaseCorrupted(
189 "Invalid header node type".to_string(),
190 )),
191 }
192 }
193
194 fn update_header(
195 &self,
196 page_id: PageID,
197 tsn: Tsn,
198 free_lists_tree_root_id: PageID,
199 events_tree_root_id: PageID,
200 tags_tree_root_id: PageID,
201 next_page_id: PageID,
202 next_position: Position,
203 ) -> DCBResult<()> {
204 let mut headers = self.headers.lock().unwrap();
205 let headers_idx = { if page_id == HEADER_PAGE_ID_0 { 0 } else { 1 } };
206 let header = &mut headers[headers_idx];
207 match &mut header.node {
208 Node::Header(node) => {
209 node.tsn = tsn;
211 node.free_lists_tree_root_id = free_lists_tree_root_id;
212 node.events_tree_root_id = events_tree_root_id;
213 node.tags_tree_root_id = tags_tree_root_id;
214 node.next_page_id = next_page_id;
215 node.next_position = next_position;
216
217 let mut buf = self.page_buf.lock().unwrap();
219 serialize_page_into(&mut buf, &header.node)?;
220 self.pager.write_page(page_id, &buf)?;
221 Ok(())
222 }
223 _ => panic!("Shouldn't get here: header should be a header"),
224 }
225 }
226
227 pub fn read_page(&self, page_id: PageID) -> DCBResult<Page> {
228 let mapped = self.pager.read_page_mmap_slice(page_id)?;
229 if self.verbose {
230 println!("Read {page_id:?} from file, deserializing...");
231 }
232 Page::deserialize(page_id, mapped.as_slice())
233 }
234
235 pub fn flush(&self) -> DCBResult<()> {
236 self.pager.flush()?;
237 Ok(())
238 }
239
240 pub fn reader(&self) -> DCBResult<Reader> {
241 let (header_page_id, header_node) = self.get_latest_header()?;
242
243 let reader_id = self.reader_id_counter.fetch_add(1, Ordering::Relaxed) + 1;
245
246 self.reader_tsns.insert(reader_id, header_node.tsn);
248
249 let reader = Reader {
251 header_page_id,
252 tsn: header_node.tsn,
253 events_tree_root_id: header_node.events_tree_root_id,
254 tags_tree_root_id: header_node.tags_tree_root_id,
255 next_position: header_node.next_position,
256 reader_id,
257 reader_tsns: Arc::clone(&self.reader_tsns),
258 };
259
260 Ok(reader)
261 }
262
263 pub fn writer(&self) -> DCBResult<Writer> {
264 if self.verbose {
265 println!();
266 println!("Constructing writer...");
267 }
268
269 let (header_page_id, header_node) = self.get_latest_header()?;
271
272 let mut writer = Writer::new(
274 header_page_id,
275 Tsn(header_node.tsn.0 + 1),
276 header_node.next_page_id,
277 header_node.free_lists_tree_root_id,
278 header_node.events_tree_root_id,
279 header_node.tags_tree_root_id,
280 header_node.next_position,
281 self.verbose,
282 );
283
284 if self.verbose {
285 println!("Constructed writer with {:?}", writer.tsn);
286 }
287
288 writer.find_reusable_page_ids(self)?;
290
291 Ok(writer)
292 }
293
294 pub fn write_pages<'a, I>(&self, pages: I) -> DCBResult<usize>
297 where
298 I: IntoIterator<Item = &'a Page>,
299 {
300 let mut buf = self.page_buf.lock().unwrap();
301 let mut count = 0usize;
302 for page in pages {
303 page.serialize_into(&mut buf)?;
304 self.pager.write_page(page.page_id, &buf)?;
305 if self.verbose {
306 println!("Wrote {:?} to file", page.page_id);
307 }
308 count += 1;
309 }
310 Ok(count)
311 }
312
313 pub fn commit(&self, writer: &mut Writer) -> DCBResult<()> {
351 if self.verbose {
353 println!();
354 println!("Commiting writer with {:?}", writer.tsn);
355 }
356
357 while !writer.reused_page_ids.is_empty() || !writer.freed_page_ids.is_empty() {
358 while let Some((reused_page_id, tsn)) = writer.reused_page_ids.pop_front() {
360 writer.remove_free_page_id(self, tsn, reused_page_id)?;
362 }
363
364 while let Some(freed_page_id) = writer.freed_page_ids.pop_front() {
366 writer.dirty.remove(&freed_page_id);
368
369 writer.insert_freed_page_id(self, writer.tsn, freed_page_id)?;
371 }
372 }
373
374 if !writer.dirty.is_empty() {
376 let count = {
377 self.write_pages(writer.dirty.values())?
385 };
386 if self.verbose {
387 println!("Wrote {} dirty page(s) to file", count);
388 }
389 }
390
391 self.flush()?;
393
394 self.update_header(
396 if writer.header_page_id == HEADER_PAGE_ID_0 {
397 HEADER_PAGE_ID_1
398 } else {
399 HEADER_PAGE_ID_0
400 },
401 writer.tsn,
402 writer.free_lists_tree_root_id,
403 writer.events_tree_root_id,
404 writer.tags_tree_root_id,
405 writer.next_page_id,
406 writer.next_position,
407 )?;
408
409 self.flush()?;
411
412 if self.verbose {
413 println!("Committed writer with {:?}", writer.tsn);
414 }
415
416 Ok(())
417 }
418}
419
420pub struct Writer {
422 pub header_page_id: PageID,
423 pub tsn: Tsn,
424 pub next_page_id: PageID,
425 pub free_lists_tree_root_id: PageID,
426 pub events_tree_root_id: PageID,
427 pub tags_tree_root_id: PageID,
428 pub next_position: Position,
429 pub reusable_page_ids: VecDeque<(PageID, Tsn)>,
430 pub freed_page_ids: VecDeque<PageID>,
431 pub deserialized: HashMap<PageID, Page>,
432 pub dirty: HashMap<PageID, Page>,
433 pub reused_page_ids: VecDeque<(PageID, Tsn)>,
434 pub verbose: bool,
435}
436
437impl Writer {
438 pub fn new(
439 header_page_id: PageID,
440 tsn: Tsn,
441 next_page_id: PageID,
442 free_lists_tree_root_id: PageID,
443 events_tree_root_id: PageID,
444 tags_tree_root_id: PageID,
445 next_position: Position,
446 verbose: bool,
447 ) -> Self {
448 Self {
449 header_page_id,
450 tsn,
451 next_page_id,
452 free_lists_tree_root_id,
453 events_tree_root_id,
454 tags_tree_root_id,
455 next_position,
456 reusable_page_ids: VecDeque::new(),
457 freed_page_ids: VecDeque::new(),
458 deserialized: HashMap::new(),
459 dirty: HashMap::new(),
460 reused_page_ids: VecDeque::new(),
461 verbose,
462 }
463 }
464
465 pub fn issue_position(&mut self) -> Position {
471 let pos = self.next_position;
472 self.next_position = Position(self.next_position.0 + 1);
473 pos
474 }
475
476 pub fn get_page_ref(&mut self, mvcc: &Mvcc, page_id: PageID) -> DCBResult<&Page> {
490 if self.dirty.contains_key(&page_id) {
492 return Ok(self.dirty.get(&page_id).unwrap());
493 }
494
495 if self.deserialized.contains_key(&page_id) {
497 return Ok(self.deserialized.get(&page_id).unwrap());
498 }
499
500 let deserialized_page = mvcc.read_page(page_id)?;
502 self.insert_deserialized(deserialized_page);
503
504 Ok(self.deserialized.get(&page_id).unwrap())
506 }
507
508 pub fn get_mut_dirty(&mut self, page_id: PageID) -> DCBResult<&mut Page> {
509 if let Some(page) = self.dirty.get_mut(&page_id) {
510 Ok(page)
511 } else {
512 Err(DCBError::DirtyPageNotFound(page_id.0))
513 }
514 }
515
516 pub fn insert_deserialized(&mut self, page: Page) {
517 self.deserialized.insert(page.page_id, page);
518 }
519
520 pub fn insert_dirty(&mut self, page: Page) -> DCBResult<()> {
521 if self.freed_page_ids.contains(&page.page_id) {
522 return Err(DCBError::PageAlreadyFreed(page.page_id.0));
523 }
524 if self.dirty.contains_key(&page.page_id) {
525 return Err(DCBError::PageAlreadyDirty(page.page_id.0));
526 }
527 self.dirty.insert(page.page_id, page);
528 Ok(())
529 }
530
531 pub fn alloc_page_id(&mut self) -> PageID {
532 if let Some((free_page_id, tsn)) = self.reusable_page_ids.pop_front() {
533 self.reused_page_ids.push_back((free_page_id, tsn));
534 return free_page_id;
535 }
536
537 let next_page_id = self.next_page_id;
538 self.next_page_id = PageID(next_page_id.0 + 1);
539 next_page_id
540 }
541
542 pub fn get_dirty_page_id(&mut self, page_id: PageID) -> DCBResult<PageID> {
543 let mut dirty_page_id = page_id;
544 if !self.freed_page_ids.iter().any(|&id| id == page_id) {
545 if !self.dirty.contains_key(&page_id) {
546 let old_page_id = page_id;
547 self.freed_page_ids.push_back(old_page_id);
548
549 let new_page_id = self.alloc_page_id();
550 let old_page = self.deserialized.get(&old_page_id).unwrap();
551 let new_page = Page {
552 page_id: new_page_id,
553 node: old_page.node.clone(),
554 };
555
556 self.dirty.insert(new_page_id, new_page);
557 if self.verbose {
558 println!(
559 "Copied {:?} to {:?}: {:?}",
560 old_page_id, new_page_id, old_page.node
561 );
562 }
563 dirty_page_id = new_page_id;
564 } else if self.verbose {
565 println!("{page_id:?} is already dirty");
566 }
567 } else {
568 return Err(DCBError::PageAlreadyFreed(page_id.0));
569 }
570 Ok(dirty_page_id)
571 }
572
573 pub fn append_freed_page_id(&mut self, page_id: PageID) {
574 let verbose = self.verbose;
575 if !self.freed_page_ids.iter().any(|&id| id == page_id) {
576 self.freed_page_ids.push_back(page_id);
577 if verbose {
578 println!("Appended {page_id:?} to freed_page_ids");
579 }
580 if self.dirty.contains_key(&page_id) {
581 self.dirty.remove(&page_id);
582 if verbose {
583 println!("Page ID {page_id:?} was in dirty and was removed");
584 }
585 }
586 if verbose && self.dirty.contains_key(&page_id) {
587 println!("Page ID {page_id:?} is still in dirty!!!!!");
588 }
589 }
590 }
591
592 pub fn find_reusable_page_ids(&mut self, mvcc: &Mvcc) -> DCBResult<()> {
593 let verbose = self.verbose;
594 let mut reusable_page_ids: VecDeque<(PageID, Tsn)> = VecDeque::new();
595 if verbose {
597 println!("Finding reusable page IDs for TSN {:?}...", self.tsn);
598 }
599
600 let smallest_reader_tsn = mvcc.reader_tsns.iter().map(|r| *r.value()).min();
602 if verbose {
603 println!("Smallest reader TSN: {smallest_reader_tsn:?}");
604 }
605
606 if verbose {
607 println!("Root is {:?}", self.free_lists_tree_root_id);
608 }
609 let mut stack = vec![(self.free_lists_tree_root_id, 0)];
611 let mut is_finished = false;
612
613 while let Some((page_id, idx)) = stack.pop() {
614 if is_finished {
615 break;
616 }
617 let node_owned = {
618 match self.get_page_ref(mvcc, page_id) {
619 Ok(p) => p.node.clone(),
620 Err(e) => {
621 return Err(DCBError::DatabaseCorrupted(format!(
622 "Free list page {:?} load error: {:?}",
623 page_id, e
624 )));
625 }
626 }
627 };
628 match node_owned {
629 Node::FreeListInternal(node) => {
630 if verbose {
631 println!("{:?} is internal node", page_id);
632 }
633 if idx < node.child_ids.len() {
634 let child_page_id = node.child_ids[idx];
635 stack.push((page_id, idx + 1));
636 stack.push((child_page_id, 0));
637 }
638 }
639 Node::FreeListLeaf(node) => {
640 if verbose {
641 println!("{:?} is leaf node", page_id);
642 }
643 for i in 0..node.keys.len() {
644 let tsn = node.keys[i];
645 if let Some(smallest) = smallest_reader_tsn
646 && tsn > smallest
647 {
648 is_finished = true;
649 break;
650 }
651
652 let leaf_value = &node.values[i];
653 if leaf_value.root_id == PageID(0) {
654 for &page_id in &leaf_value.page_ids {
655 reusable_page_ids.push_back((page_id, tsn));
656 }
657 } else {
658 let mut tsn_stack: Vec<(PageID, usize)> = vec![(leaf_value.root_id, 0)];
662 if self.verbose {
663 println!("TSN-subtree root_id: {:?}", leaf_value.root_id);
664 }
665 if self.verbose {
666 println!(
667 "root_id in dirty? {}",
668 self.dirty.contains_key(&leaf_value.root_id)
669 );
670 }
671 while let Some((sub_id, sidx)) = tsn_stack.pop() {
672 let sub_node = {
673 match self.get_page_ref(mvcc, sub_id) {
674 Ok(p) => p.node.clone(),
675 Err(e) => {
676 return Err(DCBError::DatabaseCorrupted(format!(
677 "TSN subtree page {:?} load error: {:?}",
678 sub_id, e
679 )));
680 }
681 }
682 };
683 match sub_node {
684 Node::FreeListTsnInternal(tsn_internal) => {
685 if sidx < tsn_internal.child_ids.len() {
686 let child_id = tsn_internal.child_ids[sidx];
687 tsn_stack.push((sub_id, sidx + 1));
688 tsn_stack.push((child_id, 0));
689 }
690 }
691 Node::FreeListTsnLeaf(tsn_leaf) => {
692 for &pid in &tsn_leaf.page_ids {
693 reusable_page_ids.push_back((pid, tsn));
694 }
695 }
696 other => {
697 return Err(DCBError::DatabaseCorrupted(format!(
698 "Invalid node type in TSN subtree: {}",
699 other.type_name()
700 )));
701 }
702 }
703 }
704 }
705 }
706 }
707 _ => {
708 return Err(DCBError::DatabaseCorrupted(
709 "Invalid node type in free list tree".to_string(),
710 ));
711 }
712 }
713 }
714
715 self.reusable_page_ids = reusable_page_ids;
716 if verbose {
717 println!("Found reusable page IDs: {:?}", self.reusable_page_ids);
718 }
719 Ok(())
720 }
721
722 pub fn insert_freed_page_id(
724 &mut self,
725 mvcc: &Mvcc,
726 tsn: Tsn,
727 freed_page_id: PageID,
728 ) -> DCBResult<()> {
729 let verbose = self.verbose;
730 if verbose {
731 println!("Inserting {freed_page_id:?} for {tsn:?}");
732 println!("Root is {:?}", self.free_lists_tree_root_id);
733 }
734 let mut current_page_id = self.free_lists_tree_root_id;
736
737 let mut stack: Vec<PageID> = Vec::new();
739 let plan: FreePageIDInsertStrategy;
740 loop {
741 let current_page_ref = self.get_page_ref(mvcc, current_page_id)?;
742 if let Node::FreeListLeaf(leaf_node) = ¤t_page_ref.node {
743 let len_keys = leaf_node.keys.len();
744 if len_keys == 0 {
745 if !leaf_node.would_fit_new_tsn_and_page_id(mvcc.max_node_size) {
746 return Err(DCBError::InternalError("Page size too small".to_string()));
747 }
748 plan = FreePageIDInsertStrategy::PushTsnOntoFreeListLeaf;
749 } else {
750 let last_idx = len_keys - 1;
751 let last_key = leaf_node.keys[last_idx];
752 if tsn == last_key {
753 if leaf_node.values[last_idx].root_id != PageID(0) {
755 plan = FreePageIDInsertStrategy::PushPageIdOntoExistingTsnSubtree;
756 } else if leaf_node.would_fit_new_page_id(mvcc.max_node_size) {
757 plan = FreePageIDInsertStrategy::PushPageIdOntoFreeListLeaf(last_idx);
758 } else if leaf_node.keys.len() == 1 {
759 plan = FreePageIDInsertStrategy::MoveTsnToNewTsnSubtree;
760 } else {
761 plan = FreePageIDInsertStrategy::SplitFreeListLeaf;
762 }
763 } else if tsn > last_key {
764 if leaf_node.would_fit_new_tsn_and_page_id(mvcc.max_node_size) {
766 plan = FreePageIDInsertStrategy::PushTsnOntoFreeListLeaf;
767 } else {
768 plan = FreePageIDInsertStrategy::CreateAndPromoteFreeListLeaf;
769 }
770 } else {
771 return Err(DCBError::InternalError(
773 "Insertion only supported for last TSN in leaf".to_string(),
774 ));
775 }
776 }
777 break;
778 }
779 if let Node::FreeListInternal(internal_node) = ¤t_page_ref.node {
780 if verbose {
781 println!("{:?} is internal node", current_page_ref.page_id);
782 }
783 stack.push(current_page_id);
784 current_page_id = *internal_node
785 .child_ids
786 .last()
787 .expect("FreeListInternal node should have a child");
788 } else {
789 return Err(DCBError::DatabaseCorrupted(
790 "Expected FreeListInternal node".to_string(),
791 ));
792 }
793 }
794 if verbose {
795 println!("{current_page_id:?} is leaf node");
796 }
797 let dirty_leaf_page_id = { self.get_dirty_page_id(current_page_id)? };
799 let replacement_info: Option<(PageID, PageID)> = {
800 if dirty_leaf_page_id != current_page_id {
801 Some((current_page_id, dirty_leaf_page_id))
802 } else {
803 None
804 }
805 };
806 let mut split_info: Option<(Tsn, PageID)> = None;
808
809 match plan {
811 FreePageIDInsertStrategy::PushPageIdOntoExistingTsnSubtree => {
812 let leaf_snapshot = { self.get_page_ref(mvcc, dirty_leaf_page_id)? };
814 let Node::FreeListLeaf(leaf_ro) = &leaf_snapshot.node else {
815 return Err(DCBError::DatabaseCorrupted(
816 "Expected FreeListLeaf node".to_string(),
817 ));
818 };
819 let last_idx = leaf_ro.keys.len() - 1;
820 let tsn_root_id = leaf_ro.values[last_idx].root_id;
821 if tsn_root_id == PageID(0) {
822 return Err(DCBError::DatabaseCorrupted(
823 "Expected TSN-subtree root_id to be set".to_string(),
824 ));
825 }
826 let new_root_id = self.tsn_subtree_insert(mvcc, tsn_root_id, freed_page_id)?;
827 if new_root_id != tsn_root_id {
828 let dirty_leaf_page = self.get_mut_dirty(dirty_leaf_page_id)?;
830 let Node::FreeListLeaf(dirty_leaf_node2) = &mut dirty_leaf_page.node else {
831 return Err(DCBError::DatabaseCorrupted(
832 "Expected FreeListLeaf node".to_string(),
833 ));
834 };
835 dirty_leaf_node2.values[last_idx].root_id = new_root_id;
836 }
837 }
838 FreePageIDInsertStrategy::MoveTsnToNewTsnSubtree => {
839 let leaf_snapshot = { self.get_page_ref(mvcc, dirty_leaf_page_id)? };
841 let Node::FreeListLeaf(leaf_ro) = &leaf_snapshot.node else {
842 return Err(DCBError::DatabaseCorrupted(
843 "Expected FreeListLeaf node".to_string(),
844 ));
845 };
846 let last_idx = leaf_ro.keys.len() - 1;
847 let mut page_ids = leaf_ro.values[last_idx].page_ids.clone();
848 page_ids.push(freed_page_id);
849 page_ids.sort_by_key(|pid| pid.0);
851 page_ids.dedup();
852 let mut initial_ids: Vec<PageID> = Vec::new();
855 let mut tmp_leaf = FreeListTsnLeafNode {
856 page_ids: Vec::new(),
857 };
858 for pid in &page_ids {
859 let mut candidate = tmp_leaf.clone();
860 candidate.page_ids.push(*pid);
861 let candidate_page = Page::new(PageID(0), Node::FreeListTsnLeaf(candidate));
862 if candidate_page.calc_serialized_size() <= mvcc.page_size {
863 tmp_leaf.page_ids.push(*pid);
864 initial_ids.push(*pid);
865 } else {
866 break;
867 }
868 }
869 if initial_ids.is_empty() {
870 return Err(DCBError::InternalError(
871 "Page size too small for TSN-subtree leaf with one PageID".to_string(),
872 ));
873 }
874 let tsn_leaf_id = self.alloc_page_id();
875 let tsn_leaf_page = Page::new(tsn_leaf_id, Node::FreeListTsnLeaf(tmp_leaf));
876 self.insert_dirty(tsn_leaf_page)?;
877 let mut tsn_root_id = tsn_leaf_id;
879 for pid in page_ids.into_iter().filter(|p| !initial_ids.contains(p)) {
881 tsn_root_id = self.tsn_subtree_insert(mvcc, tsn_root_id, pid)?;
882 }
883 let dirty_leaf_page = self.get_mut_dirty(dirty_leaf_page_id)?;
885 let Node::FreeListLeaf(dirty_leaf_node2) = &mut dirty_leaf_page.node else {
886 return Err(DCBError::DatabaseCorrupted(
887 "Expected FreeListLeaf node".to_string(),
888 ));
889 };
890 dirty_leaf_node2.values[last_idx].page_ids.clear();
891 dirty_leaf_node2.values[last_idx].root_id = tsn_root_id;
892 if verbose {
893 println!("Moved inline page IDs to TSN-subtree {:?}", tsn_root_id);
894 }
895 }
896 _ => { }
897 }
898
899 let dirty_leaf_page = self.get_mut_dirty(dirty_leaf_page_id)?;
901 if let Node::FreeListLeaf(dirty_leaf_node) = &mut dirty_leaf_page.node {
902 match plan {
903 FreePageIDInsertStrategy::PushTsnOntoFreeListLeaf => {
904 dirty_leaf_node.push_new_key_and_value(tsn, freed_page_id);
905 if verbose {
906 println!(
907 "Inserted first pair ({tsn:?} -> {freed_page_id:?}) in {dirty_leaf_page_id:?}: {:?}",
908 dirty_leaf_node
909 );
910 }
911 }
912 FreePageIDInsertStrategy::PushPageIdOntoFreeListLeaf(last_idx) => {
913 dirty_leaf_node.push_new_page_id(last_idx, freed_page_id);
914 if verbose {
915 println!(
916 "Appended {freed_page_id:?} for existing last {tsn:?} in {dirty_leaf_page_id:?}: {:?}",
917 dirty_leaf_node
918 );
919 }
920 }
921 FreePageIDInsertStrategy::PushPageIdOntoExistingTsnSubtree => { }
923 FreePageIDInsertStrategy::MoveTsnToNewTsnSubtree => { }
924 FreePageIDInsertStrategy::SplitFreeListLeaf => {
925 let (popped_key, mut popped_value) =
926 dirty_leaf_node.pop_last_key_and_value()?;
927 debug_assert_eq!(popped_key, tsn);
928 if verbose {
929 println!(
930 "Split (last TSN) leaf {:?}: {:?}",
931 dirty_leaf_page_id,
932 dirty_leaf_node.clone()
933 );
934 }
935 popped_value.page_ids.push(freed_page_id);
937 let new_leaf_node = FreeListLeafNode {
938 keys: vec![popped_key],
939 values: vec![popped_value],
940 };
941 let new_leaf_page_id = self.alloc_page_id();
942 let new_leaf_page =
943 Page::new(new_leaf_page_id, Node::FreeListLeaf(new_leaf_node));
944 if verbose {
951 println!(
952 "Created new leaf {:?} (moved last TSN): {:?}",
953 new_leaf_page_id, new_leaf_page.node
954 );
955 }
956 self.insert_dirty(new_leaf_page)?;
957 split_info = Some((tsn, new_leaf_page_id));
958 }
959 FreePageIDInsertStrategy::CreateAndPromoteFreeListLeaf => {
960 let new_leaf_node = FreeListLeafNode {
962 keys: vec![tsn],
963 values: vec![FreeListLeafValue {
964 page_ids: vec![freed_page_id],
965 root_id: PageID(0),
966 }],
967 };
968 let new_leaf_page_id = self.alloc_page_id();
969 let new_leaf_page =
970 Page::new(new_leaf_page_id, Node::FreeListLeaf(new_leaf_node));
971 if verbose {
978 println!(
979 "Created new leaf {:?} (new last TSN): {:?}",
980 new_leaf_page_id, new_leaf_page.node
981 );
982 }
983 self.insert_dirty(new_leaf_page)?;
984 split_info = Some((tsn, new_leaf_page_id));
985 }
986 }
987 } else {
988 return Err(DCBError::DatabaseCorrupted(
989 "Expected FreeListLeaf node".to_string(),
990 ));
991 }
992 let mut current_replacement_info = replacement_info;
994 while let Some(parent_page_id) = stack.pop() {
995 let dirty_page_id = { self.get_dirty_page_id(parent_page_id)? };
997 let parent_replacement_info: Option<(PageID, PageID)> = {
998 if dirty_page_id != parent_page_id {
999 Some((parent_page_id, dirty_page_id))
1000 } else {
1001 None
1002 }
1003 };
1004 let dirty_internal_page = self.get_mut_dirty(dirty_page_id)?;
1006
1007 if let Node::FreeListInternal(dirty_internal_node) = &mut dirty_internal_page.node {
1008 if let Some((old_id, new_id)) = current_replacement_info {
1009 dirty_internal_node.replace_last_child_id(old_id, new_id)?;
1010 if verbose {
1011 println!(
1012 "Replaced {old_id:?} with {new_id:?} in {dirty_page_id:?}: {dirty_internal_node:?}"
1013 );
1014 }
1015 } else if verbose {
1016 println!("Nothing to replace in {dirty_page_id:?}")
1017 }
1018 } else {
1019 return Err(DCBError::DatabaseCorrupted(
1020 "Expected FreeListInternal node".to_string(),
1021 ));
1022 }
1023
1024 if let Some((promoted_key, promoted_page_id)) = split_info {
1025 if let Node::FreeListInternal(dirty_internal_node) = &mut dirty_internal_page.node {
1026 dirty_internal_node
1028 .append_promoted_key_and_page_id(promoted_key, promoted_page_id)?;
1029
1030 if verbose {
1031 println!(
1032 "Appended promoted key {promoted_key:?} and child {promoted_page_id:?} in {dirty_page_id:?}: {dirty_internal_node:?}"
1033 );
1034 }
1035 } else {
1036 return Err(DCBError::DatabaseCorrupted(
1037 "Expected FreeListInternal node".to_string(),
1038 ));
1039 }
1040 }
1041
1042 if dirty_internal_page.calc_serialized_size() > mvcc.page_size {
1045 if let Node::FreeListInternal(dirty_internal_node) = &mut dirty_internal_page.node {
1046 if verbose {
1047 println!("Splitting internal {dirty_page_id:?}...");
1048 }
1049 if dirty_internal_node.keys.len() < 3 || dirty_internal_node.child_ids.len() < 4
1052 {
1053 return Err(DCBError::DatabaseCorrupted(
1054 "Cannot split internal node with too few keys/children".to_string(),
1055 ));
1056 }
1057
1058 let (promoted_key, new_keys, new_child_ids) =
1060 dirty_internal_node.split_off()?;
1061
1062 assert_eq!(
1064 dirty_internal_node.keys.len() + 1,
1065 dirty_internal_node.child_ids.len()
1066 );
1067
1068 let new_internal_node = FreeListInternalNode {
1069 keys: new_keys,
1070 child_ids: new_child_ids,
1071 };
1072
1073 assert_eq!(
1075 new_internal_node.keys.len() + 1,
1076 new_internal_node.child_ids.len()
1077 );
1078
1079 let new_internal_page_id = self.alloc_page_id();
1081 let new_internal_page = Page::new(
1082 new_internal_page_id,
1083 Node::FreeListInternal(new_internal_node),
1084 );
1085 if verbose {
1086 println!(
1087 "Created internal {:?}: {:?}",
1088 new_internal_page_id, new_internal_page.node
1089 );
1090 }
1091 self.insert_dirty(new_internal_page)?;
1092
1093 split_info = Some((promoted_key, new_internal_page_id));
1094 } else {
1095 return Err(DCBError::DatabaseCorrupted(
1096 "Expected FreeListInternal node".to_string(),
1097 ));
1098 }
1099 } else {
1100 split_info = None;
1101 }
1102 current_replacement_info = parent_replacement_info;
1103 }
1104
1105 if let Some((old_id, new_id)) = current_replacement_info {
1106 if self.free_lists_tree_root_id == old_id {
1107 self.free_lists_tree_root_id = new_id;
1108 if verbose {
1109 println!("Replaced root {old_id:?} with {new_id:?}");
1110 }
1111 } else {
1112 return Err(DCBError::RootIDMismatch(old_id.0, new_id.0));
1113 }
1114 }
1115
1116 if let Some((promoted_key, promoted_page_id)) = split_info {
1117 let new_internal_node = FreeListInternalNode {
1119 keys: vec![promoted_key],
1120 child_ids: vec![self.free_lists_tree_root_id, promoted_page_id],
1121 };
1122
1123 let new_root_page_id = self.alloc_page_id();
1124 let new_root_page =
1125 Page::new(new_root_page_id, Node::FreeListInternal(new_internal_node));
1126 if verbose {
1127 println!(
1128 "Created new internal root {:?}: {:?}",
1129 new_root_page_id, new_root_page.node
1130 );
1131 }
1132 self.insert_dirty(new_root_page)?;
1133
1134 self.free_lists_tree_root_id = new_root_page_id;
1135 }
1136
1137 Ok(())
1138 }
1139
1140 fn tsn_subtree_insert(
1143 &mut self,
1144 mvcc: &Mvcc,
1145 root_id: PageID,
1146 key: PageID,
1147 ) -> DCBResult<PageID> {
1148 let verbose = self.verbose;
1149 let mut stack: Vec<(PageID, usize)> = Vec::new();
1150 let mut current_id = root_id;
1151 loop {
1152 let current_page_ref = self.get_page_ref(mvcc, current_id)?;
1153 match ¤t_page_ref.node {
1154 Node::FreeListTsnLeaf(_) => break,
1155 Node::FreeListTsnInternal(internal) => {
1156 let child_idx = match internal.keys.binary_search_by(|k| k.0.cmp(&key.0)) {
1157 Ok(idx) => idx + 1, Err(idx) => idx, };
1160 let next_id = internal.child_ids[child_idx];
1161 stack.push((current_id, child_idx));
1162 current_id = next_id;
1163 }
1164 other => {
1165 return Err(DCBError::DatabaseCorrupted(format!(
1166 "Unexpected node type in TSN-subtree during insert: {}",
1167 other.type_name()
1168 )));
1169 }
1170 }
1171 }
1172
1173 {
1176 let leaf_page = self.get_mut_dirty(current_id)?;
1177 let Node::FreeListTsnLeaf(ref mut leaf) = leaf_page.node else {
1178 return Err(DCBError::DatabaseCorrupted(
1179 "Expected TSN-subtree leaf".to_string(),
1180 ));
1181 };
1182 match leaf.page_ids.binary_search_by(|pid| pid.0.cmp(&key.0)) {
1184 Ok(_) => {
1185 if verbose {
1187 println!("Duplicate PageID {:?} ignored in TSN-subtree", key);
1188 }
1189 }
1190 Err(ins) => {
1191 leaf.page_ids.insert(ins, key);
1192 if leaf.calc_serialized_size() <= mvcc.max_node_size {
1193 return Ok(root_id);
1194 }
1195 let mid = leaf.page_ids.len() / 2; let right_ids: Vec<PageID> = leaf.page_ids.split_off(mid);
1198 let promoted_key = right_ids[0];
1199 let right_leaf_id = self.alloc_page_id();
1201 let right_leaf_node = FreeListTsnLeafNode {
1202 page_ids: right_ids,
1203 };
1204 let right_leaf_page =
1205 Page::new(right_leaf_id, Node::FreeListTsnLeaf(right_leaf_node));
1206 self.insert_dirty(right_leaf_page)?;
1207 let mut promoted: Option<(PageID, PageID)> =
1209 Some((promoted_key, right_leaf_id));
1210 for (parent_id, child_idx) in stack.into_iter().rev() {
1212 if let Some((prom_key, prom_right_id)) = promoted.take() {
1213 let parent_page = self.get_mut_dirty(parent_id)?;
1214 let Node::FreeListTsnInternal(ref mut parent_node) = parent_page.node
1215 else {
1216 return Err(DCBError::DatabaseCorrupted(
1217 "Expected TSN-subtree internal".to_string(),
1218 ));
1219 };
1220
1221 parent_node.keys.insert(child_idx, prom_key);
1223 parent_node.child_ids.insert(child_idx + 1, prom_right_id);
1224 if parent_node.calc_serialized_size() <= mvcc.max_node_size {
1225 current_id = parent_id;
1227 continue;
1228 }
1229 let total_keys = parent_node.keys.len();
1231 debug_assert!(
1232 total_keys >= 2,
1233 "splitting parent with <2 keys after insert"
1234 );
1235 let mid = total_keys / 2; let promote_up_key = parent_node.keys[mid];
1237 let left_keys: Vec<PageID> = parent_node.keys[..mid].to_vec();
1239 let left_child_ids: Vec<PageID> =
1240 parent_node.child_ids[..=mid].to_vec();
1241 let right_keys: Vec<PageID> = parent_node.keys[mid + 1..].to_vec();
1243 let right_child_ids: Vec<PageID> =
1244 parent_node.child_ids[mid + 1..].to_vec();
1245 if right_child_ids.len() != right_keys.len() + 1 {
1246 return Err(DCBError::DatabaseCorrupted(
1247 "TSN-subtree internal split produced invalid right arity"
1248 .to_string(),
1249 ));
1250 }
1251 if left_child_ids.len() != left_keys.len() + 1 {
1252 return Err(DCBError::DatabaseCorrupted(
1253 "TSN-subtree internal split produced invalid left arity"
1254 .to_string(),
1255 ));
1256 }
1257 parent_node.keys = left_keys;
1259 parent_node.child_ids = left_child_ids;
1260 let right_internal_id = self.alloc_page_id();
1262 let right_internal =
1263 crate::free_lists_tree_nodes::FreeListTsnInternalNode {
1264 keys: right_keys,
1265 child_ids: right_child_ids,
1266 };
1267 let right_internal_page = Page::new(
1268 right_internal_id,
1269 Node::FreeListTsnInternal(right_internal),
1270 );
1271 self.insert_dirty(right_internal_page)?;
1272 promoted = Some((promote_up_key, right_internal_id));
1274 }
1275 current_id = parent_id;
1276 }
1277 if let Some((prom_key, prom_right_id)) = promoted.take() {
1279 let new_root_id = self.alloc_page_id();
1280 let left_id = current_id;
1281 let new_root = crate::free_lists_tree_nodes::FreeListTsnInternalNode {
1282 keys: vec![prom_key],
1283 child_ids: vec![left_id, prom_right_id],
1284 };
1285 let new_root_page =
1286 Page::new(new_root_id, Node::FreeListTsnInternal(new_root));
1287 self.insert_dirty(new_root_page)?;
1288 if verbose {
1289 println!("Promoted new TSN-subtree root {:?}", new_root_id);
1290 }
1291 return Ok(new_root_id);
1292 }
1293 }
1294 };
1295 Ok(root_id)
1296 }
1297 }
1298
1299 pub fn remove_free_page_id(
1300 &mut self,
1301 mvcc: &Mvcc,
1302 tsn: Tsn,
1303 used_page_id: PageID,
1304 ) -> DCBResult<()> {
1305 let verbose = self.verbose;
1306 if verbose {
1307 println!();
1308 println!("Removing {used_page_id:?} from {tsn:?}...");
1309 println!("Root is {:?}", self.free_lists_tree_root_id);
1310 }
1311 let mut current_page_id = self.free_lists_tree_root_id;
1313
1314 let mut stack: Vec<PageID> = Vec::new();
1316 let mut removed_page_ids: Vec<PageID> = Vec::new();
1317
1318 loop {
1319 let current_page_ref = self.get_page_ref(mvcc, current_page_id)?;
1320 if matches!(current_page_ref.node, Node::FreeListLeaf(_)) {
1321 break;
1322 }
1323 if let Node::FreeListInternal(internal_node) = ¤t_page_ref.node {
1324 if verbose {
1325 println!("Page {:?} is internal node", current_page_ref.page_id);
1326 }
1327 stack.push(current_page_id);
1328 current_page_id = *internal_node.child_ids.first().unwrap();
1329 } else {
1330 return Err(DCBError::DatabaseCorrupted(
1331 "Expected FreeListInternal node".to_string(),
1332 ));
1333 }
1334 }
1335 if verbose {
1336 println!("Page {current_page_id:?} is leaf node");
1337 }
1338
1339 let mut replacement_info: Option<(PageID, PageID)> = None;
1342 let mut removal_info = None;
1343
1344 let leaf_snapshot = { self.get_page_ref(mvcc, current_page_id)? };
1346 let Node::FreeListLeaf(leaf_node_ro) = &leaf_snapshot.node else {
1347 return Err(DCBError::DatabaseCorrupted(
1348 "Expected FreeListLeaf node".to_string(),
1349 ));
1350 };
1351 if leaf_node_ro.keys.is_empty() || leaf_node_ro.keys[0] != tsn {
1352 return Err(DCBError::DatabaseCorrupted(format!(
1353 "Expected TSN {} not found: {:?}",
1354 tsn.0, leaf_node_ro
1355 )));
1356 }
1357
1358 let leaf_value_root_id = leaf_node_ro.values[0].root_id;
1359 if leaf_value_root_id == PageID(0) {
1365 let dirty_page_id = { self.get_dirty_page_id(current_page_id)? };
1367 if dirty_page_id != current_page_id {
1368 replacement_info = Some((current_page_id, dirty_page_id));
1369 }
1370 let dirty_leaf_page = self.get_mut_dirty(dirty_page_id)?;
1371 if let Node::FreeListLeaf(dirty_leaf_node) = &mut dirty_leaf_page.node {
1372 let leaf_value = &mut dirty_leaf_node.values[0];
1373 if let Some(pos) = leaf_value
1374 .page_ids
1375 .iter()
1376 .position(|&id| id == used_page_id)
1377 {
1378 leaf_value.page_ids.remove(pos);
1379 } else {
1380 return Err(DCBError::DatabaseCorrupted(format!(
1381 "{used_page_id:?} not found in {tsn:?}"
1382 )));
1383 }
1384 if verbose {
1385 println!("Removed {used_page_id:?} from {tsn:?} in {dirty_page_id:?}");
1386 }
1387 if leaf_value.page_ids.is_empty() {
1388 dirty_leaf_node.keys.remove(0);
1389 dirty_leaf_node.values.remove(0);
1390 if verbose {
1391 println!("Removed {tsn:?} from {dirty_page_id:?}");
1392 }
1393 if dirty_leaf_node.keys.is_empty() {
1394 if verbose {
1395 println!("Empty leaf page {dirty_page_id:?}: {dirty_leaf_node:?}");
1396 }
1397 removal_info = Some(dirty_page_id);
1398 } else if verbose {
1399 println!("Leaf page not empty {dirty_page_id:?}: {dirty_leaf_node:?}");
1400 }
1401 } else if verbose {
1402 println!("Leaf value not empty {tsn:?}: {leaf_value:?}");
1403 }
1404 } else {
1405 return Err(DCBError::DatabaseCorrupted(
1406 "Expected FreeListLeaf node".to_string(),
1407 ));
1408 }
1409 } else {
1410 let tsn_root_id = leaf_value_root_id;
1412 let dirty_tsn_root_id = { self.get_dirty_page_id(tsn_root_id)? };
1413 let mut tsn_root_replaced: Option<PageID> = None;
1414 let dirty_tsn_root_page = self.get_mut_dirty(dirty_tsn_root_id)?;
1415 let mut tsn_leaf_became_empty = false;
1416 let mut tsn_child_leaf_became_empty = false;
1417 match &mut dirty_tsn_root_page.node {
1418 Node::FreeListTsnLeaf(tsn_leaf_node) => {
1419 if let Some(pos) = tsn_leaf_node
1420 .page_ids
1421 .iter()
1422 .position(|&id| id == used_page_id)
1423 {
1424 tsn_leaf_node.page_ids.remove(pos);
1425 } else {
1426 return Err(DCBError::DatabaseCorrupted(format!(
1427 "{used_page_id:?} not found in TSN-subtree for {tsn:?}"
1428 )));
1429 }
1430 if verbose {
1431 println!(
1432 "Removed {used_page_id:?} from TSN-subtree leaf {dirty_tsn_root_id:?} for {tsn:?}"
1433 );
1434 }
1435 if tsn_leaf_node.page_ids.is_empty() {
1436 tsn_leaf_became_empty = true;
1437 removed_page_ids.push(dirty_tsn_root_id);
1438 }
1439 }
1440 Node::FreeListTsnInternal(_) => {
1441 let mut path: Vec<(PageID, usize)> = Vec::new();
1451 let mut current_id = dirty_tsn_root_id;
1452 loop {
1453 let node_owned = { self.get_page_ref(mvcc, current_id)?.node.clone() };
1454 match node_owned {
1455 Node::FreeListTsnLeaf(_) => {
1456 break; }
1458 Node::FreeListTsnInternal(internal) => {
1459 let mut child_idx = 0usize;
1461 while child_idx < internal.keys.len()
1462 && used_page_id >= internal.keys[child_idx]
1463 {
1464 child_idx += 1;
1465 }
1466 let next_id = internal.child_ids[child_idx];
1467 path.push((current_id, child_idx));
1468 current_id = next_id;
1469 }
1470 other => {
1471 return Err(DCBError::DatabaseCorrupted(format!(
1472 "Unexpected node type in TSN-subtree during descent: {}",
1473 other.type_name()
1474 )));
1475 }
1476 }
1477 }
1478
1479 let mut dirty_child_id = { self.get_dirty_page_id(current_id)? };
1481 {
1482 let child_page = self.get_mut_dirty(dirty_child_id)?;
1483 match &mut child_page.node {
1484 Node::FreeListTsnLeaf(leaf_node) => {
1485 if let Some(pos) =
1486 leaf_node.page_ids.iter().position(|&id| id == used_page_id)
1487 {
1488 leaf_node.page_ids.remove(pos);
1489 } else {
1490 return Err(DCBError::DatabaseCorrupted(format!(
1491 "{used_page_id:?} not found in TSN-subtree for {tsn:?}"
1492 )));
1493 }
1494 if verbose {
1495 println!(
1496 "Removed {used_page_id:?} from TSN-subtree leaf {dirty_child_id:?} for {tsn:?}"
1497 );
1498 }
1499 if leaf_node.page_ids.is_empty() {
1500 tsn_child_leaf_became_empty = true;
1501 removed_page_ids.push(dirty_child_id);
1502 }
1503 }
1504 other => {
1505 return Err(DCBError::DatabaseCorrupted(format!(
1506 "Expected TSN-subtree leaf, got {}",
1507 other.type_name()
1508 )));
1509 }
1510 }
1511 }
1512
1513 let mut subtree_emptied = false;
1515 let mut new_root_id_opt: Option<PageID> = None;
1516
1517 let path_len = path.len();
1518 for (level, (parent_id, child_idx)) in path.into_iter().rev().enumerate() {
1519 let parent_dirty_id = { self.get_dirty_page_id(parent_id)? };
1521
1522 let parent_page = self.get_mut_dirty(parent_dirty_id)?;
1527 let Node::FreeListTsnInternal(ref mut parent_node) = parent_page.node
1528 else {
1529 return Err(DCBError::DatabaseCorrupted(
1530 "Expected TSN-subtree internal node".to_string(),
1531 ));
1532 };
1533
1534 if tsn_child_leaf_became_empty && level == 0 {
1535 parent_node.child_ids.remove(child_idx);
1537 if !parent_node.keys.is_empty() {
1538 let key_remove_idx = if child_idx == 0 { 0 } else { child_idx - 1 };
1539 if key_remove_idx < parent_node.keys.len() {
1540 parent_node.keys.remove(key_remove_idx);
1541 }
1542 }
1543
1544 match parent_node.child_ids.len() {
1546 0 => {
1547 subtree_emptied = true;
1549 removed_page_ids.push(parent_dirty_id);
1550 }
1551 1 => {
1552 let remaining_child = parent_node.child_ids[0];
1554 removed_page_ids.push(parent_dirty_id);
1555 dirty_child_id = remaining_child;
1557 new_root_id_opt = Some(remaining_child);
1558 }
1559 _ => {
1560 dirty_child_id = parent_dirty_id;
1562 if level == path_len - 1 {
1563 new_root_id_opt = Some(parent_dirty_id);
1565 }
1566 }
1567 }
1568 } else {
1569 if parent_node.child_ids[child_idx] != dirty_child_id {
1571 parent_node.child_ids[child_idx] = dirty_child_id;
1572 }
1573 dirty_child_id = parent_dirty_id;
1575 if level == path_len - 1 {
1576 new_root_id_opt = Some(parent_dirty_id);
1577 }
1578 }
1579 }
1580
1581 if subtree_emptied {
1584 tsn_leaf_became_empty = true;
1585 } else if let Some(new_root) = new_root_id_opt
1586 && new_root != dirty_tsn_root_id
1587 {
1588 tsn_root_replaced = Some(new_root);
1589 }
1590 }
1591 _ => {
1592 return Err(DCBError::DatabaseCorrupted(
1593 "Expected TSN-subtree node".to_string(),
1594 ));
1595 }
1596 }
1597
1598 let dirty_page_id = { self.get_dirty_page_id(current_page_id)? };
1600 if dirty_page_id != current_page_id {
1601 replacement_info = Some((current_page_id, dirty_page_id));
1602 }
1603 let dirty_leaf_page = self.get_mut_dirty(dirty_page_id)?;
1604 if let Node::FreeListLeaf(dirty_leaf_node) = &mut dirty_leaf_page.node {
1605 if dirty_leaf_node.keys.is_empty() || dirty_leaf_node.keys[0] != tsn {
1607 return Err(DCBError::DatabaseCorrupted(format!(
1608 "Expected TSN {} not found in dirty leaf: {:?}",
1609 tsn.0, dirty_leaf_node
1610 )));
1611 }
1612 if tsn_leaf_became_empty {
1613 dirty_leaf_node.keys.remove(0);
1615 dirty_leaf_node.values.remove(0);
1616 if verbose {
1617 println!("Removed {tsn:?} from {dirty_page_id:?}");
1618 }
1619 if dirty_leaf_node.keys.is_empty() {
1620 if verbose {
1621 println!("Empty leaf page {dirty_page_id:?}: {dirty_leaf_node:?}");
1622 }
1623 removal_info = Some(dirty_page_id);
1624 } else if verbose {
1625 println!("Leaf page not empty {dirty_page_id:?}: {dirty_leaf_node:?}");
1626 }
1627 } else if let Some(new_root) = tsn_root_replaced {
1628 dirty_leaf_node.values[0].root_id = new_root;
1630 } else if dirty_tsn_root_id != tsn_root_id {
1631 dirty_leaf_node.values[0].root_id = dirty_tsn_root_id;
1633 }
1634 } else {
1635 return Err(DCBError::DatabaseCorrupted(
1636 "Expected FreeListLeaf node".to_string(),
1637 ));
1638 }
1639 }
1640
1641 let mut current_replacement_info = replacement_info;
1643
1644 while let Some(parent_page_id) = stack.pop() {
1645 let dirty_page_id = { self.get_dirty_page_id(parent_page_id)? };
1647 let parent_replacement_info: Option<(PageID, PageID)> = {
1648 if dirty_page_id != parent_page_id {
1649 Some((parent_page_id, dirty_page_id))
1650 } else {
1651 None
1652 }
1653 };
1654 let dirty_internal_page = self.get_mut_dirty(dirty_page_id)?;
1656
1657 if let Some((old_id, new_id)) = current_replacement_info {
1658 if let Node::FreeListInternal(dirty_internal_node) = &mut dirty_internal_page.node {
1659 if dirty_internal_node.child_ids[0] == old_id {
1661 dirty_internal_node.child_ids[0] = new_id;
1662 if verbose {
1663 println!(
1664 "Replaced {old_id:?} with {new_id:?} in {dirty_page_id:?}: {dirty_internal_page:?}"
1665 );
1666 }
1667 } else {
1668 return Err(DCBError::DatabaseCorrupted("Child ID mismatch".to_string()));
1669 }
1670 } else {
1671 return Err(DCBError::DatabaseCorrupted(
1672 "Expected FreeListInternal node".to_string(),
1673 ));
1674 }
1675 }
1676 current_replacement_info = parent_replacement_info;
1677
1678 if let Some(removed_page_id) = removal_info {
1679 removed_page_ids.push(removed_page_id);
1680
1681 if let Node::FreeListInternal(dirty_internal_node) = &mut dirty_internal_page.node {
1682 if dirty_internal_node.child_ids[0] != removed_page_id {
1684 return Err(DCBError::DatabaseCorrupted("Child ID mismatch".to_string()));
1685 }
1686 if dirty_internal_node.keys.is_empty() {
1687 return Err(DCBError::DatabaseCorrupted(
1688 "Empty internal node keys".to_string(),
1689 ));
1690 }
1691 dirty_internal_node.child_ids.remove(0);
1692 dirty_internal_node.keys.remove(0);
1693 if verbose {
1694 println!(
1695 "Removed {removed_page_id:?} from {dirty_page_id:?}: {dirty_internal_node:?}"
1696 );
1697 }
1698
1699 if dirty_internal_node.keys.is_empty() {
1701 if verbose {
1702 println!(
1703 "Empty internal page {dirty_page_id:?}: {dirty_internal_node:?}"
1704 );
1705 }
1706 assert_eq!(dirty_internal_node.child_ids.len(), 1);
1707 let orphaned_child_id = dirty_internal_node.child_ids[0];
1708
1709 removed_page_ids.push(dirty_page_id);
1710
1711 if let Some((old_id, _)) = parent_replacement_info {
1712 current_replacement_info = Some((old_id, orphaned_child_id));
1713 } else {
1714 current_replacement_info = Some((dirty_page_id, orphaned_child_id));
1715 }
1716 }
1717 } else {
1718 return Err(DCBError::DatabaseCorrupted(
1719 "Expected FreeListInternal node".to_string(),
1720 ));
1721 }
1722
1723 removal_info = None;
1724 }
1725 }
1726
1727 for &removed_page_id in &removed_page_ids {
1728 self.append_freed_page_id(removed_page_id);
1729 }
1730
1731 if let Some((old_id, new_id)) = current_replacement_info {
1734 if self.free_lists_tree_root_id == old_id {
1735 self.append_freed_page_id(old_id);
1736 self.free_lists_tree_root_id = new_id;
1737 if verbose {
1738 println!("Replaced root {old_id:?} with {new_id:?}");
1739 }
1740 } else {
1741 return Err(DCBError::RootIDMismatch(old_id.0, new_id.0));
1742 }
1743 }
1744
1745 Ok(())
1746 }
1747}
1748
1749enum FreePageIDInsertStrategy {
1750 PushTsnOntoFreeListLeaf,
1751 PushPageIdOntoFreeListLeaf(usize),
1752 PushPageIdOntoExistingTsnSubtree,
1753 MoveTsnToNewTsnSubtree,
1754 SplitFreeListLeaf,
1755 CreateAndPromoteFreeListLeaf,
1756}
1757
1758pub struct Reader {
1760 pub header_page_id: PageID,
1761 pub tsn: Tsn,
1762 pub events_tree_root_id: PageID,
1763 pub tags_tree_root_id: PageID,
1764 pub next_position: Position,
1765 reader_id: usize,
1766 reader_tsns: Arc<DashMap<usize, Tsn>>,
1767}
1768
1769impl Drop for Reader {
1770 fn drop(&mut self) {
1771 self.reader_tsns.remove(&self.reader_id);
1773 }
1774}
1775
1776#[cfg(test)]
1777mod tests {
1778 use super::*;
1779 use crate::free_lists_tree_nodes::FreeListLeafValue;
1780 use serial_test::serial;
1781 use tempfile::tempdir;
1782
1783 static VERBOSE: bool = false;
1784
1785 #[test]
1786 #[serial]
1787 fn test_mvcc_init() {
1788 let temp_dir = tempdir().unwrap();
1789 let db_path = temp_dir.path().join("mvcc-test.db");
1790
1791 {
1792 let db = Mvcc::new(&db_path, 4096, VERBOSE).unwrap();
1793 assert!(db.pager.is_file_new);
1794 }
1795
1796 {
1797 let db = Mvcc::new(&db_path, 4096, VERBOSE).unwrap();
1798 assert!(!db.pager.is_file_new);
1799 }
1800 }
1801
1802 #[test]
1803 #[serial]
1804 fn test_write_transaction_incrementing_tsn_and_alternating_header() {
1805 let temp_dir = tempdir().unwrap();
1806 let db_path = temp_dir.path().join("mvcc-test.db");
1807 let db = Mvcc::new(&db_path, 4096, VERBOSE).unwrap();
1808
1809 {
1810 let mut writer = db.writer().unwrap();
1811 assert_eq!(Tsn(1), writer.tsn);
1812 assert_eq!(PageID(0), writer.header_page_id);
1813 db.commit(&mut writer).unwrap();
1814 }
1815
1816 {
1817 let mut writer = db.writer().unwrap();
1818 assert_eq!(Tsn(2), writer.tsn);
1819 assert_eq!(PageID(1), writer.header_page_id);
1820 db.commit(&mut writer).unwrap();
1821 }
1822
1823 {
1824 let mut writer = db.writer().unwrap();
1825 assert_eq!(Tsn(3), writer.tsn);
1826 assert_eq!(PageID(0), writer.header_page_id);
1827 db.commit(&mut writer).unwrap();
1828 }
1829
1830 {
1831 let mut writer = db.writer().unwrap();
1832 assert_eq!(Tsn(4), writer.tsn);
1833 assert_eq!(PageID(1), writer.header_page_id);
1834 db.commit(&mut writer).unwrap();
1835 }
1836
1837 {
1838 let mut writer = db.writer().unwrap();
1839 assert_eq!(Tsn(5), writer.tsn);
1840 assert_eq!(PageID(0), writer.header_page_id);
1841 db.commit(&mut writer).unwrap();
1842 }
1843 }
1844
1845 #[test]
1846 #[serial]
1847 fn test_read_transaction_header_and_tsn() {
1848 let temp_dir = tempdir().unwrap();
1849 let db_path = temp_dir.path().join("mvcc-test.db");
1850 let db = Mvcc::new(&db_path, 4096, VERBOSE).unwrap();
1851
1852 {
1854 assert_eq!(0, db.reader_tsns.len());
1855 let reader = db.reader().unwrap();
1856 assert_eq!(1, db.reader_tsns.len());
1857 assert_eq!(
1858 vec![Tsn(0)],
1859 db.reader_tsns
1860 .iter()
1861 .map(|r| *r.value())
1862 .collect::<Vec<_>>()
1863 );
1864 assert_eq!(PageID(0), reader.header_page_id);
1865 assert_eq!(Tsn(0), reader.tsn);
1866 }
1867 assert_eq!(0, db.reader_tsns.len());
1868
1869 {
1871 let reader1 = db.reader().unwrap();
1872 assert_eq!(
1873 vec![Tsn(0)],
1874 db.reader_tsns
1875 .iter()
1876 .map(|r| *r.value())
1877 .collect::<Vec<_>>()
1878 );
1879 assert_eq!(PageID(0), reader1.header_page_id);
1880 assert_eq!(Tsn(0), reader1.tsn);
1881
1882 {
1883 let reader2 = db.reader().unwrap();
1884 assert_eq!(
1885 vec![Tsn(0), Tsn(0)],
1886 db.reader_tsns
1887 .iter()
1888 .map(|r| *r.value())
1889 .collect::<Vec<_>>()
1890 );
1891 assert_eq!(PageID(0), reader2.header_page_id);
1892 assert_eq!(Tsn(0), reader2.tsn);
1893
1894 {
1895 let reader3 = db.reader().unwrap();
1896 assert_eq!(
1897 vec![Tsn(0), Tsn(0), Tsn(0)],
1898 db.reader_tsns
1899 .iter()
1900 .map(|r| *r.value())
1901 .collect::<Vec<_>>()
1902 );
1903 assert_eq!(PageID(0), reader3.header_page_id);
1904 assert_eq!(Tsn(0), reader3.tsn);
1905 }
1906 }
1907 }
1908 assert_eq!(0, db.reader_tsns.len());
1909
1910 {
1912 let mut writer = db.writer().unwrap();
1913 assert_eq!(0, db.reader_tsns.len());
1914 assert_eq!(Tsn(1), writer.tsn);
1915 assert_eq!(PageID(0), writer.header_page_id);
1916 db.commit(&mut writer).unwrap();
1917 }
1918
1919 {
1921 let reader = db.reader().unwrap();
1922 assert_eq!(
1923 vec![Tsn(1)],
1924 db.reader_tsns
1925 .iter()
1926 .map(|r| *r.value())
1927 .collect::<Vec<_>>()
1928 );
1929 assert_eq!(PageID(1), reader.header_page_id);
1930 assert_eq!(Tsn(1), reader.tsn);
1931 }
1932 }
1933
1934 #[test]
1935 #[serial]
1936 fn test_copy_on_write_page_reuse() {
1937 let temp_dir = tempdir().unwrap();
1938 let db_path = temp_dir.path().join("mvcc-test.db");
1939 let db = Mvcc::new(&db_path, 4096, VERBOSE).unwrap();
1940 {
1942 let mut writer = db.writer().unwrap();
1943
1944 assert_eq!(0, writer.reusable_page_ids.len());
1946
1947 assert_eq!(PageID(2), writer.free_lists_tree_root_id);
1949
1950 assert_eq!(PageID(3), writer.events_tree_root_id);
1952
1953 let free_page_id = writer.alloc_page_id();
1955 assert_eq!(PageID(5), free_page_id);
1956 writer
1957 .insert_freed_page_id(&db, writer.tsn, free_page_id)
1958 .unwrap();
1959
1960 assert_eq!(1, writer.dirty.len());
1962 assert_eq!(PageID(6), *writer.dirty.keys().collect::<Vec<_>>()[0]);
1963
1964 assert_eq!(1, writer.freed_page_ids.len());
1966 assert_eq!(PageID(2), writer.freed_page_ids[0]);
1967
1968 db.commit(&mut writer).unwrap();
1969 }
1970
1971 {
1973 let mut writer = db.writer().unwrap();
1974
1975 assert_eq!(2, writer.reusable_page_ids.len());
1977 assert_eq!((PageID(5), Tsn(1)), writer.reusable_page_ids[0]);
1978 assert_eq!((PageID(2), Tsn(1)), writer.reusable_page_ids[1]);
1979
1980 assert_eq!(PageID(6), writer.free_lists_tree_root_id);
1982
1983 assert_eq!(PageID(3), writer.events_tree_root_id);
1985
1986 let free_page_id = writer.alloc_page_id();
1988 assert_eq!(PageID(5), free_page_id);
1989 writer
1990 .insert_freed_page_id(&db, writer.tsn, free_page_id)
1991 .unwrap();
1992
1993 assert_eq!(1, writer.dirty.len());
1995 assert_eq!(PageID(2), *writer.dirty.keys().collect::<Vec<_>>()[0]);
1996
1997 assert_eq!(1, writer.freed_page_ids.len());
1999 assert_eq!(PageID(6), writer.freed_page_ids[0]);
2000
2001 db.commit(&mut writer).unwrap();
2002 }
2003
2004 {
2006 let mut writer = db.writer().unwrap();
2007
2008 assert_eq!(2, writer.reusable_page_ids.len());
2010 assert_eq!((PageID(5), Tsn(2)), writer.reusable_page_ids[0]);
2011 assert_eq!((PageID(6), Tsn(2)), writer.reusable_page_ids[1]);
2012
2013 assert_eq!(PageID(2), writer.free_lists_tree_root_id);
2015
2016 assert_eq!(PageID(3), writer.events_tree_root_id);
2018
2019 let free_page_id = writer.alloc_page_id();
2021 assert_eq!(PageID(5), free_page_id);
2022 writer
2023 .insert_freed_page_id(&db, writer.tsn, free_page_id)
2024 .unwrap();
2025
2026 assert_eq!(1, writer.dirty.len());
2028 assert_eq!(PageID(6), *writer.dirty.keys().collect::<Vec<_>>()[0]);
2029
2030 assert_eq!(1, writer.freed_page_ids.len());
2032 assert_eq!(PageID(2), writer.freed_page_ids[0]);
2033
2034 db.commit(&mut writer).unwrap();
2035 }
2036 }
2037
2038 mod free_list_tree_tests {
2040 use super::*;
2041 use serial_test::serial;
2042 use tempfile::tempdir;
2043
2044 fn construct_mvcc(page_size: usize) -> (tempfile::TempDir, Mvcc) {
2046 let temp_dir = tempdir().unwrap();
2047 let db_path = temp_dir.path().join("mvcc-test.db");
2048 let db = Mvcc::new(&db_path, page_size, VERBOSE).unwrap();
2049 (temp_dir, db)
2050 }
2051
2052 #[test]
2053 #[serial]
2054 fn test_find_reusable_page_ids_empty_no_entries() {
2055 let (_temp_dir, db) = construct_mvcc(64);
2056 let writer = db.writer().unwrap();
2058 assert_eq!(0, writer.reusable_page_ids.len());
2059 }
2060
2061 #[test]
2062 #[serial]
2063 fn test_find_reusable_page_ids_leaf() {
2064 let (_temp_dir, db) = construct_mvcc(64);
2065 let mut writer = db.writer().unwrap();
2066
2067 let (tsn, free_pid1, free_pid2) = build_free_list_tree_leaf(&mut writer);
2068
2069 writer.find_reusable_page_ids(&db).unwrap();
2071 assert_eq!(2, writer.reusable_page_ids.len());
2072 assert_eq!((free_pid1, tsn), writer.reusable_page_ids[0]);
2073 assert_eq!((free_pid2, tsn), writer.reusable_page_ids[1]);
2074 }
2075
2076 #[test]
2077 #[serial]
2078 fn test_find_reusable_page_ids_internal_leaf() {
2079 let (_temp_dir, db) = construct_mvcc(128);
2080 let mut writer = db.writer().unwrap();
2081
2082 let (tsn1, tsn2, pid1, pid2, pid3, pid4) =
2083 build_free_list_tree_internal_leaf(&mut writer);
2084
2085 writer.find_reusable_page_ids(&db).unwrap();
2087 assert_eq!(4, writer.reusable_page_ids.len());
2089 assert_eq!((pid1, tsn1), writer.reusable_page_ids[0]);
2090 assert_eq!((pid2, tsn1), writer.reusable_page_ids[1]);
2091 assert_eq!((pid3, tsn2), writer.reusable_page_ids[2]);
2092 assert_eq!((pid4, tsn2), writer.reusable_page_ids[3]);
2093 }
2094
2095 #[test]
2096 #[serial]
2097 fn test_find_reusable_page_ids_internal_internal_leaf() {
2098 let (_temp_dir, db) = construct_mvcc(128);
2099 let mut writer = db.writer().unwrap();
2100
2101 let (tsn1, tsn2, tsn3, tsn4, pid1, pid2, pid3, pid4, pid5, pid6, pid7, pid8) =
2102 build_free_list_tree_internal_internal_leaf(&mut writer);
2103
2104 writer.find_reusable_page_ids(&db).unwrap();
2106 assert_eq!(8, writer.reusable_page_ids.len());
2108 assert_eq!((pid1, tsn1), writer.reusable_page_ids[0]);
2109 assert_eq!((pid2, tsn1), writer.reusable_page_ids[1]);
2110 assert_eq!((pid3, tsn2), writer.reusable_page_ids[2]);
2111 assert_eq!((pid4, tsn2), writer.reusable_page_ids[3]);
2112 assert_eq!((pid5, tsn3), writer.reusable_page_ids[4]);
2113 assert_eq!((pid6, tsn3), writer.reusable_page_ids[5]);
2114 assert_eq!((pid7, tsn4), writer.reusable_page_ids[6]);
2115 assert_eq!((pid8, tsn4), writer.reusable_page_ids[7]);
2116 }
2117
2118 #[test]
2119 #[serial]
2120 fn test_find_reusable_page_ids_leaf_tsn_subtree_leaf() {
2121 let (_temp_dir, db) = construct_mvcc(64);
2122 let mut writer = db.writer().unwrap();
2123
2124 let (pid1, pid2, tsn) = build_free_list_tree_leaf_tsn_subtree_leaf(&mut writer);
2125
2126 writer.find_reusable_page_ids(&db).unwrap();
2128 assert_eq!(2, writer.reusable_page_ids.len());
2130 assert_eq!((pid1, tsn), writer.reusable_page_ids[0]);
2131 assert_eq!((pid2, tsn), writer.reusable_page_ids[1]);
2132 }
2133
2134 #[test]
2135 #[serial]
2136 fn test_find_reusable_page_ids_leaf_tsn_subtree_internal_leaf() {
2137 let (_temp_dir, db) = construct_mvcc(64);
2138 let mut writer = db.writer().unwrap();
2139
2140 let (pid1, pid2, pid3, pid4, tsn) =
2141 build_free_list_tree_leaf_tsn_subtree_internal_leaf(&mut writer);
2142
2143 writer.find_reusable_page_ids(&db).unwrap();
2145 assert_eq!(4, writer.reusable_page_ids.len());
2147 assert_eq!((pid1, tsn), writer.reusable_page_ids[0]);
2148 assert_eq!((pid2, tsn), writer.reusable_page_ids[1]);
2149 assert_eq!((pid3, tsn), writer.reusable_page_ids[2]);
2150 assert_eq!((pid4, tsn), writer.reusable_page_ids[3]);
2151 }
2152
2153 #[test]
2154 #[serial]
2155 fn test_find_reusable_page_ids_leaf_tsn_subtree_internal_internal_leaf() {
2156 let (_temp_dir, db) = construct_mvcc(64);
2157 let mut writer = db.writer().unwrap();
2158
2159 let (pid1, pid2, pid3, pid4, pid5, pid6, pid7, pid8, tsn) =
2160 build_free_list_tree_leaf_tsn_subtree_internal_internal_leaf(&mut writer);
2161
2162 writer.find_reusable_page_ids(&db).unwrap();
2164 assert_eq!(8, writer.reusable_page_ids.len());
2166 assert_eq!((pid1, tsn), writer.reusable_page_ids[0]);
2167 assert_eq!((pid2, tsn), writer.reusable_page_ids[1]);
2168 assert_eq!((pid3, tsn), writer.reusable_page_ids[2]);
2169 assert_eq!((pid4, tsn), writer.reusable_page_ids[3]);
2170 assert_eq!((pid5, tsn), writer.reusable_page_ids[4]);
2171 assert_eq!((pid6, tsn), writer.reusable_page_ids[5]);
2172 assert_eq!((pid7, tsn), writer.reusable_page_ids[6]);
2173 assert_eq!((pid8, tsn), writer.reusable_page_ids[7]);
2174 }
2175
2176 fn build_free_list_tree_leaf(writer: &mut Writer) -> (Tsn, PageID, PageID) {
2177 let tsn = Tsn(123);
2179 let free_pid1 = writer.alloc_page_id();
2180 let free_pid2 = writer.alloc_page_id();
2181 let leaf = FreeListLeafNode {
2182 keys: vec![tsn],
2183 values: vec![FreeListLeafValue {
2184 page_ids: vec![free_pid1, free_pid2],
2185 root_id: PageID(0),
2186 }],
2187 };
2188 let root_id = writer.alloc_page_id();
2189 let page = Page::new(root_id, Node::FreeListLeaf(leaf));
2190 writer.insert_dirty(page).unwrap();
2191 writer.append_freed_page_id(writer.free_lists_tree_root_id);
2192 writer.free_lists_tree_root_id = root_id;
2193 (tsn, free_pid1, free_pid2)
2194 }
2195
2196 fn build_free_list_tree_internal_leaf(
2197 writer: &mut Writer,
2198 ) -> (Tsn, Tsn, PageID, PageID, PageID, PageID) {
2199 let tsn1 = Tsn(10);
2201 let tsn2 = Tsn(20);
2202 let pid1 = writer.alloc_page_id();
2203 let pid2 = writer.alloc_page_id();
2204 let pid3 = writer.alloc_page_id();
2205 let pid4 = writer.alloc_page_id();
2206
2207 let leaf1_id = writer.alloc_page_id();
2208 let leaf2_id = writer.alloc_page_id();
2209 let leaf1 = FreeListLeafNode {
2210 keys: vec![tsn1],
2211 values: vec![FreeListLeafValue {
2212 page_ids: vec![pid1, pid2],
2213 root_id: PageID(0),
2214 }],
2215 };
2216 let leaf2 = FreeListLeafNode {
2217 keys: vec![tsn2],
2218 values: vec![FreeListLeafValue {
2219 page_ids: vec![pid3, pid4],
2220 root_id: PageID(0),
2221 }],
2222 };
2223 writer
2224 .insert_dirty(Page::new(leaf1_id, Node::FreeListLeaf(leaf1)))
2225 .unwrap();
2226 writer
2227 .insert_dirty(Page::new(leaf2_id, Node::FreeListLeaf(leaf2)))
2228 .unwrap();
2229
2230 let internal = FreeListInternalNode {
2232 keys: vec![tsn1],
2233 child_ids: vec![leaf1_id, leaf2_id],
2234 };
2235 let root_id = writer.alloc_page_id();
2236 writer
2237 .insert_dirty(Page::new(root_id, Node::FreeListInternal(internal)))
2238 .unwrap();
2239 writer.append_freed_page_id(writer.free_lists_tree_root_id);
2240 writer.free_lists_tree_root_id = root_id;
2241 (tsn1, tsn2, pid1, pid2, pid3, pid4)
2242 }
2243
2244 fn build_free_list_tree_internal_internal_leaf(
2245 writer: &mut Writer,
2246 ) -> (
2247 Tsn,
2248 Tsn,
2249 Tsn,
2250 Tsn,
2251 PageID,
2252 PageID,
2253 PageID,
2254 PageID,
2255 PageID,
2256 PageID,
2257 PageID,
2258 PageID,
2259 ) {
2260 let tsn1 = Tsn(10);
2262 let tsn2 = Tsn(20);
2263 let tsn3 = Tsn(30);
2264 let tsn4 = Tsn(40);
2265 let pid1 = writer.alloc_page_id();
2266 let pid2 = writer.alloc_page_id();
2267 let pid3 = writer.alloc_page_id();
2268 let pid4 = writer.alloc_page_id();
2269 let pid5 = writer.alloc_page_id();
2270 let pid6 = writer.alloc_page_id();
2271 let pid7 = writer.alloc_page_id();
2272 let pid8 = writer.alloc_page_id();
2273
2274 let leaf1_id = writer.alloc_page_id();
2275 let leaf2_id = writer.alloc_page_id();
2276 let leaf3_id = writer.alloc_page_id();
2277 let leaf4_id = writer.alloc_page_id();
2278 let leaf1 = FreeListLeafNode {
2279 keys: vec![tsn1],
2280 values: vec![FreeListLeafValue {
2281 page_ids: vec![pid1, pid2],
2282 root_id: PageID(0),
2283 }],
2284 };
2285 let leaf2 = FreeListLeafNode {
2286 keys: vec![tsn2],
2287 values: vec![FreeListLeafValue {
2288 page_ids: vec![pid3, pid4],
2289 root_id: PageID(0),
2290 }],
2291 };
2292 let leaf3 = FreeListLeafNode {
2293 keys: vec![tsn3],
2294 values: vec![FreeListLeafValue {
2295 page_ids: vec![pid5, pid6],
2296 root_id: PageID(0),
2297 }],
2298 };
2299 let leaf4 = FreeListLeafNode {
2300 keys: vec![tsn4],
2301 values: vec![FreeListLeafValue {
2302 page_ids: vec![pid7, pid8],
2303 root_id: PageID(0),
2304 }],
2305 };
2306 writer
2307 .insert_dirty(Page::new(leaf1_id, Node::FreeListLeaf(leaf1)))
2308 .unwrap();
2309 writer
2310 .insert_dirty(Page::new(leaf2_id, Node::FreeListLeaf(leaf2)))
2311 .unwrap();
2312 writer
2313 .insert_dirty(Page::new(leaf3_id, Node::FreeListLeaf(leaf3)))
2314 .unwrap();
2315 writer
2316 .insert_dirty(Page::new(leaf4_id, Node::FreeListLeaf(leaf4)))
2317 .unwrap();
2318
2319 let internal1 = FreeListInternalNode {
2321 keys: vec![tsn2],
2322 child_ids: vec![leaf1_id, leaf2_id],
2323 };
2324 let internal1_id = writer.alloc_page_id();
2325 let internal2 = FreeListInternalNode {
2326 keys: vec![tsn4],
2327 child_ids: vec![leaf3_id, leaf4_id],
2328 };
2329 let internal2_id = writer.alloc_page_id();
2330 let internal3 = FreeListInternalNode {
2331 keys: vec![tsn3],
2332 child_ids: vec![internal1_id, internal2_id],
2333 };
2334 let internal3_id = writer.alloc_page_id();
2335 writer
2336 .insert_dirty(Page::new(internal1_id, Node::FreeListInternal(internal1)))
2337 .unwrap();
2338 writer
2339 .insert_dirty(Page::new(internal2_id, Node::FreeListInternal(internal2)))
2340 .unwrap();
2341 writer
2342 .insert_dirty(Page::new(internal3_id, Node::FreeListInternal(internal3)))
2343 .unwrap();
2344 writer.append_freed_page_id(writer.free_lists_tree_root_id);
2345 writer.free_lists_tree_root_id = internal3_id;
2346 (
2347 tsn1, tsn2, tsn3, tsn4, pid1, pid2, pid3, pid4, pid5, pid6, pid7, pid8,
2348 )
2349 }
2350
2351 fn build_free_list_tree_leaf_tsn_subtree_leaf(
2352 writer: &mut Writer,
2353 ) -> (PageID, PageID, Tsn) {
2354 let tsn_sub_leaf_id = writer.alloc_page_id();
2356 let pid1 = writer.alloc_page_id();
2357 let pid2 = writer.alloc_page_id();
2358 let tsn_sub_leaf = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2359 page_ids: vec![pid1, pid2],
2360 };
2361 writer
2362 .insert_dirty(Page::new(
2363 tsn_sub_leaf_id,
2364 Node::FreeListTsnLeaf(tsn_sub_leaf),
2365 ))
2366 .unwrap();
2367
2368 let tsn = Tsn(33);
2369 let leaf = FreeListLeafNode {
2370 keys: vec![tsn],
2371 values: vec![FreeListLeafValue {
2372 page_ids: vec![],
2373 root_id: tsn_sub_leaf_id,
2374 }],
2375 };
2376 let root_id = writer.alloc_page_id();
2377 writer
2378 .insert_dirty(Page::new(root_id, Node::FreeListLeaf(leaf)))
2379 .unwrap();
2380 writer.append_freed_page_id(writer.free_lists_tree_root_id);
2381 writer.free_lists_tree_root_id = root_id;
2382 (pid1, pid2, tsn)
2383 }
2384
2385 fn build_free_list_tree_leaf_tsn_subtree_internal_leaf(
2386 writer: &mut Writer,
2387 ) -> (PageID, PageID, PageID, PageID, Tsn) {
2388 let tsn_sub_leaf_id1 = writer.alloc_page_id();
2390 let pid1 = writer.alloc_page_id();
2391 let pid2 = writer.alloc_page_id();
2392 let tsn_sub_leaf1 = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2393 page_ids: vec![pid1, pid2],
2394 };
2395 writer
2396 .insert_dirty(Page::new(
2397 tsn_sub_leaf_id1,
2398 Node::FreeListTsnLeaf(tsn_sub_leaf1),
2399 ))
2400 .unwrap();
2401
2402 let tsn_sub_leaf_id2 = writer.alloc_page_id();
2404 let pid3 = writer.alloc_page_id();
2405 let pid4 = writer.alloc_page_id();
2406 let tsn_sub_leaf2 = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2407 page_ids: vec![pid3, pid4],
2408 };
2409 writer
2410 .insert_dirty(Page::new(
2411 tsn_sub_leaf_id2,
2412 Node::FreeListTsnLeaf(tsn_sub_leaf2),
2413 ))
2414 .unwrap();
2415
2416 let tsn_sub_internal_id = writer.alloc_page_id();
2418 let tsn_sub_internal = crate::free_lists_tree_nodes::FreeListTsnInternalNode {
2419 keys: vec![pid3],
2420 child_ids: vec![tsn_sub_leaf_id1, tsn_sub_leaf_id2],
2421 };
2422 writer
2423 .insert_dirty(Page::new(
2424 tsn_sub_internal_id,
2425 Node::FreeListTsnInternal(tsn_sub_internal),
2426 ))
2427 .unwrap();
2428
2429 let tsn = Tsn(33);
2431 let leaf = FreeListLeafNode {
2432 keys: vec![tsn],
2433 values: vec![FreeListLeafValue {
2434 page_ids: vec![],
2435 root_id: tsn_sub_internal_id,
2436 }],
2437 };
2438 let root_id = writer.alloc_page_id();
2439 writer
2440 .insert_dirty(Page::new(root_id, Node::FreeListLeaf(leaf)))
2441 .unwrap();
2442 writer.append_freed_page_id(writer.free_lists_tree_root_id);
2443 writer.free_lists_tree_root_id = root_id;
2444 (pid1, pid2, pid3, pid4, tsn)
2445 }
2446
2447 fn build_free_list_tree_leaf_tsn_subtree_internal_internal_leaf(
2448 writer: &mut Writer,
2449 ) -> (
2450 PageID,
2451 PageID,
2452 PageID,
2453 PageID,
2454 PageID,
2455 PageID,
2456 PageID,
2457 PageID,
2458 Tsn,
2459 ) {
2460 let tsn_sub_leaf_id1 = writer.alloc_page_id();
2462 let pid1 = writer.alloc_page_id();
2463 let pid2 = writer.alloc_page_id();
2464 let tsn_sub_leaf1 = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2465 page_ids: vec![pid1, pid2],
2466 };
2467 writer
2468 .insert_dirty(Page::new(
2469 tsn_sub_leaf_id1,
2470 Node::FreeListTsnLeaf(tsn_sub_leaf1),
2471 ))
2472 .unwrap();
2473
2474 let tsn_sub_leaf_id2 = writer.alloc_page_id();
2476 let pid3 = writer.alloc_page_id();
2477 let pid4 = writer.alloc_page_id();
2478 let tsn_sub_leaf2 = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2479 page_ids: vec![pid3, pid4],
2480 };
2481 writer
2482 .insert_dirty(Page::new(
2483 tsn_sub_leaf_id2,
2484 Node::FreeListTsnLeaf(tsn_sub_leaf2),
2485 ))
2486 .unwrap();
2487
2488 let tsn_sub_internal_id1 = writer.alloc_page_id();
2490 let tsn_sub_internal1 = crate::free_lists_tree_nodes::FreeListTsnInternalNode {
2491 keys: vec![pid3],
2492 child_ids: vec![tsn_sub_leaf_id1, tsn_sub_leaf_id2],
2493 };
2494 writer
2495 .insert_dirty(Page::new(
2496 tsn_sub_internal_id1,
2497 Node::FreeListTsnInternal(tsn_sub_internal1),
2498 ))
2499 .unwrap();
2500
2501 let tsn_sub_leaf_id3 = writer.alloc_page_id();
2503 let pid5 = writer.alloc_page_id();
2504 let pid6 = writer.alloc_page_id();
2505 let tsn_sub_leaf3 = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2506 page_ids: vec![pid5, pid6],
2507 };
2508 writer
2509 .insert_dirty(Page::new(
2510 tsn_sub_leaf_id3,
2511 Node::FreeListTsnLeaf(tsn_sub_leaf3),
2512 ))
2513 .unwrap();
2514
2515 let tsn_sub_leaf_id4 = writer.alloc_page_id();
2517 let pid7 = writer.alloc_page_id();
2518 let pid8 = writer.alloc_page_id();
2519 let tsn_sub_leaf4 = crate::free_lists_tree_nodes::FreeListTsnLeafNode {
2520 page_ids: vec![pid7, pid8],
2521 };
2522 writer
2523 .insert_dirty(Page::new(
2524 tsn_sub_leaf_id4,
2525 Node::FreeListTsnLeaf(tsn_sub_leaf4),
2526 ))
2527 .unwrap();
2528
2529 let tsn_sub_internal_id2 = writer.alloc_page_id();
2531 let tsn_sub_internal2 = crate::free_lists_tree_nodes::FreeListTsnInternalNode {
2532 keys: vec![pid7],
2533 child_ids: vec![tsn_sub_leaf_id3, tsn_sub_leaf_id4],
2534 };
2535 writer
2536 .insert_dirty(Page::new(
2537 tsn_sub_internal_id2,
2538 Node::FreeListTsnInternal(tsn_sub_internal2),
2539 ))
2540 .unwrap();
2541
2542 let tsn_sub_internal_id3 = writer.alloc_page_id();
2544 let tsn_sub_internal3 = crate::free_lists_tree_nodes::FreeListTsnInternalNode {
2545 keys: vec![pid5],
2546 child_ids: vec![tsn_sub_internal_id1, tsn_sub_internal_id2],
2547 };
2548 writer
2549 .insert_dirty(Page::new(
2550 tsn_sub_internal_id3,
2551 Node::FreeListTsnInternal(tsn_sub_internal3),
2552 ))
2553 .unwrap();
2554
2555 let tsn = writer.tsn;
2557 let leaf = FreeListLeafNode {
2558 keys: vec![tsn],
2559 values: vec![FreeListLeafValue {
2560 page_ids: vec![],
2561 root_id: tsn_sub_internal_id3,
2562 }],
2563 };
2564 let root_id = writer.alloc_page_id();
2565 writer
2566 .insert_dirty(Page::new(root_id, Node::FreeListLeaf(leaf)))
2567 .unwrap();
2568 writer.append_freed_page_id(writer.free_lists_tree_root_id);
2569 writer.free_lists_tree_root_id = root_id;
2570 (pid1, pid2, pid3, pid4, pid5, pid6, pid7, pid8, tsn)
2571 }
2572
2573 #[test]
2574 #[serial]
2575 fn test_insert_freed_page_id_to_empty_leaf_root() {
2576 let (_temp_dir, mut db) = construct_mvcc(64);
2577
2578 let (header_page_id, header_node) = db.get_latest_header().unwrap();
2580 assert_eq!(PageID(0), header_page_id);
2581
2582 assert_eq!(PageID(5), header_node.next_page_id);
2584
2585 let tsn = Tsn(1001);
2587
2588 let mut writer = Writer::new(
2589 header_page_id,
2590 tsn,
2591 header_node.next_page_id,
2592 header_node.free_lists_tree_root_id,
2593 header_node.events_tree_root_id,
2594 header_node.tags_tree_root_id,
2595 header_node.next_position,
2596 VERBOSE,
2597 );
2598
2599 let initial_root_id = writer.free_lists_tree_root_id;
2601 assert_eq!(PageID(2), initial_root_id);
2602
2603 let page_id = writer.alloc_page_id();
2605
2606 assert_eq!(header_node.next_page_id, page_id);
2608
2609 let current_tsn = writer.tsn;
2611 writer
2612 .insert_freed_page_id(&mut db, current_tsn, page_id)
2613 .unwrap();
2614
2615 let expected_new_root_id = PageID(header_node.next_page_id.0 + 1);
2617 assert_eq!(expected_new_root_id, writer.free_lists_tree_root_id);
2618 assert_eq!(1, writer.dirty.len());
2619 assert!(writer.dirty.contains_key(&expected_new_root_id));
2620
2621 let new_root_page = writer.dirty.get(&expected_new_root_id).unwrap();
2622 assert_eq!(expected_new_root_id, new_root_page.page_id);
2623
2624 let freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
2625 assert_eq!(vec![initial_root_id], freed_page_ids);
2626
2627 match &new_root_page.node {
2629 Node::FreeListLeaf(node) => {
2630 let expected_keys = vec![tsn];
2631 assert_eq!(expected_keys, node.keys);
2632
2633 let expected_values = vec![FreeListLeafValue {
2634 page_ids: vec![header_node.next_page_id],
2635 root_id: PageID(0),
2636 }];
2637 assert_eq!(expected_values, node.values);
2638 }
2639 _ => panic!("Expected FreeListLeaf node"),
2640 }
2641 }
2642
2643 #[test]
2644 #[serial]
2645 fn test_remove_freed_page_id_from_root_leaf_root() {
2646 let (_temp_dir, mut db) = construct_mvcc(64);
2647
2648 let mut writer;
2650 let inserted_tsn;
2651 let inserted_page_id;
2652 let previous_root_id;
2653
2654 {
2655 writer = db.writer().unwrap();
2657
2658 previous_root_id = writer.free_lists_tree_root_id;
2660
2661 inserted_page_id = writer.alloc_page_id();
2663
2664 inserted_tsn = writer.tsn;
2666 writer
2667 .insert_freed_page_id(&mut db, inserted_tsn, inserted_page_id)
2668 .unwrap();
2669
2670 db.commit(&mut writer).unwrap();
2672 }
2673
2674 {
2676 db.reader_tsns.insert(0, Tsn(0));
2677 }
2678
2679 {
2681 writer = db.writer().unwrap();
2682
2683 assert_eq!(0, writer.reusable_page_ids.len());
2685
2686 let initial_root_id = writer.free_lists_tree_root_id;
2688 let next_page_id = writer.next_page_id;
2689
2690 writer
2692 .remove_free_page_id(&db, inserted_tsn, inserted_page_id)
2693 .unwrap();
2694
2695 let expected_new_root_id = next_page_id;
2697 assert_eq!(expected_new_root_id, writer.free_lists_tree_root_id);
2698 assert_eq!(1, writer.dirty.len());
2699 assert!(writer.dirty.contains_key(&expected_new_root_id));
2700
2701 let new_root_page = writer.dirty.get(&expected_new_root_id).unwrap();
2702 assert_eq!(expected_new_root_id, new_root_page.page_id);
2703
2704 let freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
2705 assert_eq!(vec![initial_root_id], freed_page_ids);
2706
2707 match &new_root_page.node {
2709 Node::FreeListLeaf(node) => {
2710 let expected_keys = vec![inserted_tsn];
2711 assert_eq!(expected_keys, node.keys);
2712
2713 let expected_values = vec![FreeListLeafValue {
2714 page_ids: vec![previous_root_id],
2715 root_id: PageID(0),
2716 }];
2717 assert_eq!(expected_values, node.values);
2718 }
2719 _ => panic!("Expected FreeListLeaf node"),
2720 }
2721 }
2722 }
2723
2724 #[test]
2725 #[serial]
2726 fn test_insert_freed_page_ids_until_split_leaf() {
2727 let (_temp_dir, mut db) = construct_mvcc(64);
2728
2729 let (header_page_id, header_node) = db.get_latest_header().unwrap();
2731
2732 let mut tsn = Tsn(100);
2734 let mut writer = Writer::new(
2735 header_page_id,
2736 Tsn(header_node.tsn.0 + 1),
2737 header_node.next_page_id,
2738 header_node.free_lists_tree_root_id,
2739 header_node.events_tree_root_id,
2740 header_node.tags_tree_root_id,
2741 header_node.next_position,
2742 VERBOSE,
2743 );
2744
2745 let mut has_split_leaf = false;
2746 let mut inserted: Vec<(Tsn, PageID)> = Vec::new();
2747
2748 while !has_split_leaf {
2750 let page_id1 = writer.alloc_page_id();
2752 writer.insert_freed_page_id(&mut db, tsn, page_id1).unwrap();
2753 inserted.push((tsn, page_id1));
2754
2755 let page_id2 = writer.alloc_page_id();
2757 writer.insert_freed_page_id(&mut db, tsn, page_id2).unwrap();
2758 inserted.push((tsn, page_id2));
2759
2760 tsn = Tsn(tsn.0 + 1);
2762
2763 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
2765 match &root_page.node {
2766 Node::FreeListInternal(_) => {
2767 has_split_leaf = true;
2768 }
2769 _ => {}
2770 }
2771 }
2772
2773 let mut copy_inserted = inserted.clone();
2775
2776 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
2778 let root_node = match &root_page.node {
2779 Node::FreeListInternal(node) => node,
2780 _ => panic!("Expected FreeListInternal node"),
2781 };
2782
2783 let mut active_page_ids = vec![
2785 HEADER_PAGE_ID_0,
2786 HEADER_PAGE_ID_1,
2787 writer.free_lists_tree_root_id,
2788 writer.events_tree_root_id,
2789 writer.tags_tree_root_id,
2790 ];
2791
2792 let mut freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
2794
2795 for (i, &child_id) in root_node.child_ids.iter().enumerate() {
2797 active_page_ids.push(child_id);
2798
2799 let child_page = writer.dirty.get(&child_id).unwrap();
2800 assert_eq!(child_id, child_page.page_id);
2801
2802 let child_node = match &child_page.node {
2803 Node::FreeListLeaf(node) => node,
2804 _ => panic!("Expected FreeListLeaf node"),
2805 };
2806
2807 if i > 0 {
2809 assert_eq!(root_node.keys[i - 1], child_node.keys[0]);
2810 }
2811
2812 for (k, &key) in child_node.keys.iter().enumerate() {
2814 for &value in &child_node.values[k].page_ids {
2815 let (inserted_tsn, inserted_page_id) = copy_inserted.remove(0);
2816 assert_eq!(inserted_tsn, key);
2817 assert_eq!(inserted_page_id, value);
2818 freed_page_ids.push(value);
2819 }
2820 }
2821 }
2822
2823 assert_eq!(7, active_page_ids.len());
2825
2826 let mut all_page_ids = active_page_ids.clone();
2828 all_page_ids.extend(freed_page_ids.clone());
2829 all_page_ids.sort();
2830 all_page_ids.dedup();
2831
2832 assert_eq!(
2833 all_page_ids.len(),
2834 active_page_ids.len() + freed_page_ids.len()
2835 - active_page_ids
2836 .iter()
2837 .filter(|id| freed_page_ids.contains(id))
2838 .count()
2839 );
2840
2841 let expected_page_ids: Vec<PageID> = (0..writer.next_page_id.0).map(PageID).collect();
2843 assert_eq!(expected_page_ids, all_page_ids);
2844 }
2845
2846 #[test]
2847 #[serial]
2848 fn test_insert_freed_page_ids_until_replace_internal_node_child_id() {
2849 let (_temp_dir, db) = construct_mvcc(128);
2850
2851 {
2853 db.reader_tsns.insert(0, Tsn(0));
2854 }
2855
2856 let mut has_split_leaf = false;
2857 let mut inserted: Vec<(Tsn, PageID)> = Vec::new();
2858
2859 while !has_split_leaf {
2861 let mut writer = db.writer().unwrap();
2863 let page_id1 = writer.alloc_page_id();
2865 writer
2866 .insert_freed_page_id(&db, writer.tsn, page_id1)
2867 .unwrap();
2868 inserted.push((writer.tsn, page_id1));
2869
2870 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
2872 match &root_page.node {
2873 Node::FreeListInternal(_) => {
2874 has_split_leaf = true;
2875 }
2876 _ => {}
2877 }
2878
2879 if !has_split_leaf {
2880 let page_id2 = writer.alloc_page_id();
2882 writer
2883 .insert_freed_page_id(&db, writer.tsn, page_id2)
2884 .unwrap();
2885 inserted.push((writer.tsn, page_id2));
2886
2887 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
2889 match &root_page.node {
2890 Node::FreeListInternal(_) => {
2891 has_split_leaf = true;
2892 }
2893 _ => {}
2894 }
2895 }
2896
2897 db.commit(&mut writer).unwrap();
2898 }
2899
2900 let mut writer = db.writer().unwrap();
2901 let page_id3 = writer.alloc_page_id();
2902 writer
2903 .insert_freed_page_id(&db, writer.tsn, page_id3)
2904 .unwrap();
2905 db.commit(&mut writer).unwrap();
2906 inserted.push((writer.tsn, page_id3));
2907
2908 writer = db.writer().unwrap();
2909 let page_id4 = writer.alloc_page_id();
2910 writer
2911 .insert_freed_page_id(&db, writer.tsn, page_id4)
2912 .unwrap();
2913 db.commit(&mut writer).unwrap();
2914 inserted.push((writer.tsn, page_id4));
2915
2916 writer = db.writer().unwrap();
2918 let root_page = db.read_page(writer.free_lists_tree_root_id).unwrap();
2919 let root_node = match &root_page.node {
2920 Node::FreeListInternal(node) => node,
2921 _ => panic!("Expected FreeListInternal node"),
2922 };
2923
2924 let mut active_page_ids = vec![
2926 HEADER_PAGE_ID_0,
2927 HEADER_PAGE_ID_1,
2928 writer.free_lists_tree_root_id,
2929 writer.events_tree_root_id,
2930 writer.tags_tree_root_id,
2931 ];
2932
2933 let mut freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
2935
2936 for (i, &child_id) in root_node.child_ids.iter().enumerate() {
2938 active_page_ids.push(child_id);
2939
2940 let child_page = db.read_page(child_id).unwrap();
2942 assert_eq!(child_id, child_page.page_id);
2943
2944 let child_node = match &child_page.node {
2945 Node::FreeListLeaf(node) => node,
2946 _ => panic!("Expected FreeListLeaf node"),
2947 };
2948
2949 if i > 0 {
2951 assert_eq!(root_node.keys[i - 1], child_node.keys[0]);
2952 }
2953
2954 for child_value in child_node.values.clone() {
2956 for page_id in child_value.page_ids {
2957 freed_page_ids.push(page_id);
2958 }
2959 }
2960 }
2961
2962 assert_eq!(8, active_page_ids.len());
2964
2965 let mut all_page_ids = active_page_ids.clone();
2967 all_page_ids.extend(freed_page_ids.clone());
2968 all_page_ids.sort();
2969 all_page_ids.dedup();
2970
2971 assert_eq!(
2972 all_page_ids.len(),
2973 active_page_ids.len() + freed_page_ids.len()
2974 - active_page_ids
2975 .iter()
2976 .filter(|id| freed_page_ids.contains(id))
2977 .count()
2978 );
2979
2980 let expected_page_ids: Vec<PageID> = (0..writer.next_page_id.0).map(PageID).collect();
2982 assert_eq!(expected_page_ids, all_page_ids);
2983 }
2984
2985 #[test]
2986 #[serial]
2987 fn test_remove_freed_page_ids_from_split_leaf() {
2988 let (_temp_dir, mut db) = construct_mvcc(128);
2989
2990 if VERBOSE {
2992 println!("Inserting page IDs......");
2993 }
2994 let mut inserted: Vec<(Tsn, PageID)> = Vec::new();
2995 let previous_root_id;
2996 let previous_writer_tsn;
2997
2998 {
2999 let mut writer = db.writer().unwrap();
3001
3002 previous_root_id = writer.free_lists_tree_root_id;
3004
3005 let mut has_split_leaf = false;
3007 let mut tsn = writer.tsn;
3008
3009 while !has_split_leaf {
3010 tsn = Tsn(tsn.0 + 1);
3012
3013 let page_id1 = writer.alloc_page_id();
3015 writer.insert_freed_page_id(&mut db, tsn, page_id1).unwrap();
3016 inserted.push((tsn, page_id1));
3017
3018 let page_id2 = writer.alloc_page_id();
3020 writer.insert_freed_page_id(&mut db, tsn, page_id2).unwrap();
3021 inserted.push((tsn, page_id2));
3022
3023 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3025 match &root_page.node {
3026 Node::FreeListInternal(_) => {
3027 has_split_leaf = true;
3028 }
3029 _ => {}
3030 }
3031 }
3032
3033 writer.tsn = Tsn(tsn.0 + 1);
3035 previous_writer_tsn = writer.tsn;
3036
3037 db.commit(&mut writer).unwrap();
3039 }
3040
3041 if VERBOSE {
3043 println!();
3044 println!("Removing all inserted page IDs......");
3045 }
3046
3047 {
3048 let (header_page_id, header_node) = db.get_latest_header().unwrap();
3050
3051 let mut writer = Writer::new(
3053 header_page_id,
3054 Tsn(header_node.tsn.0 + 1),
3055 header_node.next_page_id,
3056 header_node.free_lists_tree_root_id,
3057 header_node.events_tree_root_id,
3058 header_node.tags_tree_root_id,
3059 header_node.next_position,
3060 VERBOSE,
3061 );
3062
3063 let old_root_id = writer.free_lists_tree_root_id;
3065
3066 for (tsn, page_id) in inserted.iter() {
3068 writer.remove_free_page_id(&db, *tsn, *page_id).unwrap();
3069 if VERBOSE {
3070 println!("Dirty pages: {:?}", writer.dirty.keys());
3071 }
3072 }
3073
3074 assert_ne!(old_root_id, writer.free_lists_tree_root_id);
3076
3077 assert_eq!(1, writer.dirty.len());
3078 assert!(writer.dirty.contains_key(&writer.free_lists_tree_root_id));
3079
3080 let new_root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3081 assert_eq!(writer.free_lists_tree_root_id, new_root_page.page_id);
3082
3083 let freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
3085 assert!(freed_page_ids.contains(&old_root_id));
3086
3087 assert_eq!(5, writer.freed_page_ids.len());
3090
3091 match &new_root_page.node {
3093 Node::FreeListLeaf(node) => {
3094 let expected_keys = vec![previous_writer_tsn];
3095 assert_eq!(expected_keys, node.keys);
3096
3097 let expected_values = vec![FreeListLeafValue {
3098 page_ids: vec![previous_root_id],
3099 root_id: PageID(0),
3100 }];
3101 assert_eq!(expected_values, node.values);
3102 }
3103 _ => panic!("Expected FreeListLeaf node"),
3104 }
3105
3106 let active_page_ids = vec![
3108 HEADER_PAGE_ID_0,
3109 HEADER_PAGE_ID_1,
3110 writer.free_lists_tree_root_id,
3111 writer.events_tree_root_id,
3112 writer.tags_tree_root_id,
3113 ];
3114
3115 let mut all_freed_page_ids = freed_page_ids.clone();
3117
3118 match &new_root_page.node {
3120 Node::FreeListLeaf(node) => {
3121 for (_, value) in node.keys.iter().zip(node.values.iter()) {
3122 all_freed_page_ids.extend(value.page_ids.clone());
3123 }
3124 }
3125 _ => panic!("Expected FreeListLeaf node"),
3126 }
3127
3128 let inserted_page_ids: Vec<PageID> = inserted.iter().map(|(_, id)| *id).collect();
3130
3131 let mut all_page_ids = active_page_ids.clone();
3133 all_page_ids.extend(all_freed_page_ids.clone());
3134 all_page_ids.extend(inserted_page_ids.clone());
3135 all_page_ids.sort();
3136 all_page_ids.dedup();
3137
3138 let expected_page_ids: Vec<PageID> =
3140 (0..writer.next_page_id.0).map(PageID).collect();
3141 assert_eq!(expected_page_ids, all_page_ids);
3142 }
3143 }
3144
3145 #[test]
3146 #[serial]
3147 fn test_insert_freed_page_ids_until_split_internal() {
3148 let (_temp_dir, mut db) = construct_mvcc(64);
3149
3150 let (header_page_id, header_node) = db.get_latest_header().unwrap();
3152
3153 let mut writer = Writer::new(
3155 header_page_id,
3156 Tsn(header_node.tsn.0 + 1),
3157 header_node.next_page_id,
3158 header_node.free_lists_tree_root_id,
3159 header_node.events_tree_root_id,
3160 header_node.tags_tree_root_id,
3161 header_node.next_position,
3162 VERBOSE,
3163 );
3164
3165 let mut tsn = Tsn(100);
3167 let mut inserted: Vec<(Tsn, PageID)> = Vec::new();
3168 let mut has_split_internal = false;
3169
3170 while !has_split_internal {
3172 let page_id1 = writer.alloc_page_id();
3174 writer.insert_freed_page_id(&mut db, tsn, page_id1).unwrap();
3175 inserted.push((tsn, page_id1));
3176
3177 let page_id2 = writer.alloc_page_id();
3179 writer.insert_freed_page_id(&mut db, tsn, page_id2).unwrap();
3180 inserted.push((tsn, page_id2));
3181
3182 tsn = Tsn(tsn.0 + 1);
3184
3185 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3187 match &root_page.node {
3188 Node::FreeListInternal(root_node) => {
3189 if !root_node.child_ids.is_empty() {
3191 let child_id = root_node.child_ids[0];
3192 if let Some(child_page) = writer.dirty.get(&child_id) {
3193 match &child_page.node {
3194 Node::FreeListInternal(_) => {
3195 has_split_internal = true;
3196 }
3197 _ => {}
3198 }
3199 }
3200 }
3201 }
3202 _ => {}
3203 }
3204 if inserted.len() > 100 {
3205 panic!("Too many inserted page IDs");
3206 }
3207 }
3208
3209 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3211 let root_node = match &root_page.node {
3212 Node::FreeListInternal(node) => node,
3213 _ => panic!("Expected FreeListInternal node"),
3214 };
3215
3216 let mut active_page_ids = vec![
3218 HEADER_PAGE_ID_0,
3219 HEADER_PAGE_ID_1,
3220 writer.free_lists_tree_root_id,
3221 writer.events_tree_root_id,
3222 writer.tags_tree_root_id,
3223 ];
3224
3225 let mut freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
3227
3228 let mut previous_child: Option<&FreeListInternalNode> = None;
3230
3231 for (i, &child_id) in root_node.child_ids.iter().enumerate() {
3233 active_page_ids.push(child_id);
3234
3235 let child_page = writer.dirty.get(&child_id).unwrap();
3236 assert_eq!(child_id, child_page.page_id);
3237
3238 let child_node = match &child_page.node {
3239 Node::FreeListInternal(node) => node,
3240 _ => panic!("Expected FreeListInternal node"),
3241 };
3242
3243 if i > 0 {
3245 assert!(root_node.keys[i - 1] < child_node.keys[0]);
3246
3247 if let Some(prev_child) = previous_child {
3249 assert!(root_node.keys[i - 1] > *prev_child.keys.last().unwrap());
3250 }
3251 }
3252
3253 previous_child = Some(child_node);
3254
3255 for (j, &grand_child_id) in child_node.child_ids.iter().enumerate() {
3257 active_page_ids.push(grand_child_id);
3258
3259 let grand_child_page = writer.dirty.get(&grand_child_id).unwrap();
3260 assert_eq!(grand_child_id, grand_child_page.page_id);
3261
3262 let grand_child_node = match &grand_child_page.node {
3263 Node::FreeListLeaf(node) => node,
3264 _ => panic!("Expected FreeListLeaf node"),
3265 };
3266
3267 if j > 0 {
3269 assert_eq!(child_node.keys[j - 1], grand_child_node.keys[0]);
3270 }
3271
3272 for (k, &key) in grand_child_node.keys.iter().enumerate() {
3274 for &value in &grand_child_node.values[k].page_ids {
3275 let pos = inserted.iter().position(|&(t, p)| t == key && p == value);
3277 if let Some(idx) = pos {
3278 inserted.remove(idx);
3279 }
3280 freed_page_ids.push(value);
3281 }
3282 }
3283 }
3284 }
3285
3286 assert!(inserted.is_empty());
3288
3289 assert_eq!(11, active_page_ids.len());
3291
3292 let mut all_page_ids = active_page_ids.clone();
3294 all_page_ids.extend(freed_page_ids.clone());
3295 all_page_ids.sort();
3296 all_page_ids.dedup();
3297
3298 let expected_page_ids: Vec<PageID> = (0..writer.next_page_id.0).map(PageID).collect();
3300 assert_eq!(expected_page_ids, all_page_ids);
3301 }
3302
3303 #[test]
3304 #[serial]
3305 fn test_remove_freed_page_ids_from_split_internal() {
3306 let (_temp_dir, mut db) = construct_mvcc(64);
3307
3308 let mut inserted: Vec<(Tsn, PageID)> = Vec::new();
3310 let previous_root_id;
3311 let previous_writer_tsn;
3312
3313 {
3314 let mut writer = db.writer().unwrap();
3316
3317 previous_root_id = writer.free_lists_tree_root_id;
3319
3320 let mut has_split_internal = false;
3322 let mut tsn = writer.tsn;
3323
3324 while !has_split_internal {
3325 tsn = Tsn(tsn.0 + 1);
3327 writer.tsn = tsn;
3328
3329 let page_id1 = writer.alloc_page_id();
3331 writer.insert_freed_page_id(&mut db, tsn, page_id1).unwrap();
3332 inserted.push((tsn, page_id1));
3333
3334 let page_id2 = writer.alloc_page_id();
3336 writer.insert_freed_page_id(&mut db, tsn, page_id2).unwrap();
3337 inserted.push((tsn, page_id2));
3338
3339 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3341 match &root_page.node {
3342 Node::FreeListInternal(root_node) => {
3343 if !root_node.child_ids.is_empty() {
3345 let child_id = root_node.child_ids[0];
3346 if let Some(child_page) = writer.dirty.get(&child_id) {
3347 match &child_page.node {
3348 Node::FreeListInternal(_) => {
3349 has_split_internal = true;
3350 }
3351 _ => {}
3352 }
3353 }
3354 }
3355 }
3356 _ => {}
3357 }
3358 }
3359
3360 previous_writer_tsn = writer.tsn;
3362
3363 db.commit(&mut writer).unwrap();
3365 }
3366
3367 {
3369 let (header_page_id, header_node) = db.get_latest_header().unwrap();
3371
3372 let mut writer = Writer::new(
3374 header_page_id,
3375 Tsn(header_node.tsn.0 + 1),
3376 header_node.next_page_id,
3377 header_node.free_lists_tree_root_id,
3378 header_node.events_tree_root_id,
3379 header_node.tags_tree_root_id,
3380 header_node.next_position,
3381 VERBOSE,
3382 );
3383
3384 let old_root_id = writer.free_lists_tree_root_id;
3386
3387 for (tsn, page_id) in inserted.iter() {
3389 writer.remove_free_page_id(&db, *tsn, *page_id).unwrap();
3390 }
3391
3392 assert_ne!(old_root_id, writer.free_lists_tree_root_id);
3394 assert_eq!(1, writer.dirty.len());
3395 assert!(writer.dirty.contains_key(&writer.free_lists_tree_root_id));
3396
3397 let new_root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3398 assert_eq!(writer.free_lists_tree_root_id, new_root_page.page_id);
3399
3400 let freed_page_ids: Vec<PageID> = writer.freed_page_ids.iter().cloned().collect();
3402 assert!(freed_page_ids.contains(&old_root_id));
3403
3404 assert_eq!(13, writer.freed_page_ids.len());
3407
3408 match &new_root_page.node {
3410 Node::FreeListLeaf(node) => {
3411 let expected_keys = vec![previous_writer_tsn];
3412 assert_eq!(expected_keys, node.keys);
3413
3414 let expected_values = vec![FreeListLeafValue {
3415 page_ids: vec![previous_root_id],
3416 root_id: PageID(0),
3417 }];
3418 assert_eq!(expected_values, node.values);
3419 }
3420 _ => panic!("Expected FreeListLeaf node"),
3421 }
3422
3423 let active_page_ids = vec![
3425 HEADER_PAGE_ID_0,
3426 HEADER_PAGE_ID_1,
3427 writer.free_lists_tree_root_id,
3428 writer.events_tree_root_id,
3429 writer.tags_tree_root_id,
3430 ];
3431
3432 let mut all_freed_page_ids = freed_page_ids.clone();
3434
3435 match &new_root_page.node {
3437 Node::FreeListLeaf(node) => {
3438 for (_, value) in node.keys.iter().zip(node.values.iter()) {
3439 all_freed_page_ids.extend(value.page_ids.clone());
3440 }
3441 }
3442 _ => panic!("Expected FreeListLeaf node"),
3443 }
3444
3445 let inserted_page_ids: Vec<PageID> = inserted.iter().map(|(_, id)| *id).collect();
3447
3448 let mut all_page_ids = active_page_ids.clone();
3450 all_page_ids.extend(all_freed_page_ids.clone());
3451 all_page_ids.extend(inserted_page_ids.clone());
3452 all_page_ids.sort();
3453 all_page_ids.dedup();
3454
3455 let expected_page_ids: Vec<PageID> =
3457 (0..writer.next_page_id.0).map(PageID).collect();
3458 assert_eq!(expected_page_ids, all_page_ids);
3459 }
3460 }
3461
3462 #[test]
3463 #[serial]
3464 fn test_remove_freed_page_ids_until_replace_old_id_with_orphaned_child_id() {
3465 let (_temp_dir, mut db) = construct_mvcc(128);
3476
3477 let mut inserted: Vec<(Tsn, PageID)> = Vec::new();
3479
3480 {
3481 let mut writer = db.writer().unwrap();
3483
3484 let mut has_split_internal = false;
3486 let mut tsn = writer.tsn;
3487
3488 while !has_split_internal {
3489 tsn = Tsn(tsn.0 + 1);
3491 writer.tsn = tsn;
3492
3493 let page_id1 = writer.alloc_page_id();
3495 writer.insert_freed_page_id(&mut db, tsn, page_id1).unwrap();
3496 inserted.push((tsn, page_id1));
3497
3498 let page_id2 = writer.alloc_page_id();
3500 writer.insert_freed_page_id(&mut db, tsn, page_id2).unwrap();
3501 inserted.push((tsn, page_id2));
3502
3503 let root_page = writer.dirty.get(&writer.free_lists_tree_root_id).unwrap();
3505 match &root_page.node {
3506 Node::FreeListInternal(root_node) => {
3507 if !root_node.child_ids.is_empty() {
3509 let child_id = root_node.child_ids[0];
3510 if let Some(child_page) = writer.dirty.get(&child_id) {
3511 match &child_page.node {
3512 Node::FreeListInternal(_) => {
3513 has_split_internal = true;
3514 }
3515 _ => {}
3516 }
3517 }
3518 }
3519 }
3520 _ => {}
3521 }
3522 }
3523
3524 db.commit(&mut writer).unwrap();
3526 }
3527
3528 db.reader_tsns.remove(&0);
3530 let writer = db.writer().unwrap();
3531 let reusable_page_ids = writer.reusable_page_ids.clone();
3532
3533 db.reader_tsns.insert(0, Tsn(0));
3535
3536 for (page_id, tsn) in reusable_page_ids {
3538 let mut writer = db.writer().unwrap();
3539 writer.remove_free_page_id(&db, tsn, page_id).unwrap();
3540 db.commit(&mut writer).unwrap();
3541 }
3542 }
3543
3544 #[test]
3545 #[serial]
3546 fn test_insert_freed_page_ids_overflow_single_key_moves_to_tsn_subtree() {
3547 let page_size = 64;
3549 let (_temp_dir, mut mvcc) = construct_mvcc(page_size);
3550
3551 let mut writer = mvcc.writer().unwrap();
3553 let tsn = writer.tsn;
3554
3555 let mut inserted_count: usize = 0;
3558 loop {
3559 let pid = writer.alloc_page_id();
3560 writer.insert_freed_page_id(&mut mvcc, tsn, pid).unwrap();
3561 inserted_count += 1;
3562 let dirty_page_id = {
3563 let mut keys = writer.dirty.keys();
3564 assert_eq!(keys.len(), 1);
3565 *keys.next().unwrap()
3566 };
3567 let dirty_page = writer.get_mut_dirty(dirty_page_id).unwrap();
3568 if let Node::FreeListLeaf(leaf_node) = &dirty_page.node {
3569 if !leaf_node.would_fit_new_page_id(mvcc.max_node_size) {
3570 break;
3571 }
3572 } else {
3573 panic!("Expected leaf node")
3574 }
3575 }
3576
3577 let pid5 = writer.alloc_page_id();
3579 writer.insert_freed_page_id(&mut mvcc, tsn, pid5).unwrap();
3580 inserted_count += 1;
3581
3582 let pid6 = writer.alloc_page_id();
3584 writer.insert_freed_page_id(&mut mvcc, tsn, pid6).unwrap();
3585 inserted_count += 1;
3586
3587 let pid7 = writer.alloc_page_id();
3588 writer.insert_freed_page_id(&mut mvcc, tsn, pid7).unwrap();
3589 inserted_count += 1;
3590
3591 let dirty_ids: Vec<PageID> = { writer.dirty.keys().cloned().collect() };
3593 let mut tsn_root_id = PageID(0);
3594 for dirty_page_id in dirty_ids {
3595 let dirty_page = writer.get_mut_dirty(dirty_page_id).unwrap();
3596 if let Node::FreeListLeaf(leaf_node) = &dirty_page.node {
3597 assert_eq!(1, leaf_node.keys.len());
3598 assert_eq!(tsn, leaf_node.keys[0]);
3599 let val = &leaf_node.values[0];
3600 assert_eq!(0, val.page_ids.len());
3601 assert_ne!(PageID(0), val.root_id);
3602 tsn_root_id = val.root_id;
3603 break;
3604 }
3605 }
3606 assert_ne!(PageID(0), tsn_root_id);
3607 let tsn_root_page = writer.get_page_ref(&mvcc, tsn_root_id).unwrap();
3610 match &tsn_root_page.node {
3611 Node::FreeListTsnInternal(internal) => {
3612 assert_eq!(2, internal.child_ids.len());
3613 assert_eq!(1, internal.keys.len());
3614 }
3615 other => panic!(
3616 "Expected TSN-subtree internal node, got {:?}",
3617 other.type_name()
3618 ),
3619 }
3620
3621 let mut extra_inserts = 0usize;
3623 let mut guard = 0usize;
3624 loop {
3625 guard += 1;
3626 assert!(
3627 guard < 200,
3628 "guard hit while waiting for TSN-subtree internal split"
3629 );
3630 let pid = writer.alloc_page_id();
3631 writer.insert_freed_page_id(&mut mvcc, tsn, pid).unwrap();
3632 extra_inserts += 1;
3633
3634 let dirty_ids: Vec<PageID> = writer.dirty.keys().cloned().collect();
3636 tsn_root_id = PageID(0);
3637 for dirty_page_id in dirty_ids {
3638 let dirty_page = writer.get_mut_dirty(dirty_page_id).unwrap();
3639 if let Node::FreeListLeaf(leaf_node) = &dirty_page.node {
3640 assert_eq!(1, leaf_node.keys.len());
3641 assert_eq!(tsn, leaf_node.keys[0]);
3642 let val = &leaf_node.values[0];
3643 assert_eq!(0, val.page_ids.len());
3644 assert_ne!(PageID(0), val.root_id);
3645 tsn_root_id = val.root_id;
3646 break;
3647 }
3648 }
3649 assert_ne!(PageID(0), tsn_root_id);
3650
3651 let root_node_owned = {
3652 writer
3653 .get_page_ref(&mvcc, tsn_root_id)
3654 .unwrap()
3655 .node
3656 .clone()
3657 };
3658 match root_node_owned {
3659 Node::FreeListTsnInternal(internal_root) => {
3660 let first_child_id = internal_root.child_ids[0];
3662 let first_child_node = {
3663 writer
3664 .get_page_ref(&mvcc, first_child_id)
3665 .unwrap()
3666 .node
3667 .clone()
3668 };
3669 if matches!(first_child_node, Node::FreeListTsnInternal(_)) {
3670 assert_eq!(1, internal_root.keys.len());
3673 assert_eq!(2, internal_root.child_ids.len());
3674 break;
3675 }
3676 }
3677 other => panic!(
3678 "Expected TSN-subtree internal node, got {:?}",
3679 other.type_name()
3680 ),
3681 }
3682 }
3683
3684 let pid = writer.alloc_page_id();
3686 writer.insert_freed_page_id(&mut mvcc, tsn, pid).unwrap();
3687 extra_inserts += 1;
3688
3689 writer.find_reusable_page_ids(&mvcc).unwrap();
3691 assert_eq!(
3692 inserted_count + extra_inserts,
3693 writer.reusable_page_ids.len()
3694 );
3695 for &(_pid, _tsn) in writer.reusable_page_ids.iter() {
3696 assert_eq!(tsn, _tsn);
3697 }
3698 }
3699
3700 #[test]
3701 #[serial]
3702 fn test_remove_freed_page_id_from_tsn_subtree_leaf_pid1() {
3703 let (_temp_dir, db) = construct_mvcc(128);
3704 let mut writer = db.writer().unwrap();
3705
3706 let (pid1, pid2, tsn1) = build_free_list_tree_leaf_tsn_subtree_leaf(&mut writer);
3707
3708 writer.find_reusable_page_ids(&db).unwrap();
3709 assert_eq!(2, writer.reusable_page_ids.len());
3710 assert_eq!((pid1, tsn1), writer.reusable_page_ids[0]);
3711 assert_eq!((pid2, tsn1), writer.reusable_page_ids[1]);
3712
3713 writer.remove_free_page_id(&db, tsn1, pid1).unwrap();
3714 writer.find_reusable_page_ids(&db).unwrap();
3715 assert_eq!(1, writer.reusable_page_ids.len());
3716 assert_eq!((pid2, tsn1), writer.reusable_page_ids[0]);
3717 }
3718
3719 #[test]
3720 #[serial]
3721 fn test_remove_freed_page_id_from_tsn_subtree_leaf_pid2() {
3722 let (_temp_dir, db) = construct_mvcc(128);
3723 let mut writer = db.writer().unwrap();
3724
3725 let (pid1, pid2, tsn1) = build_free_list_tree_leaf_tsn_subtree_leaf(&mut writer);
3726
3727 writer.remove_free_page_id(&db, tsn1, pid2).unwrap();
3728 writer.find_reusable_page_ids(&db).unwrap();
3729 assert_eq!(1, writer.reusable_page_ids.len());
3730 assert_eq!((pid1, tsn1), writer.reusable_page_ids[0]);
3731 }
3732
3733 #[test]
3734 #[serial]
3735 fn test_tsn_subtree_random_order_insert_and_ordering() {
3736 let page_size = 256;
3738 let (_temp_dir, mut db) = construct_mvcc(page_size);
3739 let mut writer = db.writer().unwrap();
3740 let tsn = writer.tsn;
3741
3742 let n = 100usize;
3744 let mut pids: Vec<PageID> = Vec::with_capacity(n);
3745 for _ in 0..n {
3746 pids.push(writer.alloc_page_id());
3747 }
3748 for i in 0..pids.len() {
3750 let j = (i * 37 + 13) % pids.len();
3751 pids.swap(i, j);
3752 }
3753 for pid in &pids {
3755 writer.insert_freed_page_id(&mut db, tsn, *pid).unwrap();
3756 }
3757 let dup = pids[0];
3759 writer.insert_freed_page_id(&mut db, tsn, dup).unwrap();
3760
3761 writer.find_reusable_page_ids(&db).unwrap();
3763 assert_eq!(n, writer.reusable_page_ids.len());
3764 for &(_pid, _tsn) in writer.reusable_page_ids.iter() {
3765 assert_eq!(tsn, _tsn);
3766 }
3767
3768 let mut tsn_root_id = PageID(0);
3771 for page_id in writer.dirty.keys().cloned().collect::<Vec<_>>() {
3772 let page = writer.get_mut_dirty(page_id).unwrap();
3773 if let Node::FreeListLeaf(leaf_node) = &page.node {
3774 if !leaf_node.keys.is_empty() && leaf_node.keys[0] == tsn {
3775 tsn_root_id = leaf_node.values[0].root_id;
3776 break;
3777 }
3778 }
3779 }
3780 assert_ne!(PageID(0), tsn_root_id);
3781 let root_node_owned = { writer.get_page_ref(&db, tsn_root_id).unwrap().node.clone() };
3782 match root_node_owned {
3783 Node::FreeListTsnInternal(internal_root) => {
3784 let first_child_id = internal_root.child_ids[0];
3786 let first_child_node = {
3787 writer
3788 .get_page_ref(&db, first_child_id)
3789 .unwrap()
3790 .node
3791 .clone()
3792 };
3793 if let Node::FreeListTsnInternal(_in2) = first_child_node {
3794 }
3796 }
3797 Node::FreeListTsnLeaf(_) => {
3798 }
3800 other => panic!("Unexpected node type: {}", other.type_name()),
3801 }
3802 }
3803
3804 #[test]
3805 #[serial]
3806 fn test_upgrade_inline_to_tsn_subtree_with_random_inserts_and_duplicates() {
3807 let page_size = 96;
3809 let (_temp_dir, mut mvcc) = construct_mvcc(page_size);
3810 let mut writer = mvcc.writer().unwrap();
3811 let tsn = writer.tsn;
3812
3813 let mut inline_ids = Vec::new();
3815 loop {
3816 let pid = writer.alloc_page_id();
3817 let res = writer.insert_freed_page_id(&mut mvcc, tsn, pid);
3818 if res.is_err() {
3819 panic!("unexpected error inserting into inline");
3820 }
3821 inline_ids.push(pid);
3822 let dirty_id = writer.dirty.keys().cloned().next().unwrap();
3824 if let Node::FreeListLeaf(leaf_node) = &writer.get_mut_dirty(dirty_id).unwrap().node
3825 {
3826 if !leaf_node.would_fit_new_page_id(mvcc.max_node_size) {
3827 break;
3828 }
3829 }
3830 }
3831
3832 let mut extra_ids = Vec::new();
3834 for _ in 0..30 {
3835 extra_ids.push(writer.alloc_page_id());
3836 }
3837 for i in 0..extra_ids.len() {
3839 let j = (i * 29 + 7) % extra_ids.len();
3840 extra_ids.swap(i, j);
3841 }
3842 if !inline_ids.is_empty() {
3844 extra_ids.push(inline_ids[0]);
3845 }
3846 if inline_ids.len() > 1 {
3847 extra_ids.push(inline_ids[1]);
3848 }
3849
3850 for pid in &extra_ids {
3851 writer.insert_freed_page_id(&mut mvcc, tsn, *pid).unwrap();
3852 }
3853
3854 writer.find_reusable_page_ids(&mvcc).unwrap();
3856 let mut expected: Vec<PageID> = inline_ids.clone();
3857 for p in extra_ids {
3858 if !expected.contains(&p) {
3859 expected.push(p);
3860 }
3861 }
3862 expected.sort_by_key(|p| p.0);
3863 expected.dedup();
3864 let mut actual: Vec<PageID> =
3865 writer.reusable_page_ids.iter().map(|(p, _)| *p).collect();
3866 actual.sort_by_key(|p| p.0);
3867 assert_eq!(expected, actual);
3868 }
3869
3870 #[test]
3871 #[serial]
3872 fn test_remove_freed_page_id_from_tsn_subtree_leaf_all() {
3873 let (_temp_dir, db) = construct_mvcc(128);
3874 let mut writer = db.writer().unwrap();
3875
3876 let (pid1, pid2, tsn1) = build_free_list_tree_leaf_tsn_subtree_leaf(&mut writer);
3877
3878 writer.remove_free_page_id(&db, tsn1, pid1).unwrap();
3879 writer.remove_free_page_id(&db, tsn1, pid2).unwrap();
3880 writer.find_reusable_page_ids(&db).unwrap();
3881 assert_eq!(0, writer.reusable_page_ids.len());
3882
3883 assert_eq!(2, writer.freed_page_ids.len());
3884 }
3885
3886 #[test]
3887 #[serial]
3888 fn test_remove_freed_page_id_from_tsn_subtree_internal_leaf_pid1() {
3889 let (_temp_dir, db) = construct_mvcc(128);
3890 let mut writer = db.writer().unwrap();
3891
3892 let (pid1, pid2, pid3, pid4, tsn1) =
3893 build_free_list_tree_leaf_tsn_subtree_internal_leaf(&mut writer);
3894
3895 writer.remove_free_page_id(&db, tsn1, pid1).unwrap();
3896 writer.find_reusable_page_ids(&db).unwrap();
3897 assert_eq!(3, writer.reusable_page_ids.len());
3898 assert_eq!((pid2, tsn1), writer.reusable_page_ids[0]);
3899 assert_eq!((pid3, tsn1), writer.reusable_page_ids[1]);
3900 assert_eq!((pid4, tsn1), writer.reusable_page_ids[2]);
3901
3902 assert_eq!(1, writer.freed_page_ids.len());
3903
3904 writer.remove_free_page_id(&db, tsn1, pid2).unwrap();
3905 writer.find_reusable_page_ids(&db).unwrap();
3906 assert_eq!(2, writer.reusable_page_ids.len());
3907 assert_eq!((pid3, tsn1), writer.reusable_page_ids[0]);
3908 assert_eq!((pid4, tsn1), writer.reusable_page_ids[1]);
3909
3910 assert_eq!(3, writer.freed_page_ids.len());
3911
3912 writer.remove_free_page_id(&db, tsn1, pid3).unwrap();
3913 writer.find_reusable_page_ids(&db).unwrap();
3914 assert_eq!(1, writer.reusable_page_ids.len());
3915 assert_eq!((pid4, tsn1), writer.reusable_page_ids[0]);
3916
3917 assert_eq!(3, writer.freed_page_ids.len());
3918
3919 writer.remove_free_page_id(&db, tsn1, pid4).unwrap();
3920 writer.find_reusable_page_ids(&db).unwrap();
3921 assert_eq!(0, writer.reusable_page_ids.len());
3922
3923 assert_eq!(4, writer.freed_page_ids.len());
3924 }
3925
3926 #[test]
3927 #[serial]
3928 fn test_remove_freed_page_id_from_tsn_subtree_internal_internal_leaf_pid1() {
3929 let (_temp_dir, db) = construct_mvcc(128);
3930 let mut writer = db.writer().unwrap();
3931
3932 let (pid1, pid2, pid3, pid4, pid5, pid6, pid7, pid8, tsn) =
3933 build_free_list_tree_leaf_tsn_subtree_internal_internal_leaf(&mut writer);
3934
3935 writer.remove_free_page_id(&db, tsn, pid1).unwrap();
3936 writer.find_reusable_page_ids(&db).unwrap();
3937 assert_eq!(7, writer.reusable_page_ids.len());
3938 assert_eq!((pid2, tsn), writer.reusable_page_ids[0]);
3939 assert_eq!((pid3, tsn), writer.reusable_page_ids[1]);
3940 assert_eq!((pid4, tsn), writer.reusable_page_ids[2]);
3941 assert_eq!((pid5, tsn), writer.reusable_page_ids[3]);
3942 assert_eq!((pid6, tsn), writer.reusable_page_ids[4]);
3943 assert_eq!((pid7, tsn), writer.reusable_page_ids[5]);
3944 assert_eq!((pid8, tsn), writer.reusable_page_ids[6]);
3945
3946 assert_eq!(1, writer.freed_page_ids.len());
3947 }
3948
3949 #[test]
3950 #[serial]
3951 fn test_remove_freed_page_id_cow_does_not_leak_ids_in_tsn_subtree() {
3952 let (_temp_dir, db) = construct_mvcc(128);
3955
3956 let w1_tsn = {
3958 let mut w1 = db.writer().unwrap();
3959 let (_pid1, _pid2, _pid3, _pid4, _pid5, _pid6, _pid7, _pid8, tsn) =
3960 build_free_list_tree_leaf_tsn_subtree_internal_internal_leaf(&mut w1);
3961 db.commit(&mut w1).unwrap();
3963 tsn
3965 };
3966
3967 let mut w2 = db.writer().unwrap();
3969 w2.find_reusable_page_ids(&db).unwrap();
3971 assert!(w2.reusable_page_ids.len() >= 1);
3972 let (remove_pid, remove_tsn) = w2.reusable_page_ids[0];
3973 assert_eq!(remove_tsn, w1_tsn); w2.remove_free_page_id(&db, remove_tsn, remove_pid).unwrap();
3975
3976 let mut active: Vec<PageID> = Vec::new();
3979 let mut freed_tree: Vec<PageID> = Vec::new();
3980 active.push(HEADER_PAGE_ID_0);
3982 active.push(HEADER_PAGE_ID_1);
3983 active.push(w2.free_lists_tree_root_id);
3984 active.push(w2.events_tree_root_id);
3985 active.push(w2.tags_tree_root_id);
3986
3987 let mut stack: Vec<PageID> = vec![w2.free_lists_tree_root_id];
3989 while let Some(pid) = stack.pop() {
3990 if active.contains(&pid) == false {
3991 active.push(pid);
3992 }
3993 let node_owned = { w2.get_page_ref(&db, pid).unwrap().node.clone() };
3994 match node_owned {
3995 Node::FreeListInternal(internal) => {
3996 for child in internal.child_ids {
3997 stack.push(child);
3998 }
3999 }
4000 Node::FreeListLeaf(leaf) => {
4001 for val in &leaf.values {
4003 for &p in &val.page_ids {
4004 freed_tree.push(p);
4005 }
4006 }
4007 for val in leaf.values {
4009 if val.root_id != PageID(0) {
4010 let mut tsn_stack: Vec<PageID> = vec![val.root_id];
4011 while let Some(tid) = tsn_stack.pop() {
4012 if active.contains(&tid) == false {
4013 active.push(tid);
4014 }
4015 let tnode = { w2.get_page_ref(&db, tid).unwrap().node.clone() };
4016 match tnode {
4017 Node::FreeListTsnInternal(tint) => {
4018 for c in tint.child_ids {
4019 tsn_stack.push(c);
4020 }
4021 }
4022 Node::FreeListTsnLeaf(tleaf) => {
4023 for &p in &tleaf.page_ids {
4024 freed_tree.push(p);
4025 }
4026 }
4027 _ => panic!("Unexpected node type in TSN-subtree"),
4028 }
4029 }
4030 }
4031 }
4032 }
4033 _ => panic!("Unexpected node type in free list tree"),
4034 }
4035 }
4036
4037 for (&pid, _page) in w2.dirty.iter() {
4039 if !active.contains(&pid) {
4040 active.push(pid);
4041 }
4042 }
4043 for (&pid, _page) in w2.deserialized.iter() {
4045 if !active.contains(&pid) {
4046 active.push(pid);
4047 }
4048 }
4049
4050 let mut freed: Vec<PageID> = w2.freed_page_ids.iter().cloned().collect();
4052 freed.extend(freed_tree);
4054 for (pid, _tsn) in w2.reusable_page_ids.iter() {
4056 freed.push(*pid);
4057 }
4058
4059 active.sort_by_key(|p| p.0);
4061 active.dedup();
4062 freed.sort_by_key(|p| p.0);
4063 freed.dedup();
4064 let mut union = active.clone();
4065 for id in &freed {
4066 if !union.contains(id) {
4067 union.push(*id);
4068 }
4069 }
4070 union.sort_by_key(|p| p.0);
4071
4072 let expected: Vec<PageID> = (0..w2.next_page_id.0).map(PageID).collect();
4073 if expected != union {
4074 let mut missing: Vec<PageID> = expected
4075 .iter()
4076 .cloned()
4077 .filter(|p| !union.contains(p))
4078 .collect();
4079 let mut unexpected: Vec<PageID> = union
4080 .iter()
4081 .cloned()
4082 .filter(|p| !expected.contains(p))
4083 .collect();
4084 missing.sort_by_key(|p| p.0);
4085 unexpected.sort_by_key(|p| p.0);
4086 panic!(
4087 "Missing: {:?} Unexpected: {:?}\nactive: {:?}\nfreed: {:?}",
4088 missing, unexpected, active, freed
4089 );
4090 }
4091 assert_eq!(
4092 expected, union,
4093 "All page IDs must be accounted for (active or freed)"
4094 );
4095 }
4096 }
4097}