@@ -32,17 +32,21 @@ module Make (Inputs : Inputs_intf.S) = struct
32
32
; token_owners : Account_id .t Token_id.Map .t
33
33
; hashes : Hash .t Addr.Map .t
34
34
; locations : Location .t Account_id.Map .t
35
+ ; non_existent_accounts : Account_id.Set .t
35
36
}
36
37
[@@ deriving sexp ]
37
38
38
39
(* * Merges second maps object into the first one,
39
40
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 } =
41
43
let combine ~key :_ _ v = v in
42
44
{ accounts = Map. merge_skewed ~combine base.accounts accounts
43
45
; token_owners = Map. merge_skewed ~combine base.token_owners token_owners
44
46
; hashes = Map. merge_skewed ~combine base.hashes hashes
45
47
; locations = Map. merge_skewed ~combine base.locations locations
48
+ ; non_existent_accounts =
49
+ Account_id.Set. union base.non_existent_accounts non_existent_accounts
46
50
}
47
51
48
52
(* * Structure managing cache accumulated since the "base" ledger.
@@ -94,11 +98,12 @@ module Make (Inputs : Inputs_intf.S) = struct
94
98
95
99
type unattached = t [@@ deriving sexp ]
96
100
97
- let empty_maps () =
101
+ let empty_maps =
98
102
{ accounts = Location_binable.Map. empty
99
103
; token_owners = Token_id.Map. empty
100
104
; hashes = Addr.Map. empty
101
105
; locations = Account_id.Map. empty
106
+ ; non_existent_accounts = Account_id.Set. empty
102
107
}
103
108
104
109
let create ~depth () =
@@ -108,7 +113,7 @@ module Make (Inputs : Inputs_intf.S) = struct
108
113
; current_location = None
109
114
; depth
110
115
; accumulated = None
111
- ; maps = empty_maps ()
116
+ ; maps = empty_maps
112
117
; is_committing = false
113
118
}
114
119
@@ -218,6 +223,8 @@ module Make (Inputs : Inputs_intf.S) = struct
218
223
update_maps t ~f: (fun maps ->
219
224
{ maps with
220
225
locations = Map. set maps.locations ~key: account_id ~data: location
226
+ ; non_existent_accounts =
227
+ Set. remove maps.non_existent_accounts account_id
221
228
} ) ;
222
229
(* if account is at a hitherto-unused location, that
223
230
becomes the current location
@@ -274,34 +281,36 @@ module Make (Inputs : Inputs_intf.S) = struct
274
281
| _ ->
275
282
None )
276
283
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
288
298
289
299
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 )
305
314
in
306
315
self_find_or_batch_lookup self_find Base. get_batch t
307
316
@@ -621,12 +630,7 @@ module Make (Inputs : Inputs_intf.S) = struct
621
630
let parent = get_parent t in
622
631
let old_root_hash = merkle_root t in
623
632
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 ;
630
634
Base. set_batch parent account_data ;
631
635
Debug_assert. debug_assert (fun () ->
632
636
[% test_result: Hash. t]
@@ -784,21 +788,23 @@ module Make (Inputs : Inputs_intf.S) = struct
784
788
failwith " Expected mask current location to represent an account"
785
789
)
786
790
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
+
787
795
let location_of_account t account_id =
788
796
assert_is_attached t ;
789
797
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
794
801
| None ->
795
802
Base. location_of_account ancestor account_id
796
803
797
- let location_of_account_batch t =
804
+ let location_of_account_batch =
798
805
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
802
808
803
809
(* Adds specified accounts to the mask by laoding them from parent ledger.
804
810
@@ -810,7 +816,19 @@ module Make (Inputs : Inputs_intf.S) = struct
810
816
let unsafe_preload_accounts_from_parent t account_ids =
811
817
assert_is_attached t ;
812
818
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
+ } ) ;
814
832
let accounts = get_batch t non_empty_locations in
815
833
let all_hash_locations =
816
834
let rec generate_locations account_locations acc =
@@ -841,11 +859,7 @@ module Make (Inputs : Inputs_intf.S) = struct
841
859
self_set_hash t address hash ) ;
842
860
(* Batch import accounts. *)
843
861
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) )
849
863
850
864
(* not needed for in-memory mask; in the database, it's currently a NOP *)
851
865
let get_inner_hash_at_addr_exn t address =
@@ -857,12 +871,7 @@ module Make (Inputs : Inputs_intf.S) = struct
857
871
as sometimes this is desired behavior *)
858
872
let close t =
859
873
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 ;
866
875
Async.Ivar. fill_if_empty t.detached_parent_signal ()
867
876
868
877
let index_of_account_exn t key =
0 commit comments