Skip to content

Commit 7393117

Browse files
committed
perf: store serialized nodes as arrays, not lists
Signed-off-by: Tienson Qin <tiensonqin@gmail.com>
1 parent df53f5d commit 7393117

5 files changed

Lines changed: 121 additions & 141 deletions

File tree

‎bench/bench_pss.ml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,12 @@ let restored_10k =
137137
let restored_wide_4096 =
138138
lazy
139139
(let memory = Hashtbl.create 4097 in
140-
let keys = Array.to_list (Array.init 4_096 Fun.id) in
140+
let keys = Array.init 4_096 Fun.id in
141141
let child_addresses =
142-
List.map
142+
Array.map
143143
(fun value ->
144144
let address = "leaf-" ^ string_of_int value in
145-
Hashtbl.add memory address (Leaf [ value ]);
145+
Hashtbl.add memory address (Leaf [| value |]);
146146
address)
147147
keys
148148
in

‎lib/persistent_sorted_set.ml‎

Lines changed: 64 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
type 'a comparator = 'a -> 'a -> int
22
type ref_type = Strong | Weak
33
type settings = { branching_factor : int; ref_type : ref_type }
4-
type 'a stored_node = Leaf of 'a list | Branch of 'a list * string list
4+
type 'a stored_node = Leaf of 'a array | Branch of 'a array * string array
55

66
type 'a storage = {
77
store_node : 'a stored_node -> string;
@@ -167,26 +167,25 @@ let fold_array_prefix f init values len =
167167
done;
168168
!acc
169169

170-
let prepend_list values init =
171-
List.fold_right (fun value acc -> value :: acc) values init
172-
173170
let storage_required = function
174171
| Some storage -> storage
175172
| None -> invalid_arg "storage-backed node requires storage"
176173

177174
let rec materialize_address_with storage address tail =
178175
match storage.restore_node address with
179-
| Some (Leaf values) -> prepend_list values (tail ())
176+
| Some (Leaf values) -> prepend_array_prefix values (Array.length values) (tail ())
180177
| Some (Branch (_, child_addresses)) ->
181178
materialize_addresses_with storage child_addresses tail
182179
| None -> invalid_arg ("stored node not found: " ^ address)
183180

184181
and materialize_addresses_with storage addresses tail =
185-
match addresses with
186-
| [] -> tail ()
187-
| address :: rest ->
188-
materialize_address_with storage address (fun () ->
189-
materialize_addresses_with storage rest tail)
182+
let rec loop index =
183+
if index >= Array.length addresses then tail ()
184+
else
185+
materialize_address_with storage addresses.(index) (fun () ->
186+
loop (index + 1))
187+
in
188+
loop 0
190189

191190
let materialize_address storage address =
192191
materialize_address_with storage address (fun () -> [])
@@ -491,10 +490,8 @@ let find_child_index key_cmp value keys =
491490
if !best < 0 then length - 1 else !best
492491

493492
let node_of_stored_branch keys child_addresses address =
494-
if List.length keys <> List.length child_addresses then
493+
if Array.length keys <> Array.length child_addresses then
495494
invalid_arg "branch keys and addresses arity mismatch";
496-
let keys = Array.of_list keys in
497-
let child_addresses = Array.of_list child_addresses in
498495
let children =
499496
Array.mapi
500497
(fun index child_address ->
@@ -507,7 +504,6 @@ let node_of_stored_branch keys child_addresses address =
507504
let node_of_stored_node storage address =
508505
match restore_stored_node storage address with
509506
| Leaf values ->
510-
let values = Array.of_list values in
511507
Node.Leaf { values; len = Array.length values; address = Some address }
512508
| Branch (keys, child_addresses) ->
513509
node_of_stored_branch keys child_addresses address
@@ -723,8 +719,8 @@ let rec add_to_address storage settings order_cmp equality_cmp key_cmp value
723719
add_to_node (Some storage) settings order_cmp equality_cmp key_cmp value
724720
(Node.Leaf
725721
{
726-
values = Array.of_list values;
727-
len = List.length values;
722+
values;
723+
len = Array.length values;
728724
address = Some address;
729725
})
730726
| Branch (keys, child_addresses) ->
@@ -764,8 +760,8 @@ let rec remove_from_address storage settings order_cmp equality_cmp key_cmp
764760
value
765761
(Node.Leaf
766762
{
767-
values = Array.of_list values;
768-
len = List.length values;
763+
values;
764+
len = Array.length values;
769765
address = Some address;
770766
})
771767
| Branch (keys, child_addresses) ->
@@ -1079,18 +1075,15 @@ type search_step = Found | Stop | Continue
10791075
let rec search_deferred storage order_cmp equality_cmp value address =
10801076
match storage.restore_node address with
10811077
| Some (Leaf values) ->
1082-
let values = Array.of_list values in
10831078
let cmp = total_cmp order_cmp equality_cmp in
10841079
if array_mem_by_cmp cmp value values then Found
10851080
else
10861081
let length = Array.length values in
10871082
if length > 0 && order_cmp value values.(length - 1) <= 0 then Stop
10881083
else Continue
10891084
| Some (Branch (keys, child_addresses)) -> (
1090-
if List.length keys <> List.length child_addresses then
1085+
if Array.length keys <> Array.length child_addresses then
10911086
invalid_arg "branch keys and addresses arity mismatch";
1092-
let keys = Array.of_list keys in
1093-
let child_addresses = Array.of_list child_addresses in
10941087
let key_cmp = route_cmp order_cmp equality_cmp in
10951088
let child_address =
10961089
let length = Array.length keys in
@@ -1136,9 +1129,9 @@ let mem value set =
11361129

11371130
let rec fold_address storage f init address =
11381131
match storage.restore_node address with
1139-
| Some (Leaf values) -> List.fold_left f init values
1132+
| Some (Leaf values) -> Array.fold_left f init values
11401133
| Some (Branch (_, child_addresses)) ->
1141-
List.fold_left
1134+
Array.fold_left
11421135
(fun acc child_address -> fold_address storage f acc child_address)
11431136
init child_addresses
11441137
| None -> invalid_arg ("stored node not found: " ^ address)
@@ -1190,20 +1183,6 @@ let child_after_range cmp to_ previous_child_max =
11901183
| Some to_, Some previous_child_max -> cmp previous_child_max to_ > 0
11911184
| _ -> false
11921185

1193-
let slice_values cmp from_ to_ values =
1194-
values
1195-
|> List.filter (fun value ->
1196-
lower_ok cmp from_ value && upper_ok cmp to_ value)
1197-
1198-
let reverse_slice_values cmp from_ to_ values =
1199-
values |> List.rev
1200-
|> List.filter (fun value ->
1201-
match (from_, to_) with
1202-
| None, None -> true
1203-
| Some from_, None -> cmp value from_ <= 0
1204-
| None, Some to_ -> cmp value to_ >= 0
1205-
| Some from_, Some to_ -> cmp value from_ <= 0 && cmp value to_ >= 0)
1206-
12071186
let slice_array_into_len cmp from_ to_ values len acc =
12081187
let rec loop acc index =
12091188
if index >= len then acc
@@ -1238,23 +1217,23 @@ let reverse_slice_array_into_len cmp from_ to_ values len acc =
12381217
let rec slice_deferred_into storage cmp from_ to_ address acc =
12391218
match storage.restore_node address with
12401219
| Some (Leaf values) ->
1241-
List.rev_append (slice_values cmp from_ to_ values) acc
1220+
slice_array_into_len cmp from_ to_ values (Array.length values) acc
12421221
| Some (Branch (keys, child_addresses)) ->
1243-
let rec collect previous_key acc keys child_addresses =
1244-
match (keys, child_addresses) with
1245-
| [], [] -> acc
1246-
| key :: keys, child_address :: child_addresses ->
1247-
if child_after_range cmp to_ previous_key then acc
1248-
else if child_before_range cmp from_ key then
1249-
collect (Some key) acc keys child_addresses
1250-
else
1251-
collect (Some key)
1252-
(slice_deferred_into storage cmp from_ to_ child_address acc)
1253-
keys child_addresses
1254-
| [], _ :: _ | _ :: _, [] ->
1255-
invalid_arg "branch keys and addresses arity mismatch"
1222+
if Array.length keys <> Array.length child_addresses then
1223+
invalid_arg "branch keys and addresses arity mismatch";
1224+
let rec collect index previous_key acc =
1225+
if index >= Array.length keys then acc
1226+
else
1227+
let key = keys.(index) in
1228+
let child_address = child_addresses.(index) in
1229+
if child_after_range cmp to_ previous_key then acc
1230+
else if child_before_range cmp from_ key then
1231+
collect (index + 1) (Some key) acc
1232+
else
1233+
collect (index + 1) (Some key)
1234+
(slice_deferred_into storage cmp from_ to_ child_address acc)
12561235
in
1257-
collect None acc keys child_addresses
1236+
collect 0 None acc
12581237
| None -> invalid_arg ("stored node not found: " ^ address)
12591238

12601239
let slice_deferred storage cmp from_ to_ address =
@@ -1263,30 +1242,31 @@ let slice_deferred storage cmp from_ to_ address =
12631242
let rec reverse_slice_deferred_into storage cmp from_ to_ address acc =
12641243
match storage.restore_node address with
12651244
| Some (Leaf values) ->
1266-
List.rev_append (reverse_slice_values cmp from_ to_ values) acc
1245+
reverse_slice_array_into_len cmp from_ to_ values (Array.length values)
1246+
acc
12671247
| Some (Branch (keys, child_addresses)) ->
1268-
let rec collect previous_key keys child_addresses acc =
1269-
match (keys, child_addresses) with
1270-
| [], [] -> acc
1271-
| key :: keys, child_address :: child_addresses ->
1272-
let acc = collect (Some key) keys child_addresses acc in
1273-
let child_above_range =
1274-
match (from_, previous_key) with
1275-
| Some from_, Some previous_key -> cmp previous_key from_ > 0
1276-
| _ -> false
1277-
in
1278-
let child_below_range =
1279-
match to_ with Some to_ -> cmp key to_ < 0 | None -> false
1280-
in
1281-
if child_above_range then acc
1282-
else if child_below_range then acc
1283-
else
1284-
reverse_slice_deferred_into storage cmp from_ to_ child_address
1285-
acc
1286-
| [], _ :: _ | _ :: _, [] ->
1287-
invalid_arg "branch keys and addresses arity mismatch"
1248+
if Array.length keys <> Array.length child_addresses then
1249+
invalid_arg "branch keys and addresses arity mismatch";
1250+
let rec collect index previous_key acc =
1251+
if index >= Array.length keys then acc
1252+
else
1253+
let key = keys.(index) in
1254+
let child_address = child_addresses.(index) in
1255+
let acc = collect (index + 1) (Some key) acc in
1256+
let child_above_range =
1257+
match (from_, previous_key) with
1258+
| Some from_, Some previous_key -> cmp previous_key from_ > 0
1259+
| _ -> false
1260+
in
1261+
let child_below_range =
1262+
match to_ with Some to_ -> cmp key to_ < 0 | None -> false
1263+
in
1264+
if child_above_range then acc
1265+
else if child_below_range then acc
1266+
else
1267+
reverse_slice_deferred_into storage cmp from_ to_ child_address acc
12881268
in
1289-
collect None keys child_addresses acc
1269+
collect 0 None acc
12901270
| None -> invalid_arg ("stored node not found: " ^ address)
12911271

12921272
let reverse_slice_deferred storage cmp from_ to_ address =
@@ -1443,21 +1423,17 @@ let upper_bound_index_len cmp upper values length =
14431423
!low - 1
14441424

14451425
let cursor_children_of_addresses keys child_addresses =
1446-
if List.length keys <> List.length child_addresses then
1426+
if Array.length keys <> Array.length child_addresses then
14471427
invalid_arg "branch keys and addresses arity mismatch";
1448-
( Array.of_list keys,
1449-
child_addresses
1450-
|> List.map (fun address -> Cursor_address address)
1451-
|> Array.of_list )
1428+
( keys,
1429+
Array.map (fun address -> Cursor_address address) child_addresses )
14521430

14531431
let cursor_children_of_nodes children =
14541432
Array.map (fun child -> Cursor_node child) children
14551433

14561434
let restore_cursor_child storage address =
14571435
match storage.restore_node address with
1458-
| Some (Leaf values) ->
1459-
let values = Array.of_list values in
1460-
`Leaf (values, Array.length values)
1436+
| Some (Leaf values) -> `Leaf (values, Array.length values)
14611437
| Some (Branch (keys, child_addresses)) ->
14621438
let keys, children = cursor_children_of_addresses keys child_addresses in
14631439
`Branch (keys, children)
@@ -1815,7 +1791,9 @@ let seek key (seq : 'a seq) =
18151791
in
18161792
{ seq with lower; upper }
18171793

1818-
let split_branch_refs refs = List.split refs
1794+
let split_branch_refs refs =
1795+
let keys, child_addresses = List.split refs in
1796+
(Array.of_list keys, Array.of_list child_addresses)
18191797

18201798
let branch_key refs =
18211799
match last refs with
@@ -1847,9 +1825,7 @@ let rec store_node_tree storage settings = function
18471825
| Node.Ref { address; _ } -> (address, [ address ])
18481826
| Node.Leaf { address = Some address; _ } -> (address, [ address ])
18491827
| Node.Leaf { values; len; address = None; _ } ->
1850-
let address =
1851-
storage.store_node (Leaf (array_prefix_to_list values len))
1852-
in
1828+
let address = storage.store_node (Leaf (Array.sub values 0 len)) in
18531829
(address, [ address ])
18541830
| Node.Branch { address = Some address; _ } -> (address, [ address ])
18551831
| Node.Branch { keys; children; address = None; _ } ->
@@ -1886,7 +1862,7 @@ let store set =
18861862
let address, _addresses = store_node_tree storage set.set_settings root in
18871863
(address, stored_set address)
18881864
| Empty ->
1889-
let address = storage.store_node (Leaf []) in
1865+
let address = storage.store_node (Leaf [||]) in
18901866
(address, stored_set address)
18911867

18921868
let restore ?count ?(cmp = default_cmp) ?(settings = default_settings) storage

‎lib/persistent_sorted_set.mli‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
type 'a comparator = 'a -> 'a -> int
22
type ref_type = Strong | Weak
33
type settings = { branching_factor : int; ref_type : ref_type }
4-
type 'a stored_node = Leaf of 'a list | Branch of 'a list * string list
4+
type 'a stored_node = Leaf of 'a array | Branch of 'a array * string array
55

66
type 'a storage = {
77
store_node : 'a stored_node -> string;

‎test/js_memory_test.ml‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ let irange from_ to_ =
3030
loop [] to_
3131

3232
let copy_stored_node = function
33-
| Leaf values -> Leaf values
34-
| Branch (keys, child_addresses) -> Branch (keys, child_addresses)
33+
| Leaf values -> Leaf (Array.copy values)
34+
| Branch (keys, child_addresses) ->
35+
Branch (Array.copy keys, Array.copy child_addresses)
3536

3637
let set_timeout f milliseconds =
3738
ignore

0 commit comments

Comments
 (0)