|
|
|
@ -14,16 +14,24 @@ module L = Logging
|
|
|
|
|
module F = Format
|
|
|
|
|
|
|
|
|
|
(** Generic serializer *)
|
|
|
|
|
type 'a serializer = (string -> 'a option) * (DB.filename -> 'a option) * (DB.filename -> 'a -> unit)
|
|
|
|
|
type 'a serializer =
|
|
|
|
|
{
|
|
|
|
|
read_from_string: (string -> 'a option);
|
|
|
|
|
read_from_file: (DB.filename -> 'a option);
|
|
|
|
|
write_to_file: (DB.filename -> 'a -> unit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(** Serialization key, used to distinguish versions of serializers and avoid assert faults *)
|
|
|
|
|
type key = int
|
|
|
|
|
module Key = struct
|
|
|
|
|
|
|
|
|
|
(** current key for tenv, procedure summary, cfg, error trace, call graph *)
|
|
|
|
|
let tenv_key, summary_key, cfg_key, trace_key, cg_key,
|
|
|
|
|
analysis_results_key, cluster_key, attributes_key, lint_issues_key =
|
|
|
|
|
425184201, 160179325, 1062389858, 221487792, 477305409,
|
|
|
|
|
799050016, 579094948, 972393003, 852343110
|
|
|
|
|
(** Serialization key, used to distinguish versions of serializers and avoid assert faults *)
|
|
|
|
|
type t = int
|
|
|
|
|
|
|
|
|
|
(** current key for tenv, procedure summary, cfg, error trace, call graph *)
|
|
|
|
|
let tenv, summary, cfg, trace, cg,
|
|
|
|
|
analysis_results, cluster, attributes, lint_issues =
|
|
|
|
|
425184201, 160179325, 1062389858, 221487792, 477305409,
|
|
|
|
|
799050016, 579094948, 972393003, 852343110
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
(** version of the binary files, to be incremented for each change *)
|
|
|
|
|
let version = 26
|
|
|
|
@ -31,7 +39,7 @@ let version = 26
|
|
|
|
|
|
|
|
|
|
(** Retry the function while an exception filtered is thrown,
|
|
|
|
|
or until the timeout in seconds expires. *)
|
|
|
|
|
let retry_exception timeout catch_exn f x =
|
|
|
|
|
let retry_exception ~timeout ~catch_exn ~f x =
|
|
|
|
|
let init_time = Unix.gettimeofday () in
|
|
|
|
|
let expired () =
|
|
|
|
|
Unix.gettimeofday () -. init_time >= timeout in
|
|
|
|
@ -42,8 +50,8 @@ let retry_exception timeout catch_exn f x =
|
|
|
|
|
retry ()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let create_serializer (key : key) : 'a serializer =
|
|
|
|
|
let match_data ((key': key), (version': int), (value: 'a)) source_msg =
|
|
|
|
|
let create_serializer (key : Key.t) : 'a serializer =
|
|
|
|
|
let read_data ((key': Key.t), (version': int), (value: 'a)) source_msg =
|
|
|
|
|
if key <> key' then
|
|
|
|
|
begin
|
|
|
|
|
L.err "Wrong key in when loading data from %s@\n" source_msg;
|
|
|
|
@ -55,11 +63,11 @@ let create_serializer (key : key) : 'a serializer =
|
|
|
|
|
None
|
|
|
|
|
end
|
|
|
|
|
else Some value in
|
|
|
|
|
let from_string (str : string) : 'a option =
|
|
|
|
|
let read_from_string (str : string) : 'a option =
|
|
|
|
|
try
|
|
|
|
|
match_data (Marshal.from_string str 0) "string"
|
|
|
|
|
read_data (Marshal.from_string str 0) "string"
|
|
|
|
|
with Sys_error _ -> None in
|
|
|
|
|
let from_file (fname_ : DB.filename) : 'a option =
|
|
|
|
|
let read_from_file (fname_ : DB.filename) : 'a option =
|
|
|
|
|
let fname = DB.filename_to_string fname_ in
|
|
|
|
|
match open_in_bin fname with
|
|
|
|
|
| exception Sys_error _ ->
|
|
|
|
@ -68,10 +76,9 @@ let create_serializer (key : key) : 'a serializer =
|
|
|
|
|
let read () =
|
|
|
|
|
try
|
|
|
|
|
In_channel.seek inc 0L ;
|
|
|
|
|
match_data (Marshal.from_channel inc) fname
|
|
|
|
|
read_data (Marshal.from_channel inc) fname
|
|
|
|
|
with
|
|
|
|
|
| Sys_error _ -> None in
|
|
|
|
|
let timeout = 1.0 in
|
|
|
|
|
let catch_exn = function
|
|
|
|
|
| End_of_file -> true
|
|
|
|
|
| Failure _ -> true (* handle input_value: truncated object *)
|
|
|
|
@ -79,9 +86,9 @@ let create_serializer (key : key) : 'a serializer =
|
|
|
|
|
(* Retry to read for 1 second in case of end of file, *)
|
|
|
|
|
(* which indicates that another process is writing the same file. *)
|
|
|
|
|
SymOp.try_finally
|
|
|
|
|
(fun () -> retry_exception timeout catch_exn read ())
|
|
|
|
|
(fun () -> retry_exception ~timeout:1.0 ~catch_exn ~f:read ())
|
|
|
|
|
(fun () -> In_channel.close inc) in
|
|
|
|
|
let to_file (fname : DB.filename) (value : 'a) =
|
|
|
|
|
let write_to_file (fname : DB.filename) (value : 'a) =
|
|
|
|
|
let fname_str = DB.filename_to_string fname in
|
|
|
|
|
(* support nonblocking reads and writes in parallel: *)
|
|
|
|
|
(* write to a tmp file and use rename which is atomic *)
|
|
|
|
@ -91,17 +98,17 @@ let create_serializer (key : key) : 'a serializer =
|
|
|
|
|
Marshal.to_channel outc (key, version, value) [];
|
|
|
|
|
Out_channel.close outc;
|
|
|
|
|
Unix.rename ~src:fname_tmp ~dst:fname_str in
|
|
|
|
|
(from_string, from_file, to_file)
|
|
|
|
|
{read_from_string; read_from_file; write_to_file}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let from_string (serializer : 'a serializer) =
|
|
|
|
|
let (s, _, _) = serializer in s
|
|
|
|
|
let read_from_string s =
|
|
|
|
|
s.read_from_string
|
|
|
|
|
|
|
|
|
|
let from_file (serializer : 'a serializer) =
|
|
|
|
|
let (_, s, _) = serializer in s
|
|
|
|
|
let read_from_file s =
|
|
|
|
|
s.read_from_file
|
|
|
|
|
|
|
|
|
|
let to_file (serializer : 'a serializer) =
|
|
|
|
|
let (_, _, s) = serializer in s
|
|
|
|
|
let write_to_file s =
|
|
|
|
|
s.write_to_file
|
|
|
|
|
|
|
|
|
|
(*
|
|
|
|
|
(** Generate random keys, to be used in an ocaml toplevel *)
|
|
|
|
|