···153153154154 let compare = compare
155155end)
156156+157157+module Map = Map.Make (struct
158158+ type nonrec t = t
159159+160160+ let compare = compare
161161+end)
···11+module StringMap = Dag_cbor.StringMap
22+33+type node_raw =
44+ { (* link to lower level left subtree with all keys sorting before this node *)
55+ l: Cid.t option
66+ ; (* ordered list of entries below this node *)
77+ e: entry_raw list }
88+99+and entry_raw =
1010+ { (* length of prefix shared with previous path *)
1111+ p: int
1212+ ; (* remainder of path for this entry, after the first p characters *)
1313+ k: bytes
1414+ ; (* link to the CBOR record data for this entry *)
1515+ v: Cid.t
1616+ ; (* link to lower level right subtree with all keys sorting after this entry, but before the next entry *)
1717+ t: Cid.t option }
1818+1919+let encode_entry_raw entry : Dag_cbor.value =
2020+ `Map
2121+ (StringMap.of_list
2222+ [ ("p", `Integer (Int64.of_int entry.p))
2323+ ; ("k", `Bytes entry.k)
2424+ ; ("v", `Link entry.v)
2525+ ; ("t", match entry.t with Some t -> `Link t | None -> `Null) ] )
2626+2727+let encode_node_raw node : Dag_cbor.value =
2828+ `Map
2929+ (StringMap.of_list
3030+ [ ("l", match node.l with Some l -> `Link l | None -> `Null)
3131+ ; ("e", `Array (Array.of_list (List.map encode_entry_raw node.e))) ] )
3232+3333+type node_hydrated =
3434+ { layer: int
3535+ ; mutable left: node_hydrated option
3636+ ; mutable entries: entry_hydrated list }
3737+3838+and entry_hydrated =
3939+ {layer: int; key: string; value: Cid.t; right: node_hydrated option}
4040+4141+module Make (Store : Storage.Writable_blockstore) = struct
4242+ type bs = Store.t
4343+4444+ type t = {blockstore: bs; root: Cid.t}
4545+4646+ let create blockstore root = {blockstore; root}
4747+4848+ let decode_block b : node_raw =
4949+ match Dag_cbor.decode b with
5050+ | `Map node ->
5151+ if not (StringMap.mem "e" node) then
5252+ raise (Invalid_argument "mst node missing 'e'") ;
5353+ let l =
5454+ if StringMap.mem "l" node then
5555+ match StringMap.find "l" node with `Link l -> Some l | _ -> None
5656+ else None
5757+ in
5858+ let e_array =
5959+ match StringMap.find "e" node with `Array e -> e | _ -> [||]
6060+ in
6161+ let e =
6262+ Array.to_list
6363+ @@ Array.map
6464+ (fun (entry : Dag_cbor.value) ->
6565+ match entry with
6666+ | `Map entry ->
6767+ { p=
6868+ ( entry |> StringMap.find "p"
6969+ |> function
7070+ | `Integer p ->
7171+ Int64.to_int p
7272+ | _ ->
7373+ raise (Invalid_argument "mst entry missing 'p'") )
7474+ ; k=
7575+ ( entry |> StringMap.find "k"
7676+ |> function
7777+ | `Bytes k ->
7878+ k
7979+ | _ ->
8080+ raise (Invalid_argument "mst entry missing 'k'") )
8181+ ; v=
8282+ ( entry |> StringMap.find "v"
8383+ |> function
8484+ | `Link v ->
8585+ v
8686+ | _ ->
8787+ raise (Invalid_argument "mst entry missing 'v'") )
8888+ ; t=
8989+ ( entry |> StringMap.find "t"
9090+ |> function `Link t -> Some t | _ -> None ) }
9191+ | _ ->
9292+ raise (Invalid_argument "non-map mst entry") )
9393+ e_array
9494+ in
9595+ {l; e}
9696+ | _ ->
9797+ raise (Invalid_argument "invalid block")
9898+9999+ let retrieve_node t cid : node_raw option Lwt.t =
100100+ match%lwt Store.get_bytes t.blockstore cid with
101101+ | Some bytes ->
102102+ Lwt.return_some (decode_block bytes)
103103+ | None ->
104104+ Lwt.return_none
105105+106106+ let rec get_node_height t node : int Lwt.t =
107107+ match (node.l, node.e) with
108108+ | None, [] ->
109109+ Lwt.return 0
110110+ | Some left, [] -> (
111111+ match%lwt retrieve_node t left with
112112+ | Some node ->
113113+ let%lwt height = get_node_height t node in
114114+ Lwt.return (height + 1)
115115+ | None ->
116116+ failwith ("couldn't find node " ^ Cid.to_string left) )
117117+ | _, leaf :: _ -> (
118118+ match leaf.p with
119119+ | 0 ->
120120+ Lwt.return (Util.leading_zeros_on_hash (Bytes.to_string leaf.k))
121121+ | _ ->
122122+ failwith "first node entry has nonzero p value" )
123123+124124+ let traverse t fn : unit Lwt.t =
125125+ let rec traverse node =
126126+ let%lwt () =
127127+ match node.l with
128128+ | Some cid -> (
129129+ match%lwt retrieve_node t cid with
130130+ | Some node ->
131131+ traverse node
132132+ | None ->
133133+ Lwt.return_unit )
134134+ | None ->
135135+ Lwt.return_unit
136136+ in
137137+ ignore
138138+ (List.fold_left
139139+ (fun prev_path entry ->
140140+ let prefix = String.sub prev_path 0 entry.p in
141141+ let path = String.concat "" [prefix; Bytes.to_string entry.k] in
142142+ fn path entry.v ; path )
143143+ "" node.e ) ;
144144+ Lwt.return_unit
145145+ in
146146+ match%lwt retrieve_node t t.root with
147147+ | Some root ->
148148+ traverse root
149149+ | None ->
150150+ failwith "root cid not found in repo store"
151151+152152+ let build_map t : Cid.t StringMap.t Lwt.t =
153153+ let map = StringMap.empty in
154154+ let%lwt () =
155155+ traverse t (fun path cid -> ignore (StringMap.add path cid map))
156156+ in
157157+ Lwt.return map
158158+159159+ let rec insert_entry node entry : node_hydrated Lwt.t =
160160+ let entry_layer = Util.leading_zeros_on_hash entry.key in
161161+ (* as long as node layer <= entry layer, create a new node above node
162162+ until we have a node at the correct height for the entry to be inserted *)
163163+ let rec build_insert_node node layer =
164164+ if layer >= entry_layer then node
165165+ else
166166+ build_insert_node
167167+ {layer= layer + 1; left= Some node; entries= []}
168168+ (layer + 1)
169169+ in
170170+ let insert_node = build_insert_node node node.layer in
171171+ (* if entry is below node, recursively insert into node's left subtree *)
172172+ if entry_layer < insert_node.layer then
173173+ match (insert_node.entries, insert_node.left) with
174174+ | [], None ->
175175+ failwith "found totally empty mst node"
176176+ | [], Some left ->
177177+ node.left <- Some (Lwt_main.run (insert_entry left entry)) ;
178178+ Lwt.return insert_node
179179+ | _ ->
180180+ Lwt.return insert_node
181181+ else (
182182+ (* if entry is at this node's layer, append it to node's entries,
183183+ checking that its key occurs after the last existing entry *)
184184+ assert (node.layer = entry_layer) ;
185185+ if List.length node.entries > 0 then
186186+ assert (entry.key > (List.rev node.entries |> List.hd).key) ;
187187+ node.entries <- node.entries @ [entry] ;
188188+ Lwt.return node )
189189+190190+ let hydrate_from_map t map =
191191+ let keys =
192192+ map |> StringMap.bindings |> List.map fst |> List.sort String.compare
193193+ in
194194+ let entry_for_key key =
195195+ let value = StringMap.find key map in
196196+ let height = Util.leading_zeros_on_hash key in
197197+ {layer= height; key; value; right= None}
198198+ in
199199+ let root =
200200+ { layer= keys |> List.hd |> Util.leading_zeros_on_hash
201201+ ; entries= []
202202+ ; left= None }
203203+ in
204204+ List.iter
205205+ (fun key -> ignore (insert_entry root (entry_for_key key)))
206206+ (List.tl keys) ;
207207+ let rec finalize node : Cid.t Lwt.t =
208208+ let left =
209209+ match node.left with
210210+ | Some l ->
211211+ Some (Lwt_main.run (finalize l))
212212+ | None ->
213213+ None
214214+ in
215215+ let last_key = ref "" in
216216+ let mst_entries =
217217+ List.map
218218+ (fun entry ->
219219+ let right =
220220+ match entry.right with
221221+ | Some r ->
222222+ Some (Lwt_main.run (finalize r))
223223+ | None ->
224224+ None
225225+ in
226226+ let prefix_len = Util.shared_prefix_length !last_key entry.key in
227227+ last_key := entry.key ;
228228+ { k=
229229+ Bytes.of_string
230230+ (String.sub entry.key prefix_len
231231+ (String.length entry.key - prefix_len) )
232232+ ; p= prefix_len
233233+ ; v= entry.value
234234+ ; t= right } )
235235+ node.entries
236236+ in
237237+ let mst_node = {l= left; e= mst_entries} in
238238+ let encoded = Dag_cbor.encode (encode_node_raw mst_node) in
239239+ let cid = Cid.create Dcbor encoded in
240240+ let%lwt () = Store.put_block t.blockstore cid encoded in
241241+ Lwt.return cid
242242+ in
243243+ finalize root
244244+end
+4-4
mist/lib/storage/memory_store.ml
···12121313 let get_blocks s cids = Lwt.return (Block_map.get_many cids s.blocks)
14141515- let put_block s cid bytes ~rev =
1515+ let put_block s ?rev cid bytes =
1616 s.blocks <- Block_map.set cid bytes s.blocks ;
1717- s.rev <- Some rev ;
1717+ s.rev <- rev ;
1818 Lwt.return_unit
19192020 let put_many s blocks =
2121 s.blocks <- Block_map.merge s.blocks blocks ;
2222 Lwt.return_unit
23232424- let update_root s cid ~rev =
2424+ let update_root s ?rev cid =
2525 s.root <- Some cid ;
2626- s.rev <- Some rev ;
2626+ s.rev <- rev ;
2727 Lwt.return_unit
28282929 let apply_commit s (c : Repo_store.commit_data) =
+2-2
mist/lib/storage/repo_store.ml
···21212222 include Readable with type t := t
23232424- val put_block : t -> Cid.t -> bytes -> rev:string -> unit Lwt.t
2424+ val put_block : t -> ?rev:string -> Cid.t -> bytes -> unit Lwt.t
25252626 val put_many : t -> Block_map.t -> unit Lwt.t
27272828- val update_root : t -> Cid.t -> rev:string -> unit Lwt.t
2828+ val update_root : t -> ?rev:string -> Cid.t -> unit Lwt.t
29293030 val apply_commit : t -> commit_data -> unit Lwt.t
3131end