Source file file_cache.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
module Make (Input : sig
type t
val read : string -> t
val cache_name : string
end) =
struct
let { Logger.log } =
Logger.for_section ("File_cache(" ^ Input.cache_name ^ ")")
let cache : (string, File_id.t * float ref * Input.t) Hashtbl.t =
Hashtbl.create 17
type cache_stats = { hit : int; miss : int }
let cache_hit = ref 0
let cache_miss = ref 0
let get_cache_stats () = { hit = !cache_hit; miss = !cache_miss }
let clear_cache_stats () =
cache_hit := 0;
cache_miss := 0
let get_cached_entry ~title fid filename =
let fid', latest_use, file = Hashtbl.find cache filename in
if File_id.check fid fid' then (
log ~title "reusing %S" filename;
cache_hit := !cache_hit + 1)
else (
log ~title "%S was updated on disk" filename;
raise Not_found);
latest_use := Unix.time ();
file
let read filename =
let fid = File_id.get filename in
let title = "read" in
try get_cached_entry ~title fid filename
with Not_found -> (
try
cache_miss := !cache_miss + 1;
log ~title "reading %S from disk" filename;
let file = Input.read filename in
Hashtbl.replace cache filename (fid, ref (Unix.time ()), file);
file
with exn ->
log ~title "failed to read %S (%t)" filename (fun () ->
Printexc.to_string exn);
Hashtbl.remove cache filename;
raise exn)
let check filename =
let fid = File_id.get filename in
match Hashtbl.find cache filename with
| exception Not_found -> false
| fid', latest_use, _ ->
if File_id.check fid fid' then begin
latest_use := Unix.time ();
true
end
else begin
false
end
let get_cached_entry filename =
let fid = File_id.get filename in
let title = "get_cached_entry" in
get_cached_entry ~title fid filename
let flush ?older_than () =
let title = "flush" in
let limit =
match older_than with
| None -> -.max_float
| Some dt -> Unix.time () -. dt
in
let add_invalid filename (fid, latest_use, _) invalids =
if !latest_use > limit && File_id.check (File_id.get filename) fid then (
log ~title "keeping %S" filename;
invalids)
else (
log ~title "removing %S" filename;
filename :: invalids)
in
let invalid = Hashtbl.fold add_invalid cache [] in
List.iter (Hashtbl.remove cache) invalid
let clear () = Hashtbl.clear cache
end