From 8012d61b0f4e3bc16524d75496b235b8ca612eb2 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Fri, 29 Sep 2017 08:47:45 -0700 Subject: [PATCH] [sql] do not generate the source file for attribute store if they are no-op Summary: If we know for sure we won't need to store an attribute in the DB, there's no need to compute its marshalled value. Reviewed By: jberdine Differential Revision: D5891050 fbshipit-source-id: cf4534e --- infer/src/IR/Attributes.ml | 24 ++++++++++++++++++++---- infer/src/base/DB.ml | 2 +- infer/src/base/SqliteUtils.mli | 2 +- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/infer/src/IR/Attributes.ml b/infer/src/IR/Attributes.ml index 8ef63ccac..802b79c33 100644 --- a/infer/src/IR/Attributes.ml +++ b/infer/src/IR/Attributes.ml @@ -62,9 +62,6 @@ let get_replace_statement = in several files *) (* TRICK: older versions of sqlite (prior to version 3.15.0 (2016-10-14)) do not support row values so the lexicographic ordering for (:akind, :sfile) is done by hand *) - (* TODO (optim): it might be worth not generating the source file everytime we do a store, but - only generate it if the attribute needs updating (which should be orders of magnitude less - frequent) *) ResultsDir.register_statement {| INSERT OR REPLACE INTO attributes @@ -91,6 +88,24 @@ let replace pname_blob akind loc_file attr_blob = |> SqliteUtils.check_sqlite_error ~log:"replace bind proc attributes" ; SqliteUtils.sqlite_unit_step ~finalize:false ~log:"Attributes.replace" replace_stmt +let get_find_more_defined_statement = + ResultsDir.register_statement + {| +SELECT attr_kind +FROM attributes +WHERE proc_name = :pname + AND attr_kind > :akind +|} + +let should_try_to_update pname_blob akind = + let find_stmt = get_find_more_defined_statement () in + Sqlite3.bind find_stmt 1 (* :pname *) pname_blob + |> SqliteUtils.check_sqlite_error ~log:"replace bind pname" ; + Sqlite3.bind find_stmt 2 (* :akind *) (Sqlite3.Data.INT (int64_of_attributes_kind akind)) + |> SqliteUtils.check_sqlite_error ~log:"replace bind attribute kind" ; + SqliteUtils.sqlite_result_step ~finalize:false ~log:"Attributes.replace" find_stmt + |> (* there is no entry with a strictly larger "definedness" for that proc name *) Option.is_none + let get_select_statement = ResultsDir.register_statement "SELECT proc_attributes FROM attributes WHERE proc_name = :k" @@ -111,7 +126,8 @@ let load pname = Data.of_pname pname |> find ~defined:false let store (attr: ProcAttributes.t) = let pkind = proc_kind_of_attr attr in let key = Data.of_pname attr.proc_name in - replace key pkind (Data.of_source_file attr.loc.Location.file) (Data.of_proc_attr attr) + if should_try_to_update key pkind then + replace key pkind (Data.of_source_file attr.loc.Location.file) (Data.of_proc_attr attr) let load_defined pname = Data.of_pname pname |> find ~defined:true diff --git a/infer/src/base/DB.ml b/infer/src/base/DB.ml index 738c6ff51..a191301fc 100644 --- a/infer/src/base/DB.ml +++ b/infer/src/base/DB.ml @@ -28,7 +28,7 @@ let append_crc_cutoff ?(key= "") ?(crc_only= false) name = let name_for_crc = name ^ key in Utils.string_crc_hex32 name_for_crc in - if crc_only then crc_str else name_up_to_cutoff ^ Char.to_string crc_token ^ crc_str + if crc_only then crc_str else Printf.sprintf "%s%c%s" name_up_to_cutoff crc_token crc_str (* Lengh of .crc part: 32 characters of digest, plus 1 character of crc_token *) let dot_crc_len = 1 + 32 diff --git a/infer/src/base/SqliteUtils.mli b/infer/src/base/SqliteUtils.mli index 5a050175d..be9458c9c 100644 --- a/infer/src/base/SqliteUtils.mli +++ b/infer/src/base/SqliteUtils.mli @@ -27,7 +27,7 @@ val sqlite_result_rev_list_step : (** Return a reversed list of results obtained by repeatedly stepping through [stmt] and saving only column 0 of each returned row (all that's been needed so far). *) val sqlite_result_step : ?finalize:bool -> log:string -> Sqlite3.stmt -> Sqlite3.Data.t option -(** Same as [sqlite_result_rev_list_step] but asserts that exactly one result is returned. *) +(** Same as [sqlite_result_rev_list_step] but asserts that at most one result is returned. *) val sqlite_unit_step : ?finalize:bool -> log:string -> Sqlite3.stmt -> unit (** Same as [sqlite_result_rev_list_step] but asserts that no result is returned. *)