Skip to main content

reddb_engine/storage/btree/
reclaim.rs

1use super::*;
2
3impl<P: PageStore> BTree<P> {
4    pub fn has_retirement_readers(&self) -> bool {
5        Arc::strong_count(&self.retirement_pin) != 1
6    }
7
8    /// Enumerate a retired generation before changing the allocator. Never
9    /// follow leaf sibling links as additional ownership edges: interior
10    /// children already own every leaf. Validate overflow chains as well.
11    pub fn retired_pages(&self) -> BTreeResult<Vec<u32>> {
12        let mut pending = vec![self.root_page_id()];
13        let mut seen = std::collections::HashSet::new();
14        let mut pages = Vec::new();
15        let page_count = self.pager.page_count()?;
16        while let Some(id) = pending.pop() {
17            if id == 0 {
18                continue;
19            }
20            if id >= page_count || !seen.insert(id) {
21                return Err(BTreeError::Corrupted(
22                    "invalid retired tree page ownership".into(),
23                ));
24            }
25            let page = self.pager.read_page(id)?;
26            match page.page_type()? {
27                PageType::BTreeInterior => {
28                    let (_, children) = read_interior_keys_children(&page)?;
29                    pending.extend(children);
30                }
31                PageType::BTreeLeaf => {
32                    for index in 0..usize::from(page.cell_count()) {
33                        let (_, stored) = read_leaf_cell(&page, index)?;
34                        if let Some(head) = value_layout::pointer_head(&stored) {
35                            pending.push(head);
36                        }
37                    }
38                }
39                PageType::Overflow => {
40                    let content = page.content();
41                    let next = u32::from_le_bytes(content[..4].try_into().expect("chain header"));
42                    let len = u32::from_le_bytes(content[4..8].try_into().expect("chain length"));
43                    if len as usize > crate::storage::overflow::OVERFLOW_PAYLOAD_PER_PAGE {
44                        return Err(BTreeError::Corrupted(
45                            "invalid retired overflow length".into(),
46                        ));
47                    }
48                    pending.push(next);
49                }
50                _ => {
51                    return Err(BTreeError::Corrupted(
52                        "unexpected retired tree page type".into(),
53                    ))
54                }
55            }
56            pages.push(id);
57        }
58        Ok(pages)
59    }
60}