sled/
meta.rs

1use crate::*;
2
3/// A simple map that can be used to store metadata
4/// for the pagecache tenant.
5#[derive(Clone, Debug, Eq, PartialEq, Default)]
6pub struct Meta {
7    pub(crate) inner: BTreeMap<IVec, PageId>,
8}
9
10impl Meta {
11    /// Retrieve the `PageId` associated with an identifier
12    pub(crate) fn get_root(&self, table: &[u8]) -> Option<PageId> {
13        self.inner.get(table).cloned()
14    }
15
16    /// Set the `PageId` associated with an identifier
17    pub(crate) fn set_root(
18        &mut self,
19        name: IVec,
20        pid: PageId,
21    ) -> Option<PageId> {
22        self.inner.insert(name, pid)
23    }
24
25    /// Remove the page mapping for a given identifier
26    pub(crate) fn del_root(&mut self, name: &[u8]) -> Option<PageId> {
27        self.inner.remove(name)
28    }
29
30    /// Return the current rooted tenants in Meta
31    pub(crate) fn tenants(&self) -> BTreeMap<IVec, PageId> {
32        self.inner.clone()
33    }
34
35    pub(crate) fn rss(&self) -> u64 {
36        self.inner
37            .iter()
38            .map(|(k, _pid)| {
39                k.len() as u64 + std::mem::size_of::<PageId>() as u64
40            })
41            .sum()
42    }
43}
44
45/// Open or create a new disk-backed Tree with its own keyspace,
46/// accessible from the `Db` via the provided identifier.
47pub(crate) fn open_tree<V>(
48    context: &Context,
49    raw_name: V,
50    guard: &Guard,
51) -> Result<Tree>
52where
53    V: Into<IVec>,
54{
55    let name = raw_name.into();
56
57    // we loop because creating this Tree may race with
58    // concurrent attempts to open the same one.
59    loop {
60        match context.pagecache.meta_pid_for_name(&name, guard) {
61            Ok(root_id) => {
62                return Ok(Tree(Arc::new(TreeInner {
63                    tree_id: name,
64                    context: context.clone(),
65                    subscribers: Subscribers::default(),
66                    root: AtomicU64::new(root_id),
67                    merge_operator: RwLock::new(None),
68                })));
69            }
70            Err(Error::CollectionNotFound(_)) => {}
71            Err(other) => return Err(other),
72        }
73
74        // set up empty leaf
75        let leaf = Node::default();
76        let (leaf_id, leaf_ptr) = context.pagecache.allocate(leaf, guard)?;
77
78        trace!(
79            "allocated pid {} for leaf in new_tree for namespace {:?}",
80            leaf_id,
81            name
82        );
83
84        // set up root index
85
86        // vec![0] represents a prefix-encoded empty prefix
87        let root = Node::new_root(leaf_id);
88        let (root_id, root_ptr) = context.pagecache.allocate(root, guard)?;
89
90        debug!("allocated pid {} for root of new_tree {:?}", root_id, name);
91
92        let res = context.pagecache.cas_root_in_meta(
93            &name,
94            None,
95            Some(root_id),
96            guard,
97        )?;
98
99        if res.is_err() {
100            // clean up the tree we just created if we couldn't
101            // install it.
102            let _ = context
103                .pagecache
104                .free(root_id, root_ptr, guard)?
105                .expect("could not free allocated page");
106            let _ = context
107                .pagecache
108                .free(leaf_id, leaf_ptr, guard)?
109                .expect("could not free allocated page");
110            continue;
111        }
112
113        return Ok(Tree(Arc::new(TreeInner {
114            tree_id: name,
115            subscribers: Subscribers::default(),
116            context: context.clone(),
117            root: AtomicU64::new(root_id),
118            merge_operator: RwLock::new(None),
119        })));
120    }
121}