oasis_core_runtime/storage/mkvs/tree/
commit.rs

1use anyhow::Result;
2
3use crate::{
4    common::{crypto::hash::Hash, namespace::Namespace},
5    storage::mkvs::{
6        cache::{Cache, LRUCache, UpdateList},
7        tree::{Node, NodeBox, NodeKind, NodePtrRef, Root, Tree},
8    },
9};
10
11impl Tree {
12    /// Commit tree updates to the underlying database and return
13    /// the write log and new merkle root.
14    pub fn commit(&mut self, namespace: Namespace, version: u64) -> Result<Hash> {
15        let mut update_list: UpdateList<LRUCache> = UpdateList::new();
16        let pending_root = self.cache.borrow().get_pending_root();
17        let new_hash = _commit(pending_root, &mut update_list)?;
18
19        update_list.commit(&mut self.cache.borrow_mut());
20
21        self.cache.borrow_mut().set_sync_root(Root {
22            namespace,
23            version,
24            root_type: self.root_type,
25            hash: new_hash,
26        });
27
28        Ok(new_hash)
29    }
30}
31
32pub fn _commit<C: Cache>(ptr: NodePtrRef, update_list: &mut UpdateList<C>) -> Result<Hash> {
33    if ptr.borrow().clean {
34        return Ok(ptr.borrow().hash);
35    }
36
37    match classify_noderef!(? ptr.borrow().node) {
38        NodeKind::None => {
39            ptr.borrow_mut().hash = Hash::empty_hash();
40        }
41        NodeKind::Internal => {
42            let some_node_ref = ptr.borrow().get_node();
43            if some_node_ref.borrow().is_clean() {
44                ptr.borrow_mut().hash = some_node_ref.borrow().get_hash();
45            } else {
46                let int_leaf_node = noderef_as!(some_node_ref, Internal).leaf_node.clone();
47                let int_left = noderef_as!(some_node_ref, Internal).left.clone();
48                let int_right = noderef_as!(some_node_ref, Internal).right.clone();
49
50                _commit(int_leaf_node, update_list)?;
51                _commit(int_left, update_list)?;
52                _commit(int_right, update_list)?;
53
54                some_node_ref.borrow_mut().update_hash();
55                ptr.borrow_mut().hash = some_node_ref.borrow().get_hash();
56
57                update_list.push(Box::new(move |_| {
58                    noderef_as_mut!(some_node_ref, Internal).clean = true
59                }));
60            }
61        }
62        NodeKind::Leaf => {
63            let node_ref = ptr.borrow().get_node();
64            if node_ref.borrow().is_clean() {
65                ptr.borrow_mut().hash = node_ref.borrow().get_hash();
66            } else {
67                node_ref.borrow_mut().update_hash();
68                ptr.borrow_mut().hash = node_ref.borrow().get_hash();
69
70                update_list.push(Box::new(move |_| {
71                    noderef_as_mut!(node_ref, Leaf).clean = true
72                }));
73            }
74        }
75    };
76
77    let closure_ptr = ptr.clone();
78    update_list.push(Box::new(move |cache| {
79        closure_ptr.borrow_mut().clean = true;
80        // Make node eligible for eviction.
81        cache.commit_node(closure_ptr.clone());
82    }));
83
84    Ok(ptr.borrow().hash)
85}