Merge "libstore: use BEGIN IMMEDIATE SQLite transactions" into main

This commit is contained in:
Lily Ballard
2025-02-19 04:51:39 +00:00
committed by Gerrit Code Review
3 changed files with 44 additions and 9 deletions
+3 -3
View File
@@ -1116,7 +1116,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
return retrySQLite([&]() {
auto state(_dbState.lockSync(always_progresses));
SQLiteTxn txn = state->db.beginTransaction();
SQLiteTxn txn = state->db.beginTransaction(SQLiteTxnType::Immediate);
StorePathSet paths;
for (auto & [_, i] : infos) {
@@ -1508,7 +1508,7 @@ void LocalStore::invalidatePathChecked(const StorePath & path)
retrySQLite([&]() {
auto state(_dbState.lockSync(always_progresses));
SQLiteTxn txn = state->db.beginTransaction();
SQLiteTxn txn = state->db.beginTransaction(SQLiteTxnType::Immediate);
if (isValidPath_(*state, path)) {
StorePathSet referrers; queryReferrers(*state, path, referrers);
@@ -1772,7 +1772,7 @@ void LocalStore::addSignatures(const StorePath & storePath, const StringSet & si
retrySQLite([&]() {
auto state(_dbState.lockSync(always_progresses));
SQLiteTxn txn = state->db.beginTransaction();
SQLiteTxn txn = state->db.beginTransaction(SQLiteTxnType::Immediate);
auto info = std::const_pointer_cast<ValidPathInfo>(queryPathInfoInternal(*state, storePath));
+15 -4
View File
@@ -117,9 +117,9 @@ SQLiteStmt SQLite::create(const std::string & stmt)
return SQLiteStmt(db.get(), stmt);
}
SQLiteTxn SQLite::beginTransaction()
SQLiteTxn SQLite::beginTransaction(SQLiteTxnType type)
{
return SQLiteTxn(db.get());
return SQLiteTxn(db.get(), type);
}
void SQLite::setPersistWAL(bool persist)
@@ -253,9 +253,20 @@ bool SQLiteStmt::Use::isNull(int col)
return sqlite3_column_type(stmt.stmt.get(), col) == SQLITE_NULL;
}
SQLiteTxn::SQLiteTxn(sqlite3 * db)
SQLiteTxn::SQLiteTxn(sqlite3 * db, SQLiteTxnType type)
{
if (sqlite3_exec(db, "begin;", 0, 0, 0) != SQLITE_OK)
const char * sql = "begin;";
switch (type) {
case SQLiteTxnType::Deferred:
break;
case SQLiteTxnType::Immediate:
sql = "begin immediate;";
break;
case SQLiteTxnType::Exclusive:
sql = "begin exclusive;";
break;
}
if (sqlite3_exec(db, sql, 0, 0, 0) != SQLITE_OK)
SQLiteError::throw_(db, "starting transaction");
this->db.reset(db);
}
+26 -2
View File
@@ -37,6 +37,30 @@ enum class SQLiteOpenMode {
Immutable,
};
enum class SQLiteTxnType {
/**
* A deferred transaction does not actually begin until the database is first accessed.
* If the first statement in the transaction 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 another write transaction started on another database connection.
* If the first statement in the transaction is a write statement then a write transaction
* is started.
*/
Deferred,
/**
* An immediate transaction causes the database to start a write transaction immediately,
* without waiting for a write statement. The transaction might fail wth SQLITE_BUSY if another
* write transaction is already active on another database connection.
*/
Immediate,
/**
* An exclusive transaction causes the database to start a write transaction immediately.
* In WAL mode this is the same as Immediate, but in other journaling modes this prevents
* other database connections from reading the database while a transction is underway.
*/
Exclusive,
};
struct SQLiteError;
class SQLiteStmt;
class SQLiteTxn;
@@ -66,7 +90,7 @@ public:
SQLiteStmt create(const std::string & stmt);
SQLiteTxn beginTransaction();
SQLiteTxn beginTransaction(SQLiteTxnType type = SQLiteTxnType::Deferred);
void setPersistWAL(bool persist);
@@ -154,7 +178,7 @@ class SQLiteTxn
};
std::unique_ptr<sqlite3, Rollback> db;
explicit SQLiteTxn(sqlite3 * db);
explicit SQLiteTxn(sqlite3 * db, SQLiteTxnType type);
public:
void commit();