Optimize deserialization retrying

Summary:
Optimize retries in deserialization by opening the file only once
instead of once per retry.  Also ensure that the file is closed on
failure.  This reduces memory leaked for unclosed channels.

Reviewed By: jvillard, cristianoc

Differential Revision: D3321132

fbshipit-source-id: 05e6ff0
master
Josh Berdine 9 years ago committed by Facebook Github Bot 7
parent 1c7375143d
commit 1177f21aa4

@ -28,6 +28,26 @@ let exn_not_failure = function
| Analysis_failure_exe _ -> false | Analysis_failure_exe _ -> false
| _ -> true | _ -> true
let try_finally ?(fail_early=false) f g =
match f () with
| r ->
g () ;
r
| exception (Analysis_failure_exe _ as f_exn) ->
if not fail_early then
(try g () with _ -> ());
raise f_exn
| exception f_exn ->
match g () with
| () ->
raise f_exn
| exception (Analysis_failure_exe _ as g_exn) ->
raise g_exn
| exception _ ->
raise f_exn
let finally_try g f = try_finally f g
let pp_failure_kind fmt = function let pp_failure_kind fmt = function
| FKtimeout -> F.fprintf fmt "TIMEOUT" | FKtimeout -> F.fprintf fmt "TIMEOUT"
| FKsymops_timeout symops -> F.fprintf fmt "SYMOPS TIMEOUT (%d)" symops | FKsymops_timeout symops -> F.fprintf fmt "SYMOPS TIMEOUT (%d)" symops

@ -68,4 +68,14 @@ exception Analysis_failure_exe of failure_kind
(** check that the exception is not a timeout exception *) (** check that the exception is not a timeout exception *)
val exn_not_failure : exn -> bool val exn_not_failure : exn -> bool
(** [try_finally ~fail_early f g] executes [f] and then [g] even if [f] raises an exception.
Assuming that [g ()] terminates quickly [Analysis_failure_exe] exceptions are handled correctly.
In particular, an exception raised by [f ()] is delayed until [g ()] finishes, so [g ()] should
return reasonably quickly. [~fail_early=true] can be passed to skip executing [g ()] when [f
()] raises a [Analysis_failure_exe] exception. *)
val try_finally : ?fail_early:bool -> (unit -> 'a) -> (unit -> unit) -> 'a
(** [finally_try g f] is equivalent to [try_finally f g]. *)
val finally_try : (unit -> unit) -> (unit -> 'a) -> 'a
val pp_failure_kind : Format.formatter -> failure_kind -> unit val pp_failure_kind : Format.formatter -> failure_kind -> unit

@ -59,14 +59,16 @@ let create_serializer (key : key) : 'a serializer =
try try
match_data (Marshal.from_string str 0) "string" match_data (Marshal.from_string str 0) "string"
with Sys_error _ -> None in with Sys_error _ -> None in
let from_file (_fname : DB.filename) : 'a option = let from_file (fname_ : DB.filename) : 'a option =
let fname = DB.filename_to_string fname_ in
match open_in_bin fname with
| exception Sys_error _ ->
None
| inc ->
let read () = let read () =
try try
let fname = DB.filename_to_string _fname in seek_in inc 0 ;
let inc = open_in_bin fname in match_data (Marshal.from_channel inc) fname
let value_option = match_data (Marshal.from_channel inc) fname in
close_in inc;
value_option
with with
| Sys_error _ -> None in | Sys_error _ -> None in
let timeout = 1.0 in let timeout = 1.0 in
@ -76,7 +78,9 @@ let create_serializer (key : key) : 'a serializer =
| _ -> false in | _ -> false in
(* Retry to read for 1 second in case of end of file, *) (* Retry to read for 1 second in case of end of file, *)
(* which indicates that another process is writing the same file. *) (* which indicates that another process is writing the same file. *)
retry_exception timeout catch_exn read () in SymOp.try_finally
(fun () -> retry_exception timeout catch_exn read ())
(fun () -> close_in inc) in
let to_file (fname : DB.filename) (value : 'a) = let to_file (fname : DB.filename) (value : 'a) =
let fname_str = DB.filename_to_string fname in let fname_str = DB.filename_to_string fname in
(* support nonblocking reads and writes in parallel: *) (* support nonblocking reads and writes in parallel: *)

Loading…
Cancel
Save