You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
3.0 KiB
85 lines
3.0 KiB
(*
|
|
* Copyright (c) 2009-2013, Monoidics ltd.
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*)
|
|
|
|
open! IStd
|
|
module L = Logging
|
|
|
|
(** Generic serializer *)
|
|
type 'a serializer =
|
|
{read_from_file: DB.filename -> 'a option; write_to_file: data:'a -> DB.filename -> unit}
|
|
|
|
module Key = struct
|
|
type t =
|
|
{ name: string (** for logging purposes *)
|
|
; key: int
|
|
(** Serialization key, used to distinguish versions of serializers and avoid assert faults *)
|
|
}
|
|
|
|
(** Current keys for various serializable objects. The keys are computed using the [generate_keys]
|
|
function below *)
|
|
let tenv, summary, issues =
|
|
( {name= "tenv"; key= 425184201}
|
|
, {name= "summary"; key= 160179325}
|
|
, {name= "issues"; key= 852343110} )
|
|
end
|
|
|
|
(** version of the binary files, to be incremented for each change *)
|
|
let version = 27
|
|
|
|
let create_serializer (key : Key.t) : 'a serializer =
|
|
let read_data ((key' : int), (version' : int), (value : 'a)) source_msg =
|
|
if key.key <> key' then (
|
|
L.user_error
|
|
"Wrong key in when loading data of type %s from %s -- are you running infer with results \
|
|
coming from a previous version of infer?@\n"
|
|
key.name source_msg ;
|
|
None )
|
|
else if version <> version' then (
|
|
L.user_error
|
|
"Wrong version in when loading data of type %s from %s -- are you running infer with \
|
|
results coming from a previous version of infer?@\n"
|
|
key.name source_msg ;
|
|
None )
|
|
else Some value
|
|
in
|
|
let read_from_file (fname : DB.filename) : 'a option =
|
|
(* The serialization is based on atomic file renames,
|
|
so the deserialization cannot read a file while it is being written. *)
|
|
let filename = DB.filename_to_string fname in
|
|
PerfEvent.(
|
|
log (fun logger -> log_begin_event logger ~name:("reading " ^ key.name) ~categories:["io"] ())) ;
|
|
let result =
|
|
try Utils.with_file_in filename ~f:(fun inc -> read_data (Marshal.from_channel inc) filename)
|
|
with Sys_error _ -> None
|
|
in
|
|
PerfEvent.(log (fun logger -> log_end_event logger ())) ;
|
|
result
|
|
in
|
|
let write_to_file ~(data : 'a) (fname : DB.filename) =
|
|
let filename = DB.filename_to_string fname in
|
|
PerfEvent.(
|
|
log (fun logger -> log_begin_event logger ~name:("writing " ^ key.name) ~categories:["io"] ())) ;
|
|
Utils.with_intermediate_temp_file_out filename ~f:(fun outc ->
|
|
Marshal.to_channel outc (key.key, version, data) [] ) ;
|
|
PerfEvent.(log (fun logger -> log_end_event logger ()))
|
|
in
|
|
{read_from_file; write_to_file}
|
|
|
|
|
|
let read_from_file s = s.read_from_file
|
|
|
|
let write_to_file s = s.write_to_file
|
|
|
|
(** Generate new (random) serialization keys, to be run in an ocaml toplevel and used in the [Key]
|
|
module above *)
|
|
let generate_keys () =
|
|
Random.self_init () ;
|
|
let max_rand_int = 0x3FFFFFFF (* determined by Rand library *) in
|
|
let gen () = Random.int max_rand_int in
|
|
(gen (), gen (), gen ())
|