[sqlite] reset before query

Summary:
When running with high parallelism and a large number of insertions in the DB (eg, ObjC analysis with block specialisation), we see MISUSE exceptions thrown by Sqlite **when trying to bind parameters to queries**.  It does not always occur, and maybe that's because the check in Sqlite that throws this error is documented as "probabilistic".  For the same reason, it is plausible that high parallelism increases the chance of detection.

According to documentation this unequivocally means a bug in our usage of the API (https://www.sqlite.org/rescode.html#misuse), in particular that a parameter is re-bound while the query is running (https://www2.sqlite.org/cvstrac/wiki?p=LibraryRoutineCalledOutOfSequence).  I believe this may have to do with `result_fold_rows` (as it's the only one that uses a query that can be continued, and thus misused), but I have not managed to track the bug.

Always resetting the query before using it is a defensive measure that seems to make these errors go away (and turn some of them to BUSY timeouts, which should be addressed by a write serialiser, but in any case it's a more logical state of affairs = higher parallelism means more contention thus possibly timeouts due to lock usage).

Reviewed By: jvillard

Differential Revision: D17147447

fbshipit-source-id: 7ef3cc73f
master
Nikos Gorogiannis 5 years ago committed by Facebook Github Bot
parent ad4bc0a905
commit c07555a768

@ -93,6 +93,7 @@ let register_statement =
| None ->
L.(die InternalError) "database not initialized"
| Some (stmt, db) ->
Sqlite3.reset stmt |> SqliteUtils.check_result_code db ~log:"reset prepared statement" ;
Sqlite3.clear_bindings stmt
|> SqliteUtils.check_result_code db ~log:"clear bindings of prepared statement" ;
(stmt, db)
@ -104,7 +105,6 @@ let with_registered_statement get_stmt ~f =
PerfEvent.(log (fun logger -> log_begin_event logger ~name:"sql op" ())) ;
let stmt, db = get_stmt () in
let result = f db stmt in
Sqlite3.reset stmt |> SqliteUtils.check_result_code db ~log:"reset prepared statement" ;
PerfEvent.(log (fun logger -> log_end_event logger ())) ;
result

Loading…
Cancel
Save