66
77use std:: borrow:: Borrow ;
88use std:: cmp:: Ordering ;
9+ use std:: ops:: Deref ;
910use std:: sync:: OnceLock ;
1011
1112use bincode:: Decode ;
@@ -20,6 +21,9 @@ use octez_riscv_data::foldable::NodeFold;
2021use octez_riscv_data:: hash:: Hash ;
2122use octez_riscv_data:: hash:: HashFold ;
2223use octez_riscv_data:: mode:: Mode ;
24+ use octez_riscv_data:: mode:: Normal ;
25+ use octez_riscv_data:: serialisation:: deserialise;
26+ use octez_riscv_data:: serialisation:: serialise;
2327use perfect_derive:: perfect_derive;
2428
2529use super :: resolver:: TreeResolver ;
@@ -28,6 +32,10 @@ use crate::avl::resolver::AvlResolver;
2832use crate :: errors:: Error ;
2933use crate :: errors:: OperationalError ;
3034use crate :: key:: Key ;
35+ use crate :: storage:: KeyValueStore ;
36+ use crate :: storage:: Loadable ;
37+ use crate :: storage:: Storable ;
38+ use crate :: storage:: StoreOptions ;
3139
3240/// Metadata of a [`Node`] needed for accesses.
3341#[ derive( Clone , Default , Debug , Encode , Decode ) ]
@@ -38,22 +46,12 @@ pub(crate) struct Meta {
3846 balance_factor : i64 ,
3947}
4048
41- /// A serialisable representation of [`Meta`] .
49+ /// This type is a compact serialised form of a [`Node`] with metadata and child subtree hashes .
4250#[ derive( Encode , Decode ) ]
43- pub ( super ) struct MetaHashRepresentation < K : Borrow < self :: Key > > {
44- key : K ,
45- balance_factor : i64 ,
46- }
47-
48- /// A serialisable representation of [`Node`].
49- #[ derive( Encode , Decode ) ]
50- pub ( super ) struct NodeHashRepresentation < Data , K : Borrow < self :: Key > , H : Borrow < self :: Hash > > {
51- meta : MetaHashRepresentation < K > ,
52- data : Data ,
53- // The hash of the left subtree.
54- left : H ,
55- // The hash of the right subtree.
56- right : H ,
51+ struct StoredNode {
52+ meta : Meta ,
53+ left : Hash ,
54+ right : Hash ,
5755}
5856
5957/// A node that supports rebalancing and Merklisation.
@@ -71,25 +69,6 @@ pub struct Node<TreeId, M: Mode> {
7169 hash : OnceLock < Hash > ,
7270}
7371
74- impl < TreeId , M : BytesMode + AtomMode > From < NodeHashRepresentation < Bytes < M > , Key , Hash > >
75- for Node < TreeId , M >
76- where
77- TreeId : From < Hash > ,
78- {
79- fn from ( node_repr : NodeHashRepresentation < Bytes < M > , Key , Hash > ) -> Self {
80- Node {
81- meta : Atom :: new ( Meta {
82- key : node_repr. meta . key ,
83- balance_factor : node_repr. meta . balance_factor ,
84- } ) ,
85- data : node_repr. data ,
86- left : TreeId :: from ( node_repr. left ) ,
87- right : TreeId :: from ( node_repr. right ) ,
88- hash : OnceLock :: new ( ) ,
89- }
90- }
91- }
92-
9372impl < TreeId , M : Mode > Node < TreeId , M > {
9473 /// Mark the hash of this node as dirty.
9574 fn invalidate_hash ( & mut self ) {
@@ -153,31 +132,12 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
153132 }
154133 }
155134
156- /// Converts the [`Node`] to an encoded, serialisable representation,
157- /// [`NodeHashRepresentation`], potentially re-hashing uncached [`Node`]s.
158- pub ( crate ) fn to_encode < ' a > ( & ' a self ) -> impl Encode + ' a
159- where
160- Bytes < M > : Encode ,
161- TreeId : Foldable < HashFold > ,
162- {
163- NodeHashRepresentation {
164- meta : MetaHashRepresentation {
165- key : & self . meta . key ,
166- balance_factor : self . meta . balance_factor ,
167- } ,
168- data : & self . data ,
169- left : Hash :: from_foldable ( & self . left ) ,
170- right : Hash :: from_foldable ( & self . right ) ,
171- }
172- }
173-
174135 /// Returns the hash of this node.
175136 ///
176137 /// If the hash has been cached, the memo is returned. Otherwise, the hash is calculated and
177138 /// cached.
178139 pub ( crate ) fn hash ( & self ) -> & Hash
179140 where
180- TreeId : Foldable < HashFold > ,
181141 Atom < Meta , M > : Foldable < HashFold > ,
182142 Bytes < M > : Foldable < HashFold > ,
183143 TreeId : Foldable < HashFold > ,
@@ -187,7 +147,7 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
187147
188148 #[ inline]
189149 /// The difference in heights between child branches.
190- pub ( super ) fn balance_factor ( & self ) -> i64 {
150+ pub ( crate ) fn balance_factor ( & self ) -> i64 {
191151 self . meta . balance_factor
192152 }
193153
@@ -199,10 +159,16 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
199159
200160 #[ inline]
201161 /// The [`Key`] used for determining the [`Node`].
202- pub ( super ) fn key ( & self ) -> & Key {
162+ pub ( crate ) fn key ( & self ) -> & Key {
203163 & self . meta . key
204164 }
205165
166+ /// Retrieve the value associated with this node.
167+ #[ cfg( test) ]
168+ pub ( crate ) fn value ( & self ) -> & Bytes < M > {
169+ & self . data
170+ }
171+
206172 /// Rebalance the subtree of the [`Node`] so that the difference in height between child
207173 /// branches is in the range of -1..=1.
208174 ///
@@ -815,6 +781,80 @@ impl<TreeId, M: BytesMode + AtomMode> Node<TreeId, M> {
815781 }
816782}
817783
784+ impl < TreeId : Storable > Storable for Node < TreeId , Normal > {
785+ fn store (
786+ & self ,
787+ store : & impl KeyValueStore ,
788+ options : & StoreOptions ,
789+ ) -> Result < ( ) , OperationalError > {
790+ // The stored representation is more compact. We don't include the `data` field, as that
791+ // should be written to the KV store separately.
792+ let repr = StoredNode {
793+ meta : self . meta . deref ( ) . clone ( ) ,
794+ left : Hash :: from_foldable ( & self . left ) ,
795+ right : Hash :: from_foldable ( & self . right ) ,
796+ } ;
797+
798+ let & id = self . hash ( ) ;
799+ let bytes = serialise ( repr) ?;
800+ store. blob_set ( id, bytes) ?;
801+
802+ // Are we in charge of writing the value data to the KV store?
803+ if options. node_data ( ) {
804+ let key: & [ u8 ] = self . meta . key . as_ref ( ) ;
805+ let value: & [ u8 ] = self . data . borrow ( ) ;
806+ store. set ( key, value) ?;
807+ }
808+
809+ if options. deep ( ) {
810+ self . left . store ( store, options) ?;
811+ self . right . store ( store, options) ?;
812+ }
813+
814+ Ok ( ( ) )
815+ }
816+ }
817+
818+ impl < TreeId : Loadable > Loadable for Node < TreeId , Normal > {
819+ fn load ( id : Hash , store : & impl KeyValueStore ) -> Result < Self , OperationalError > {
820+ let StoredNode { meta, left, right } = {
821+ let bytes =
822+ store
823+ . blob_get ( id)
824+ . map_err ( |error| OperationalError :: CommitDataMissing {
825+ root : id,
826+ source : Box :: new ( error) ,
827+ } ) ?;
828+ deserialise ( bytes. as_ref ( ) ) ?
829+ } ;
830+
831+ let meta = Atom :: new ( meta) ;
832+
833+ // The stored representation does not include the `data` field, so we need to load it
834+ // separately from the KV store.
835+ let data = {
836+ let bytes = store. get ( meta. key . as_ref ( ) ) . map_err ( |error| {
837+ OperationalError :: CommitValueMissing {
838+ key : meta. key . clone ( ) ,
839+ source : Box :: new ( error) ,
840+ }
841+ } ) ?;
842+ Bytes :: from ( bytes. as_ref ( ) )
843+ } ;
844+
845+ let left = TreeId :: load ( left, store) ?;
846+ let right = TreeId :: load ( right, store) ?;
847+
848+ Ok ( Self {
849+ meta,
850+ data,
851+ left,
852+ right,
853+ hash : OnceLock :: new ( ) ,
854+ } )
855+ }
856+ }
857+
818858impl < F , TreeId , M > Foldable < F > for Node < TreeId , M >
819859where
820860 F : Fold ,
0 commit comments