Skip to content

Commit d341b28

Browse files
committed
Disk Cache: design an API to disable GC collection
1 parent 19872b9 commit d341b28

File tree

4 files changed

+27
-15
lines changed

4 files changed

+27
-15
lines changed

src/lib/disk_cache/filesystem/disk_cache.ml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,39 @@ module Make (B : sig
1010
include Binable.S
1111
end) =
1212
struct
13-
type t = string * int ref
13+
type t = { root : string; next_idx : int ref; gc_freezed : bool ref }
1414

1515
type id = { idx : int }
1616

1717
let initialize path ~logger =
1818
Async.Deferred.Result.map (Disk_cache_utils.initialize_dir path ~logger)
19-
~f:(fun path -> (path, ref 0))
19+
~f:(fun root -> { root; next_idx = ref 0; gc_freezed = ref false })
2020

2121
let path root i = root ^ Filename.dir_sep ^ Int.to_string i
2222

23-
let get ((root, _) : t) (id : id) : B.t =
23+
let get ({ root; _ } : t) (id : id) : B.t =
2424
(* Read from the file. *)
2525
In_channel.with_file ~binary:true (path root id.idx) ~f:(fun chan ->
2626
let str = In_channel.input_all chan in
2727
Binable.of_string (module B) str )
2828

29-
let put ((root, next_idx) : t) x : id =
29+
let freeze_gc { gc_freezed; _ } = gc_freezed := true
30+
31+
let put ({ root; next_idx; gc_freezed } : t) x : id =
3032
let idx = !next_idx in
3133
incr next_idx ;
3234
let res = { idx } in
3335
(* When this reference is GC'd, delete the file. *)
3436
Core.Gc.Expert.add_finalizer_last_exn res (fun () ->
35-
(* Ignore errors: if a directory is deleted, it's ok. *)
36-
try Core.Unix.unlink (path root idx) with _ -> () ) ;
37+
if not !gc_freezed then
38+
(* Ignore errors: if a directory is deleted, it's ok. *)
39+
try Core.Unix.unlink (path root idx) with _ -> () ) ;
3740
(* Write the proof to the file. *)
3841
Out_channel.with_file ~binary:true (path root idx) ~f:(fun chan ->
3942
Out_channel.output_string chan @@ Binable.to_string (module B) x ) ;
4043
res
4144

42-
let count ((path, _) : t) = Sys.ls_dir path |> List.length
45+
let count ({ root; _ } : t) = Sys.ls_dir root |> List.length
4346
end
4447

4548
let%test_module "disk_cache filesystem" =

src/lib/disk_cache/identity/disk_cache.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ struct
1414
let get () = ident
1515

1616
let put () = ident
17+
18+
let freeze_gc () = ()
1719
end

src/lib/disk_cache/intf/disk_cache_intf.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ module type S = sig
1919

2020
(** Read from the cache, crashing if the value cannot be found. *)
2121
val get : t -> id -> Data.t
22+
23+
val freeze_gc : t -> unit
2224
end
2325

2426
module type S_with_count = sig

src/lib/disk_cache/lmdb/disk_cache.ml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module Make (Data : Binable.S) = struct
2424
(** A list of ids that are no longer reachable from OCaml runtime, but
2525
haven't been cleared inside the LMDB disk cache *)
2626
; queue_guard : Error_checking_mutex.t
27+
; gc_freezed : bool ref
2728
}
2829

2930
(** How big can the queue [reusable_keys] be before we do a cleanup *)
@@ -38,15 +39,16 @@ module Make (Data : Binable.S) = struct
3839
; counter = ref 0
3940
; reusable_keys = Queue.create ()
4041
; queue_guard = Error_checking_mutex.create ()
42+
; gc_freezed = ref false
4143
} )
4244

4345
type id = { idx : int }
4446

4547
let get ({ env; db; _ } : t) ({ idx } : id) : Data.t =
4648
Rw.get ~env db idx |> Option.value_exn
4749

48-
let put ({ env; db; counter; reusable_keys; queue_guard } : t) (x : Data.t) :
49-
id =
50+
let put ({ env; db; counter; reusable_keys; queue_guard; gc_freezed } : t)
51+
(x : Data.t) : id =
5052
let idx =
5153
match
5254
Error_checking_mutex.critical_section queue_guard ~f:(fun () ->
@@ -63,12 +65,13 @@ module Make (Data : Binable.S) = struct
6365
let res = { idx } in
6466
(* When this reference is GC'd, delete the file. *)
6567
Gc.Expert.add_finalizer_last_exn res (fun () ->
66-
(* The actual deletion is delayed, as GC maybe triggered in LMDB's
67-
critical section. LMDB critical section then will be re-entered if
68-
it's invoked directly in a GC hook.
69-
This causes mutex double-acquiring and node freezes. *)
70-
Error_checking_mutex.critical_section queue_guard ~f:(fun () ->
71-
Queue.enqueue reusable_keys idx ) ) ;
68+
if not !gc_freezed then
69+
(* The actual deletion is delayed, as GC maybe triggered in LMDB's
70+
critical section. LMDB critical section then will be re-entered if
71+
it's invoked directly in a GC hook.
72+
This causes mutex double-acquiring and node freezes. *)
73+
Error_checking_mutex.critical_section queue_guard ~f:(fun () ->
74+
Queue.enqueue reusable_keys idx ) ) ;
7275

7376
Error_checking_mutex.critical_section queue_guard ~f:(fun () ->
7477
if Queue.length reusable_keys >= reuse_size_limit then (
@@ -77,6 +80,8 @@ module Make (Data : Binable.S) = struct
7780
Rw.set ~env db idx x ;
7881
res
7982

83+
let freeze_gc ({ gc_freezed; _ } : t) = gc_freezed := true
84+
8085
let iteri ({ env; db; _ } : t) ~f = Rw.iter ~env db ~f
8186

8287
let count ({ env; db; _ } : t) =

0 commit comments

Comments
 (0)