66
77use std:: borrow:: Borrow ;
88use std:: cmp:: Ordering ;
9+ use std:: ops:: Deref ;
910use std:: sync:: OnceLock ;
1011
1112use bincode:: Decode ;
@@ -22,6 +23,8 @@ use octez_riscv_data::hash::HashFold;
2223use octez_riscv_data:: mode:: Mode ;
2324use octez_riscv_data:: mode:: Normal ;
2425use octez_riscv_data:: mode:: Prove ;
26+ use octez_riscv_data:: serialisation:: deserialise;
27+ use octez_riscv_data:: serialisation:: serialise;
2528use perfect_derive:: perfect_derive;
2629
2730use super :: resolver:: LazyTreeId ;
@@ -32,6 +35,10 @@ use crate::avl::resolver::AvlResolver;
3235use crate :: errors:: Error ;
3336use crate :: errors:: OperationalError ;
3437use crate :: key:: Key ;
38+ use crate :: storage:: KeyValueStore ;
39+ use crate :: storage:: Loadable ;
40+ use crate :: storage:: Storable ;
41+ use crate :: storage:: StoreOptions ;
3542
3643/// Metadata of a [`Node`] needed for accesses.
3744#[ derive( Clone , Default , Debug , Encode , Decode ) ]
@@ -42,22 +49,12 @@ pub(crate) struct Meta {
4249 balance_factor : i64 ,
4350}
4451
45- /// A serialisable representation of [`Meta`] .
52+ /// This type is a compact serialised form of a [`Node`] with metadata and child subtree hashes .
4653#[ derive( Encode , Decode ) ]
47- pub ( super ) struct MetaHashRepresentation < K : Borrow < self :: Key > > {
48- key : K ,
49- balance_factor : i64 ,
50- }
51-
52- /// A serialisable representation of [`Node`].
53- #[ derive( Encode , Decode ) ]
54- pub ( super ) struct NodeHashRepresentation < Data , K : Borrow < self :: Key > , H : Borrow < self :: Hash > > {
55- meta : MetaHashRepresentation < K > ,
56- data : Data ,
57- // The hash of the left subtree.
58- left : H ,
59- // The hash of the right subtree.
60- right : H ,
54+ struct StoredNode {
55+ meta : Meta ,
56+ left : Hash ,
57+ right : Hash ,
6158}
6259
6360/// A node that supports rebalancing and Merklisation.
@@ -75,25 +72,6 @@ pub struct Node<TreeId, M: Mode> {
7572 hash : OnceLock < Hash > ,
7673}
7774
78- impl < TreeId , M : BytesMode + AtomMode > From < NodeHashRepresentation < Bytes < M > , Key , Hash > >
79- for Node < TreeId , M >
80- where
81- TreeId : From < Hash > ,
82- {
83- fn from ( node_repr : NodeHashRepresentation < Bytes < M > , Key , Hash > ) -> Self {
84- Node {
85- meta : Atom :: new ( Meta {
86- key : node_repr. meta . key ,
87- balance_factor : node_repr. meta . balance_factor ,
88- } ) ,
89- data : node_repr. data ,
90- left : TreeId :: from ( node_repr. left ) ,
91- right : TreeId :: from ( node_repr. right ) ,
92- hash : OnceLock :: new ( ) ,
93- }
94- }
95- }
96-
9775impl Node < LazyTreeId , Normal > {
9876 /// Converts the [`Node`] to [`Prove`] mode.
9977 pub fn into_proof ( self ) -> Node < ProveTreeId , Prove < ' static > > {
@@ -170,31 +148,12 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
170148 }
171149 }
172150
173- /// Converts the [`Node`] to an encoded, serialisable representation,
174- /// [`NodeHashRepresentation`], potentially re-hashing uncached [`Node`]s.
175- pub ( crate ) fn to_encode < ' a > ( & ' a self ) -> impl Encode + ' a
176- where
177- Bytes < M > : Encode ,
178- TreeId : Foldable < HashFold > ,
179- {
180- NodeHashRepresentation {
181- meta : MetaHashRepresentation {
182- key : & self . meta . key ,
183- balance_factor : self . meta . balance_factor ,
184- } ,
185- data : & self . data ,
186- left : Hash :: from_foldable ( & self . left ) ,
187- right : Hash :: from_foldable ( & self . right ) ,
188- }
189- }
190-
191151 /// Returns the hash of this node.
192152 ///
193153 /// If the hash has been cached, the memo is returned. Otherwise, the hash is calculated and
194154 /// cached.
195155 pub ( crate ) fn hash ( & self ) -> & Hash
196156 where
197- TreeId : Foldable < HashFold > ,
198157 Atom < Meta , M > : Foldable < HashFold > ,
199158 Bytes < M > : Foldable < HashFold > ,
200159 TreeId : Foldable < HashFold > ,
@@ -204,7 +163,7 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
204163
205164 #[ inline]
206165 /// The difference in heights between child branches.
207- pub ( super ) fn balance_factor ( & self ) -> i64 {
166+ pub ( crate ) fn balance_factor ( & self ) -> i64 {
208167 self . meta . balance_factor
209168 }
210169
@@ -216,10 +175,16 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
216175
217176 #[ inline]
218177 /// The [`Key`] used for determining the [`Node`].
219- pub ( super ) fn key ( & self ) -> & Key {
178+ pub ( crate ) fn key ( & self ) -> & Key {
220179 & self . meta . key
221180 }
222181
182+ /// Retrieve the value associated with this node.
183+ #[ cfg( all( test, feature = "rocksdb" ) ) ]
184+ pub ( crate ) fn value ( & self ) -> & Bytes < M > {
185+ & self . data
186+ }
187+
223188 /// Rebalance the subtree of the [`Node`] so that the difference in height between child
224189 /// branches is in the range of -1..=1.
225190 ///
@@ -832,6 +797,80 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
832797 }
833798}
834799
800+ impl < TreeId : Storable > Storable for Node < TreeId , Normal > {
801+ fn store (
802+ & self ,
803+ store : & impl KeyValueStore ,
804+ options : & StoreOptions ,
805+ ) -> Result < ( ) , OperationalError > {
806+ // The stored representation is more compact. We don't include the `data` field, as that
807+ // should be written to the KV store separately.
808+ let repr = StoredNode {
809+ meta : self . meta . deref ( ) . clone ( ) ,
810+ left : Hash :: from_foldable ( & self . left ) ,
811+ right : Hash :: from_foldable ( & self . right ) ,
812+ } ;
813+
814+ let & id = self . hash ( ) ;
815+ let bytes = serialise ( repr) ?;
816+ store. blob_set ( id, bytes) ?;
817+
818+ // Are we in charge of writing the value data to the KV store?
819+ if options. node_data ( ) {
820+ let key: & [ u8 ] = self . meta . key . as_ref ( ) ;
821+ let value: & [ u8 ] = self . data . borrow ( ) ;
822+ store. set ( key, value) ?;
823+ }
824+
825+ if options. deep ( ) {
826+ self . left . store ( store, options) ?;
827+ self . right . store ( store, options) ?;
828+ }
829+
830+ Ok ( ( ) )
831+ }
832+ }
833+
834+ impl < TreeId : Loadable > Loadable for Node < TreeId , Normal > {
835+ fn load ( id : Hash , store : & impl KeyValueStore ) -> Result < Self , OperationalError > {
836+ let StoredNode { meta, left, right } = {
837+ let bytes =
838+ store
839+ . blob_get ( id)
840+ . map_err ( |error| OperationalError :: CommitDataMissing {
841+ root : id,
842+ source : Box :: new ( error) ,
843+ } ) ?;
844+ deserialise ( bytes. as_ref ( ) ) ?
845+ } ;
846+
847+ let meta = Atom :: new ( meta) ;
848+
849+ // The stored representation does not include the `data` field, so we need to load it
850+ // separately from the KV store.
851+ let data = {
852+ let bytes = store. get ( meta. key . as_ref ( ) ) . map_err ( |error| {
853+ OperationalError :: CommitValueMissing {
854+ key : meta. key . clone ( ) ,
855+ source : Box :: new ( error) ,
856+ }
857+ } ) ?;
858+ Bytes :: from ( bytes. as_ref ( ) )
859+ } ;
860+
861+ let left = TreeId :: load ( left, store) ?;
862+ let right = TreeId :: load ( right, store) ?;
863+
864+ Ok ( Self {
865+ meta,
866+ data,
867+ left,
868+ right,
869+ hash : OnceLock :: new ( ) ,
870+ } )
871+ }
872+ }
873+
835874impl < F , TreeId , M > Foldable < F > for Node < TreeId , M >
836875where
837876 F : Fold ,
0 commit comments