@@ -33,24 +33,69 @@ module Make (Args : Gc_args.S) = struct
3333
3434 val make : unit -> t
3535 val add : off :int63 -> len :int -> t -> unit
36- val to_list : t -> (int63 * int ) list
3736 val count : t -> int
37+ val iter : (off :int63 -> len :int63 -> unit ) -> t -> unit
3838 end = struct
39- type t = { mutable ranges : (int63 * int ) list ; mutable count : int }
39+ module Stack = struct
40+ type t =
41+ | Empty
42+ | Stack of { mutable len : int ; arr : int63 array ; prev : t }
43+
44+ let capacity =
45+ 131_072 (* = 128*1024, a large but not too large chunk size *)
46+
47+ let make prev =
48+ Stack { len = 0 ; arr = Array. make capacity Int63. zero; prev }
49+
50+ let is_full = function Empty -> true | Stack s -> s.len > = capacity
51+
52+ let rec push_pair ~off ~len t =
53+ match t with
54+ | Stack s when not (is_full t) ->
55+ let i = s.len in
56+ s.len < - i + 2 ;
57+ s.arr.(i) < - off;
58+ s.arr.(i + 1 ) < - Int63. of_int len;
59+ t
60+ | _ -> push_pair ~off ~len (make t)
61+
62+ let rec iter_pair fn = function
63+ | Empty -> ()
64+ | Stack { len; arr; prev } ->
65+ assert (len mod 2 = 0 );
66+ for i = (len / 2 ) - 1 downto 0 do
67+ let off = arr.(2 * i) in
68+ let len = arr.((2 * i) + 1 ) in
69+ fn ~off ~len
70+ done ;
71+ iter_pair fn prev
72+ end
4073
41- let make () = { ranges = [] ; count = 0 }
42- let to_list t = t.ranges
43- let count t = t.count
74+ type t = {
75+ mutable last : (int63 * int ) option ;
76+ mutable ranges : Stack .t ;
77+ mutable count : int ;
78+ }
4479
45- let add_range ~off ~len lst =
46- let off_end = Int63. (Syntax. (off + of_int len)) in
47- match lst with
48- | (off' , len' ) :: rest when off_end = off' -> (off, len + len') :: rest
49- | _ -> (off, len) :: lst
80+ let make () = { last = None ; ranges = Stack. Empty ; count = 0 }
81+ let count t = t.count
5082
5183 let add ~off ~len t =
5284 t.count < - t.count + 1 ;
53- t.ranges < - add_range ~off ~len t.ranges
85+ let off_end = Int63. (Syntax. (off + of_int len)) in
86+ match t.last with
87+ | None -> t.last < - Some (off, len)
88+ | Some (off' , len' ) when off_end = off' -> t.last < - Some (off, len + len')
89+ | Some (off' , len' ) ->
90+ t.last < - Some (off, len);
91+ t.ranges < - Stack. push_pair ~off: off' ~len: len' t.ranges
92+
93+ let iter fn t =
94+ match t.last with
95+ | None -> assert (t.count = 0 )
96+ | Some (off , len ) ->
97+ fn ~off ~len: (Int63. of_int len);
98+ Stack. iter_pair fn t.ranges
5499 end
55100
56101 module Priority_queue = struct
@@ -278,7 +323,7 @@ module Make (Args : Gc_args.S) = struct
278323 Gc_stats.Worker. finish_current_step ! stats " mapping: of reachable" ;
279324 stats :=
280325 Gc_stats.Worker. set_objects_traversed ! stats (Live. count live_entries);
281- Live. to_list live_entries
326+ live_entries
282327 in
283328
284329 let () =
@@ -299,9 +344,8 @@ module Make (Args : Gc_args.S) = struct
299344 |> Errs. log_if_error " GC: Close prefix after data copy" )
300345 @@ fun () ->
301346 (* Step 5.1. Transfer all. *)
302- List. iter
303- (fun (off , len ) ->
304- let len = Int63. of_int len in
347+ Live. iter
348+ (fun ~off ~len ->
305349 let str = Dispatcher. read_seq_exn dispatcher ~off ~len in
306350 Sparse.Ao. append_seq_exn prefix ~off str)
307351 live_entries
@@ -399,16 +443,14 @@ module Make (Args : Gc_args.S) = struct
399443 stats :=
400444 Gc_stats.Worker. finish_current_step ! stats " archive: iter reachable" ;
401445 let min_offset = Dispatcher. suffix_start_offset dispatcher in
402- let to_archive =
403- traverse_range ~min_offset commit_key commit_store node_store
404- in
405- let to_archive =
406- List. map
407- (fun (off , len ) ->
408- let len = Int63. of_int len in
409- (off, Dispatcher. read_seq_exn dispatcher ~off ~len ))
410- (Live. to_list to_archive)
411- in
446+ let to_archive = ref [] in
447+ Live. iter
448+ (fun ~off ~len ->
449+ to_archive :=
450+ (off, Dispatcher. read_seq_exn dispatcher ~off ~len )
451+ :: ! to_archive)
452+ (traverse_range ~min_offset commit_key commit_store node_store);
453+ let to_archive = List. rev ! to_archive in
412454 stats :=
413455 Gc_stats.Worker. finish_current_step ! stats " archive: copy to lower" ;
414456 Lower. set_readonly lower false ;
0 commit comments