Skip to content

Commit 99ed169

Browse files
committed
Handle non-existent accounts in preload
Problem: account preloading is not able to preserve information about some accounts not existing inledger, which invites future repetetive lookups to DB during staged ledger application. Solution: keep a set of non-existent accounts for masks populated on preload.
1 parent 12dd166 commit 99ed169

File tree

1 file changed

+64
-55
lines changed

1 file changed

+64
-55
lines changed

src/lib/merkle_mask/masking_merkle_tree.ml

+64-55
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,21 @@ module Make (Inputs : Inputs_intf.S) = struct
3232
; token_owners : Account_id.t Token_id.Map.t
3333
; hashes : Hash.t Addr.Map.t
3434
; locations : Location.t Account_id.Map.t
35+
; non_existent_accounts : Account_id.Set.t
3536
}
3637
[@@deriving sexp]
3738

3839
(** Merges second maps object into the first one,
3940
potentially overwriting some keys *)
40-
let maps_merge base { accounts; token_owners; hashes; locations } =
41+
let maps_merge base
42+
{ accounts; token_owners; hashes; locations; non_existent_accounts } =
4143
let combine ~key:_ _ v = v in
4244
{ accounts = Map.merge_skewed ~combine base.accounts accounts
4345
; token_owners = Map.merge_skewed ~combine base.token_owners token_owners
4446
; hashes = Map.merge_skewed ~combine base.hashes hashes
4547
; locations = Map.merge_skewed ~combine base.locations locations
48+
; non_existent_accounts =
49+
Account_id.Set.union base.non_existent_accounts non_existent_accounts
4650
}
4751

4852
(** Structure managing cache accumulated since the "base" ledger.
@@ -94,11 +98,12 @@ module Make (Inputs : Inputs_intf.S) = struct
9498

9599
type unattached = t [@@deriving sexp]
96100

97-
let empty_maps () =
101+
let empty_maps =
98102
{ accounts = Location_binable.Map.empty
99103
; token_owners = Token_id.Map.empty
100104
; hashes = Addr.Map.empty
101105
; locations = Account_id.Map.empty
106+
; non_existent_accounts = Account_id.Set.empty
102107
}
103108

104109
let create ~depth () =
@@ -108,7 +113,7 @@ module Make (Inputs : Inputs_intf.S) = struct
108113
; current_location = None
109114
; depth
110115
; accumulated = None
111-
; maps = empty_maps ()
116+
; maps = empty_maps
112117
; is_committing = false
113118
}
114119

@@ -218,6 +223,8 @@ module Make (Inputs : Inputs_intf.S) = struct
218223
update_maps t ~f:(fun maps ->
219224
{ maps with
220225
locations = Map.set maps.locations ~key:account_id ~data:location
226+
; non_existent_accounts =
227+
Set.remove maps.non_existent_accounts account_id
221228
} ) ;
222229
(* if account is at a hitherto-unused location, that
223230
becomes the current location
@@ -274,34 +281,36 @@ module Make (Inputs : Inputs_intf.S) = struct
274281
| _ ->
275282
None )
276283
in
277-
let from_parent = lookup_parent ancestor not_found in
278-
List.fold_map self_found_or_none ~init:from_parent
279-
~f:(fun from_parent (id, self_found) ->
280-
match (self_found, from_parent) with
281-
| None, r :: rest ->
282-
(rest, r)
283-
| Some acc_found_locally, _ ->
284-
(from_parent, (id, acc_found_locally))
285-
| _ ->
286-
failwith "unexpected number of results from DB" )
287-
|> snd
284+
if List.is_empty not_found then
285+
List.map ~f:(fun (a, x) -> (a, Option.value_exn x)) self_found_or_none
286+
else
287+
let from_parent = lookup_parent ancestor not_found in
288+
List.fold_map self_found_or_none ~init:from_parent
289+
~f:(fun from_parent (id, self_found) ->
290+
match (self_found, from_parent) with
291+
| None, r :: rest ->
292+
(rest, r)
293+
| Some acc_found_locally, _ ->
294+
(from_parent, (id, acc_found_locally))
295+
| _ ->
296+
failwith "unexpected number of results from DB" )
297+
|> snd
288298

289299
let get_batch t =
290-
let self_find ~maps id =
291-
let res = Map.find maps.accounts id in
292-
let res =
293-
if Option.is_none res then
294-
let is_empty =
295-
Option.value_map ~default:true t.current_location
296-
~f:(fun current_location ->
297-
let address = Location.to_path_exn id in
298-
let current_address = Location.to_path_exn current_location in
299-
Addr.is_further_right ~than:current_address address )
300-
in
301-
Option.some_if is_empty None
302-
else Some res
303-
in
304-
(id, res)
300+
let is_empty loc =
301+
Option.value_map ~default:true t.current_location ~f:(fun cur_loc ->
302+
let cur_addr = Location.to_path_exn cur_loc in
303+
Addr.is_further_right ~than:cur_addr @@ Location.to_path_exn loc )
304+
in
305+
let self_find ~maps:{ accounts; _ } id =
306+
( id
307+
, match Map.find accounts id with
308+
| None when is_empty id ->
309+
Some None
310+
| None ->
311+
None
312+
| s ->
313+
Some s )
305314
in
306315
self_find_or_batch_lookup self_find Base.get_batch t
307316

@@ -621,12 +630,7 @@ module Make (Inputs : Inputs_intf.S) = struct
621630
let parent = get_parent t in
622631
let old_root_hash = merkle_root t in
623632
let account_data = Map.to_alist t.maps.accounts in
624-
t.maps <-
625-
{ accounts = Location_binable.Map.empty
626-
; hashes = Addr.Map.empty
627-
; token_owners = Token_id.Map.empty
628-
; locations = Account_id.Map.empty
629-
} ;
633+
t.maps <- empty_maps ;
630634
Base.set_batch parent account_data ;
631635
Debug_assert.debug_assert (fun () ->
632636
[%test_result: Hash.t]
@@ -784,21 +788,23 @@ module Make (Inputs : Inputs_intf.S) = struct
784788
failwith "Expected mask current location to represent an account"
785789
)
786790

791+
let self_lookup_account ~maps account_id =
792+
if Set.mem maps.non_existent_accounts account_id then Some None
793+
else Option.map ~f:Option.some @@ Map.find maps.locations account_id
794+
787795
let location_of_account t account_id =
788796
assert_is_attached t ;
789797
let maps, ancestor = maps_and_ancestor t in
790-
let mask_result = Map.find maps.locations account_id in
791-
match mask_result with
792-
| Some _ ->
793-
mask_result
798+
match self_lookup_account ~maps account_id with
799+
| Some r ->
800+
r
794801
| None ->
795802
Base.location_of_account ancestor account_id
796803

797-
let location_of_account_batch t =
804+
let location_of_account_batch =
798805
self_find_or_batch_lookup
799-
(fun ~maps id ->
800-
(id, Option.map ~f:Option.some @@ Map.find maps.locations id) )
801-
Base.location_of_account_batch t
806+
(fun ~maps id -> (id, self_lookup_account ~maps id))
807+
Base.location_of_account_batch
802808

803809
(* Adds specified accounts to the mask by laoding them from parent ledger.
804810
@@ -810,7 +816,19 @@ module Make (Inputs : Inputs_intf.S) = struct
810816
let unsafe_preload_accounts_from_parent t account_ids =
811817
assert_is_attached t ;
812818
let locations = location_of_account_batch t account_ids in
813-
let non_empty_locations = List.filter_map locations ~f:snd in
819+
let non_empty_locations, empty_keys =
820+
List.partition_map locations ~f:(function
821+
| _, Some loc ->
822+
First loc
823+
| key, None ->
824+
Second key )
825+
in
826+
update_maps t ~f:(fun maps ->
827+
{ maps with
828+
non_existent_accounts =
829+
Set.union maps.non_existent_accounts
830+
(Account_id.Set.of_list empty_keys)
831+
} ) ;
814832
let accounts = get_batch t non_empty_locations in
815833
let all_hash_locations =
816834
let rec generate_locations account_locations acc =
@@ -841,11 +859,7 @@ module Make (Inputs : Inputs_intf.S) = struct
841859
self_set_hash t address hash ) ;
842860
(* Batch import accounts. *)
843861
List.iter accounts ~f:(fun (location, account) ->
844-
match account with
845-
| None ->
846-
()
847-
| Some account ->
848-
set_account_unsafe t location account )
862+
Option.iter account ~f:(set_account_unsafe t location) )
849863

850864
(* not needed for in-memory mask; in the database, it's currently a NOP *)
851865
let get_inner_hash_at_addr_exn t address =
@@ -857,12 +871,7 @@ module Make (Inputs : Inputs_intf.S) = struct
857871
as sometimes this is desired behavior *)
858872
let close t =
859873
assert_is_attached t ;
860-
t.maps <-
861-
{ t.maps with
862-
accounts = Location_binable.Map.empty
863-
; hashes = Addr.Map.empty
864-
; locations = Account_id.Map.empty
865-
} ;
874+
t.maps <- empty_maps ;
866875
Async.Ivar.fill_if_empty t.detached_parent_signal ()
867876

868877
let index_of_account_exn t key =

0 commit comments

Comments
 (0)