Skip to content

Commit

Permalink
[sqlite] cd rather than symlink db paths
Browse files Browse the repository at this point in the history
Summary: Reuse technique originally for unix sockets: cd into the directory with the database file, open it, then cd back. This avoids the Sqlite limits on maximum path length entirely.

Reviewed By: jvillard

Differential Revision:
D66544844

Privacy Context Container: L1208441

fbshipit-source-id: 66d05cee5c85bc41c7f8fa5404dbefdc741fb4e9
  • Loading branch information
ngorogiannis authored and facebook-github-bot committed Nov 27, 2024
1 parent a42a0c6 commit 960f345
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 25 deletions.
34 changes: 12 additions & 22 deletions infer/src/base/Database.ml
Original file line number Diff line number Diff line change
Expand Up @@ -138,39 +138,28 @@ type location = Primary | Secondary of string [@@deriving show {with_path= false
let results_dir_get_path entry = ResultsDirEntryName.get_path ~results_dir:Config.results_dir entry

let get_db_path location id =
match location with
| Secondary file ->
file
| Primary ->
let path_to_db = results_dir_get_path (get_db_entry id) in
if String.length path_to_db > SqliteUtils.sqlite_max_path_length then (
let link_name = Filename.temp_file "infer-merge-sqlite-trampoline" ".db" in
Unix.unlink link_name ;
Unix.symlink ~target:(Filename.dirname path_to_db) ~link_name ;
Filename.concat link_name (Filename.basename path_to_db) )
else path_to_db
match location with Secondary file -> file | Primary -> results_dir_get_path (get_db_entry id)


let do_in_db_dir db_path ~f =
let dir = Filename.dirname db_path in
let base_name = Filename.basename db_path in
Utils.do_in_dir ~dir ~f:(fun () -> f base_name)


let create_db location id =
let final_db_path = get_db_path location id in
let pid = Unix.getpid () in
let in_dir =
(* if the length of the path to the results directory is greater than Sqlite's limit
then create the DB in [$TMPDIR] otherwise in [results_dir/tmp] *)
let results_temp_dir = results_dir_get_path Temporary in
if String.length results_temp_dir > SqliteUtils.sqlite_max_path_length - 50 then None
else Some results_temp_dir
in
let temp_db_path =
Filename.temp_file ?in_dir
Filename.temp_file ~in_dir:(results_dir_get_path Temporary)
( match id with
| CaptureDatabase ->
"capture." ^ Pid.to_string pid ^ ".db"
| AnalysisDatabase ->
"results." ^ Pid.to_string pid ^ ".db" )
".tmp"
in
let db = Sqlite3.db_open ~mutex:`FULL temp_db_path in
let db = do_in_db_dir temp_db_path ~f:(fun db_path -> Sqlite3.db_open ~mutex:`FULL db_path) in
SqliteUtils.exec db ~log:"sqlite page size"
~stmt:(Printf.sprintf "PRAGMA page_size=%d" Config.sqlite_page_size) ;
create_tables db id ;
Expand Down Expand Up @@ -315,8 +304,9 @@ end = struct
db_close_1 id ;
let db_path = get_db_path location id in
let db =
Sqlite3.db_open ~mode:`NO_CREATE ~cache:`PRIVATE ~mutex:`FULL ?vfs:Config.sqlite_vfs ~uri:true
db_path
do_in_db_dir db_path ~f:(fun db_path ->
Sqlite3.db_open ~mode:`NO_CREATE ~cache:`PRIVATE ~mutex:`FULL ?vfs:Config.sqlite_vfs
~uri:true db_path )
in
Sqlite3.busy_timeout db Config.sqlite_lock_timeout ;
SqliteUtils.exec db ~log:"mmap"
Expand Down
3 changes: 0 additions & 3 deletions infer/src/base/SqliteUtils.mli
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ exception Error of string
(** Raised from serializers when final size exceeds Sqlite3 limits (normally 1000_000_000 bytes). *)
exception DataTooBig

val sqlite_max_path_length : int
(** an underapproximation of the maximum path length allowed in sqlite *)

val check_result_code : Sqlite3.db -> log:string -> Sqlite3.Rc.t -> unit
(** Assert that the result is either [Sqlite3.Rc.OK] or [Sqlite3.Rc.ROW]. If the result is not
valid, raise {!Error}. *)
Expand Down

0 comments on commit 960f345

Please sign in to comment.