From 6357a7bf559f5a187aa0af59a8703e37e782ec5b Mon Sep 17 00:00:00 2001 From: zimbatm Date: Sat, 19 Oct 2024 10:35:02 +0200 Subject: [PATCH] libstore: use sqlit3 IMMEDIATE transactions The default transaction behavior (of Sqlite3) is DEFERRED. DEFERRED means that the transaction does not actually start until the database is first accessed. Internally, the BEGIN DEFERRED statement merely sets a flag on the database connection that turns off the automatic commit that would normally occur when the last statement finishes. This causes the transaction that is automatically started to persist until an explicit COMMIT or ROLLBACK or until a rollback is provoked by an error or an ON CONFLICT ROLLBACK clause. If the first statement after BEGIN DEFERRED is a SELECT, then a read transaction is started. Subsequent write statements will upgrade the transaction to a write transaction if possible, or return SQLITE_BUSY. If the first statement after BEGIN DEFERRED is a write statement, then a write transaction is started. IMMEDIATE causes the database connection to start a new write immediately, without waiting for a write statement. The BEGIN IMMEDIATE might fail with SQLITE_BUSY if another write transaction is already active on another database connection. source: https://www.sqlite.org/lang_transaction.html#immediate Because Nix only uses transactions for write operations, changing the default will allow pushing the SQLITE_BUSY errors early instead of mid-transaction. --- src/libstore/sqlite.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstore/sqlite.cc b/src/libstore/sqlite.cc index f02e472fd5f..619fa90cf5b 100644 --- a/src/libstore/sqlite.cc +++ b/src/libstore/sqlite.cc @@ -222,7 +222,7 @@ bool SQLiteStmt::Use::isNull(int col) SQLiteTxn::SQLiteTxn(sqlite3 * db) { this->db = db; - if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK) + if (sqlite3_exec(db, "begin immediate transaction;", 0, 0, 0) != SQLITE_OK) SQLiteError::throw_(db, "starting transaction"); active = true; }