123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2022 Nomadic Labs, <contact@nomadic-labs.com> *)(* Copyright (c) 2022 Trili Tech, <contact@trili.tech> *)(* *)(* Permission is hereby granted, free of charge, to any person obtaining a *)(* copy of this software and associated documentation files (the "Software"),*)(* to deal in the Software without restriction, including without limitation *)(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)(* and/or sell copies of the Software, and to permit persons to whom the *)(* Software is furnished to do so, subject to the following conditions: *)(* *)(* The above copyright notice and this permission notice shall be included *)(* in all copies or substantial portions of the Software. *)(* *)(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)(* DEALINGS IN THE SOFTWARE. *)(* *)(*****************************************************************************)openStore_sigsletdecodeencodingencoded_value=letopenResult_syntaxinletres=Data_encoding.Binary.of_bytesencodingencoded_valueinResult.bind_errorres(fune->tzfail@@Store_errors.Decoding_errore)letencodeencodingvalue=letopenResult_syntaxinletres=Data_encoding.Binary.to_bytesencodingvalueinResult.bind_errorres(fune->tzfail@@Store_errors.Encoding_errore)moduleMake(B:BACKEND)=structtype'at='aB.tmoduleMake_map(S:STORAGE_INFO)(K:KEY)(V:VALUE)=structtypekey=K.keytype'astore='aB.ttypevalue=V.valueletpath=S.pathletmake_keykey=B.make_key_pathpath@@K.to_path_representationkeyletmemstorekey=B.memstore(make_keykey)letdecode_value=decodeV.encodingletencode_value=encodeV.encodingletgetstorekey=letopenLwt_result_syntaxinlet*e=B.getstore(make_keykey)inLwt.return@@decode_valueeletfindstorekey=letopenLwt_result_syntaxinlet*value=B.findstore(make_keykey)inLwt.return@@Option.map_edecode_valuevalueletfind_with_defaultstorekey~on_default=letopenLwt_result_syntaxinlet*value=findstorekeyinreturn@@Option.value_fvalue~default:on_defaultendmoduleMake_updatable_map(S:STORAGE_INFO)(K:KEY)(V:VALUE)=structincludeMake_map(S)(K)(V)letaddstorekeyvalue=letopenLwt_result_syntaxinlet*?encoded_value=encode_valuevalueinB.setstore(make_keykey)encoded_valueendmoduleMake_append_only_map(S:STORAGE_INFO)(K:KEY)(V:VALUE)=structincludeMake_map(S)(K)(V)letaddstorekeyvalue=letopenLwt_result_syntaxinlet*existing_value=findstorekeyinlet*?encoded_value=encode_valuevalueinmatchexisting_valuewith|None->B.setstore(make_keykey)encoded_value|Someexisting_value->let*?encoded_existing_value=encode_valueexisting_valuein(* To be robust to interruption in the middle of processes,
we accept to redo some work when we restart the node.
Hence, it is fine to insert twice the same value for a
given value. *)ifnot(Bytes.equalencoded_existing_valueencoded_value)thentzfail@@Store_errors.Cannot_overwrite_key_in_store{name=B.name;key=B.path_to_string@@make_keykey;old_value=String.of_bytesencoded_existing_value;new_value=String.of_bytesencoded_value;}elsereturn_unitendmoduleMake_mutable_value(S:STORAGE_INFO)(V:VALUE)=structtype'astore='aB.ttypevalue=V.valueletpath_key=S.pathletdecode_value=decodeV.encodingletencode_value=encodeV.encodingletsetstorevalue=letopenLwt_result_syntaxinlet*?encoded_value=encode_valuevalueinB.setstorepath_keyencoded_valueletgetstore=letopenLwt_result_syntaxinlet*value=B.getstorepath_keyinLwt.return@@decode_valuevalueletfindstore=letopenLwt_result_syntaxinlet*value=B.findstorepath_keyinLwt.return@@Option.map_edecode_valuevalueendmoduleMake_nested_map(S:STORAGE_INFO)(K1:KEY)(K2:COMPARABLE_KEY)(V:VALUE)=structtype'astore='aB.ttypeprimary_key=K1.keytypesecondary_key=K2.keytypevalue=V.valueletpath=S.pathmoduleSecondary_key_map=Map.Make(structtypet=K2.keyletcompare=K2.compareend)moduleMap_as_value=structtypevalue=V.valueSecondary_key_map.tletencoding=Data_encoding.conv(funmap->Secondary_key_map.bindingsmap)(funbindings->Secondary_key_map.of_seq@@List.to_seqbindings)Data_encoding.(list@@obj2(reqK2.nameK2.encoding)(reqV.nameV.encoding))letencode_value=encodeV.encodingletname=""endmoduleM=Make_updatable_map(S)(K1)(Map_as_value)(* Return the bindings associated with a primary key. *)letlist_secondary_keys_with_valuesstore~primary_key=letopenLwt_result_syntaxinlet+slots_map=M.findstoreprimary_keyinOption.fold~none:[]~some:Secondary_key_map.bindingsslots_map(* Check whether the updatable store contains an entry
for the primary_key, which itself contains a
binding whose key is ~secondary_key. *)letmemstore~primary_key~secondary_key=letopenLwt_result_syntaxinlet*primary_key_binding_exists=M.memstoreprimary_keyinifnotprimary_key_binding_existsthenreturn_falseelselet+secondary_key_map=M.getstoreprimary_keyinSecondary_key_map.memsecondary_keysecondary_key_map(* Unsafe call. The existence of a value for
primary and secondary key in the store must be
checked before invoking this function. *)letgetstore~primary_key~secondary_key=letopenLwt_result_syntaxinlet*secondary_key_map=M.getstoreprimary_keyinmatchSecondary_key_map.findsecondary_keysecondary_key_mapwith|None->letkey=K1.to_path_representationprimary_keyintzfail@@Store_errors.Cannot_read_key_from_store{name=B.name;key}|Somevalue->returnvalueletfindstore~primary_key~secondary_key=letopenLwt_result_syntaxinlet*binding_exists=memstore~primary_key~secondary_keyinifbinding_existsthenlet+value=getstore~primary_key~secondary_keyinSomevalueelsereturn_none(* Returns the set of keys from the bindings of
~primary_key in the store. *)letlist_secondary_keysstore~primary_key=letopenLwt_result_syntaxinlet+secondary_keys_with_values=list_secondary_keys_with_valuesstore~primary_keyinList.map(fun(key,_value)->key)secondary_keys_with_values(* Returns the set of values from the bindings of
~primary_key in the store. *)letlist_valuesstore~primary_key=letopenLwt_result_syntaxinlet+secondary_keys_with_values=list_secondary_keys_with_valuesstore~primary_keyinList.map(fun(_key,value)->value)secondary_keys_with_values(* Updates the entry of the updatable map with key ~primary_key
by adding to it a binding with key ~secondary_key and
value `value`.*)letaddstore~primary_key~secondary_keyvalue=letopenLwt_result_syntaxinlet*value_map=M.findstoreprimary_keyinletvalue_map=Option.value~default:Secondary_key_map.emptyvalue_mapinlet*?value_can_be_added,encoded_old_value,encoded_value=letopenResult_syntaxinlet*encoded_value=Map_as_value.encode_valuevalueinmatchSecondary_key_map.findsecondary_keyvalue_mapwith|None->return(true,None,encoded_value)|Someold_value->let*encoded_old_value=Map_as_value.encode_valueold_valueinreturn@@(Bytes.equalencoded_old_valueencoded_value,Someencoded_old_value,encoded_value)inifvalue_can_be_addedthenletupdated_map=Secondary_key_map.addsecondary_keyvaluevalue_mapinM.addstoreprimary_keyupdated_mapelseletkey=B.path_to_string@@B.make_key_pathS.path@@K1.to_path_representationprimary_keyinmatchencoded_old_valuewith|None->tzfail@@Store_errors.Cannot_write_key_value_pair_to_store{name=B.name;key;value=String.of_bytesencoded_value}|Someencoded_old_value->tzfail@@Store_errors.Cannot_overwrite_key_in_store{name=B.name;key;old_value=String.of_bytesencoded_old_value;new_value=String.of_bytesencoded_value;}endend