cfx_storage/impls/delta_mpt/
node_ref.rs

1// Copyright 2019 Conflux Foundation. All rights reserved.
2// Conflux is free software and distributed under GNU General Public License.
3// See http://www.gnu.org/licenses/
4
5pub type CompactNodeRef = RowNumberUnderlyingType;
6
7/// The MSB is used to indicate if a node is in mem or on disk,
8/// the rest 31 bits specifies the index of the node in the
9/// memory region.
10///
11/// It's necessary to use MaybeNodeRef in ChildrenTable because it consumes less
12/// space than NodeRef.
13#[derive(Copy, Clone, Debug, Eq, PartialEq, MallocSizeOfDerive)]
14pub struct NodeRefDeltaMptCompact {
15    value: CompactNodeRef,
16}
17
18impl NodeRefTrait for NodeRefDeltaMptCompact {}
19
20#[derive(Copy, Clone, Debug, Eq, PartialEq, MallocSizeOfDerive)]
21pub struct MaybeNodeRefDeltaMptCompact {
22    value: CompactNodeRef,
23}
24
25impl Default for MaybeNodeRefDeltaMptCompact {
26    fn default() -> Self { Self { value: Self::NULL } }
27}
28
29impl NodeRefDeltaMptCompact {
30    /// Valid dirty slot ranges from [0..DIRTY_SLOT_LIMIT).
31    /// The DIRTY_SLOT_LIMIT is reserved for MaybeNodeRefDeltaMptCompact#NULL.
32    pub const DIRTY_SLOT_LIMIT: u32 = 0x7fffffff;
33    const LARGE_PERSISTENT_KEY_BIT: CompactNodeRef =
34        1 << (CompactNodeRef::BITS - 1);
35    /// All the bit operations assume that a persistent key is less than
36    /// PERSISTENT_KEY_BIT.
37    const PERSISTENT_KEY_BIT: CompactNodeRef = 0x80000000;
38
39    pub fn new(value: CompactNodeRef) -> Self { Self { value } }
40}
41
42impl MaybeNodeRefDeltaMptCompact {
43    pub const NULL: CompactNodeRef = 0;
44    pub const NULL_NODE: MaybeNodeRefDeltaMptCompact =
45        MaybeNodeRefDeltaMptCompact { value: Self::NULL };
46
47    pub fn new(value: CompactNodeRef) -> Self { Self { value } }
48}
49
50// Manages access to a TrieNode. Converted from MaybeNodeRef. NodeRef is not
51// copy because it controls access to TrieNode.
52#[derive(Clone, Eq, PartialOrd, PartialEq, Ord, Debug, MallocSizeOfDerive)]
53pub enum NodeRefDeltaMpt {
54    Committed { db_key: DeltaMptDbKey },
55    Dirty { index: ActualSlabIndex },
56}
57
58impl From<NodeRefDeltaMpt> for NodeRefDeltaMptCompact {
59    fn from(node: NodeRefDeltaMpt) -> Self {
60        match node {
61            NodeRefDeltaMpt::Committed { db_key } => Self {
62                value: if db_key < NodeRefDeltaMptCompact::PERSISTENT_KEY_BIT {
63                    db_key ^ NodeRefDeltaMptCompact::PERSISTENT_KEY_BIT
64                } else {
65                    if cfg!(feature = "u64_mpt_db_key") {
66                        db_key ^ NodeRefDeltaMptCompact::PERSISTENT_KEY_BIT
67                            | NodeRefDeltaMptCompact::LARGE_PERSISTENT_KEY_BIT
68                    } else {
69                        unreachable!("should not run large state with u32 key")
70                    }
71                },
72            },
73            NodeRefDeltaMpt::Dirty { index } => Self {
74                value: (index ^ NodeRefDeltaMptCompact::DIRTY_SLOT_LIMIT)
75                    as CompactNodeRef,
76            },
77        }
78    }
79}
80
81impl From<NodeRefDeltaMptCompact> for NodeRefDeltaMpt {
82    fn from(x: NodeRefDeltaMptCompact) -> Self {
83        if NodeRefDeltaMptCompact::PERSISTENT_KEY_BIT & x.value == 0
84            // if `CompactNodeRef` is u32, `PERSISTENT_KEY_BIT` and `LARGE_PERSISTENT_KEY_BIT` are the same.
85            && (NodeRefDeltaMptCompact::LARGE_PERSISTENT_KEY_BIT as CompactNodeRef) & x.value == 0
86        {
87            NodeRefDeltaMpt::Dirty {
88                index: (NodeRefDeltaMptCompact::DIRTY_SLOT_LIMIT
89                    ^ x.value as u32),
90            }
91        } else {
92            NodeRefDeltaMpt::Committed {
93                db_key: (NodeRefDeltaMptCompact::PERSISTENT_KEY_BIT ^ x.value)
94                    & !NodeRefDeltaMptCompact::LARGE_PERSISTENT_KEY_BIT,
95            }
96        }
97    }
98}
99
100impl From<MaybeNodeRefDeltaMptCompact> for Option<NodeRefDeltaMpt> {
101    fn from(x: MaybeNodeRefDeltaMptCompact) -> Self {
102        if x.value == MaybeNodeRefDeltaMptCompact::NULL {
103            None
104        } else {
105            Some(NodeRefDeltaMptCompact::new(x.value).into())
106        }
107    }
108}
109
110impl From<Option<NodeRefDeltaMpt>> for MaybeNodeRefDeltaMptCompact {
111    fn from(maybe_node: Option<NodeRefDeltaMpt>) -> Self {
112        match maybe_node {
113            None => MaybeNodeRefDeltaMptCompact::NULL_NODE,
114            Some(node) => MaybeNodeRefDeltaMptCompact::new(
115                NodeRefDeltaMptCompact::from(node).value,
116            ),
117        }
118    }
119}
120
121impl Decodable for NodeRefDeltaMptCompact {
122    fn decode(rlp: &Rlp) -> ::std::result::Result<Self, DecoderError> {
123        Ok(NodeRefDeltaMptCompact {
124            value: rlp.as_val()?,
125        })
126    }
127}
128
129impl Encodable for NodeRefDeltaMptCompact {
130    fn rlp_append(&self, s: &mut RlpStream) { s.append_internal(&self.value); }
131}
132
133use super::{
134    super::merkle_patricia_trie::NodeRefTrait,
135    node_memory_manager::ActualSlabIndex, node_ref_map::DeltaMptDbKey,
136};
137use crate::impls::delta_mpt::row_number::RowNumberUnderlyingType;
138use malloc_size_of_derive::MallocSizeOf as MallocSizeOfDerive;
139use rlp::*;
140
141#[test]
142#[cfg(feature = "u64_mpt_db_key")]
143fn test_large_key() {
144    let db_key = NodeRefDeltaMpt::Committed { db_key: (1 << 32) };
145    let compact: NodeRefDeltaMptCompact = db_key.clone().into();
146    let a = match db_key {
147        NodeRefDeltaMpt::Committed { db_key } => db_key,
148        _ => unreachable!(),
149    };
150    let b = match NodeRefDeltaMpt::from(compact) {
151        NodeRefDeltaMpt::Committed { db_key } => db_key,
152        _ => unreachable!(),
153    };
154    assert_eq!(a.to_be_bytes(), b.to_be_bytes());
155}