diff --git a/scripts/policy/frameworks/storage/backend/sqlite/main.zeek b/scripts/policy/frameworks/storage/backend/sqlite/main.zeek index c8c5f6ca87..505aee00de 100644 --- a/scripts/policy/frameworks/storage/backend/sqlite/main.zeek +++ b/scripts/policy/frameworks/storage/backend/sqlite/main.zeek @@ -20,14 +20,19 @@ export { ## different between the two. table_name: string; + ## The timeout for the connection to the database. This is set + ## per-connection. It is equivalent to setting a ``busy_timeout`` pragma + ## value, but that value will be ignored in favor of this field. + busy_timeout: interval &default=5 secs; + ## Key/value table for passing pragma commands when opening the database. ## These must be pairs that can be passed to the ``pragma`` command in ## sqlite. The ``integrity_check`` pragma is run automatically and does ## not need to be included here. For pragmas without a second argument, - ## set the value to an empty string. + ## set the value to an empty string. Setting the ``busy_timeout`` pragma + ## here will be ignored. pragma_commands: table[string] of string &ordered &default=table( ["integrity_check"] = "", - ["busy_timeout"] = "5000", ["journal_mode"] = "WAL", ["synchronous"] = "normal", ["temp_store"] = "memory" diff --git a/src/storage/backend/sqlite/SQLite.cc b/src/storage/backend/sqlite/SQLite.cc index 596ae6374f..309407bb6c 100644 --- a/src/storage/backend/sqlite/SQLite.cc +++ b/src/storage/backend/sqlite/SQLite.cc @@ -84,6 +84,8 @@ OperationResult SQLite::DoOpen(OpenResultCallback* cb, RecordValPtr options) { full_path = zeek::filesystem::path(path->ToStdString()).string(); table_name = backend_options->GetField("table_name")->ToStdString(); + auto busy_timeout = backend_options->GetField("busy_timeout")->Get(); + auto pragma_timeout_val = backend_options->GetField("pragma_timeout"); pragma_timeout = std::chrono::milliseconds(static_cast(pragma_timeout_val->Get() * 1000)); @@ -99,25 +101,26 @@ OperationResult SQLite::DoOpen(OpenResultCallback* cb, RecordValPtr options) { return open_res; } - // TODO: Should we use sqlite3_busy_timeout here instead of using the pragma? That would - // at least let us skip over one. The busy timeout is per-connection as well, so it'll - // never fail to run like the other pragmas can. - // sqlite3_busy_timeout(db, 2000); + sqlite3_busy_timeout(db, busy_timeout * 1000); auto pragmas = backend_options->GetField("pragma_commands"); for ( const auto& iter : *(pragmas->Get()) ) { auto k = iter.GetHashKey(); - auto v = iter.value; auto vl = pragmas->GetTableHash()->RecoverVals(*k); auto ks = vl->AsListVal()->Idx(0)->AsStringVal(); auto ks_sv = ks->ToStdStringView(); + + if ( ks_sv == "busy_timeout" ) + continue; + auto vs = iter.value->GetVal()->AsStringVal(); auto vs_sv = vs->ToStdStringView(); auto pragma_res = RunPragma(ks_sv, vs_sv); if ( pragma_res.code != ReturnCode::SUCCESS ) { Error(pragma_res.err_str.c_str()); + Close(nullptr); return pragma_res; } } diff --git a/testing/btest/Baseline/scripts.base.frameworks.storage.sqlite-basic/out b/testing/btest/Baseline/scripts.base.frameworks.storage.sqlite-basic/out index 0d8cb07abb..055e0cd530 100644 --- a/testing/btest/Baseline/scripts.base.frameworks.storage.sqlite-basic/out +++ b/testing/btest/Baseline/scripts.base.frameworks.storage.sqlite-basic/out @@ -1,7 +1,6 @@ ### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. -Storage::backend_opened, Storage::STORAGE_BACKEND_SQLITE, [serializer=Storage::STORAGE_SERIALIZER_JSON, sqlite=[database_path=test.sqlite, table_name=testing, pragma_commands={ +Storage::backend_opened, Storage::STORAGE_BACKEND_SQLITE, [serializer=Storage::STORAGE_SERIALIZER_JSON, sqlite=[database_path=test.sqlite, table_name=testing, busy_timeout=5.0 secs, pragma_commands={ [integrity_check] = , -[busy_timeout] = 5000, [journal_mode] = WAL, [synchronous] = normal, [temp_store] = memory