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,24 +59,28 @@ 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 read () = let fname = DB.filename_to_string fname_ in
try match open_in_bin fname with
let fname = DB.filename_to_string _fname in | exception Sys_error _ ->
let inc = open_in_bin fname in None
let value_option = match_data (Marshal.from_channel inc) fname in | inc ->
close_in inc; let read () =
value_option try
with seek_in inc 0 ;
| Sys_error _ -> None in match_data (Marshal.from_channel inc) fname
let timeout = 1.0 in with
let catch_exn = function | Sys_error _ -> None in
| End_of_file -> true let timeout = 1.0 in
| Failure _ -> true (* handle input_value: truncated object *) let catch_exn = function
| _ -> false in | End_of_file -> true
(* Retry to read for 1 second in case of end of file, *) | Failure _ -> true (* handle input_value: truncated object *)
(* which indicates that another process is writing the same file. *) | _ -> false in
retry_exception timeout catch_exn read () in (* 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 () -> 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