forked from lix-project/lix
* Retry a transaction if SQLite returns SQLITE_BUSY. This can happen
even with a very long busy timeout, because SQLITE_BUSY is also returned to resolve deadlocks. This should get rid of random "database is locked" errors. This is kind of hard to test though. * Fix a horrible bug in deleteFromStore(): deletePathWrapped() should be called after committing the transaction, not before, because the commit might not succeed.
This commit is contained in:
parent
365f3028dd
commit
de79d23f76
|
@ -23,14 +23,23 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
class SQLiteError : public Error
|
MakeError(SQLiteError, Error);
|
||||||
{
|
MakeError(SQLiteBusy, SQLiteError);
|
||||||
public:
|
|
||||||
SQLiteError(sqlite3 * db, const format & f)
|
|
||||||
: Error(format("%1%: %2%") % f.str() % sqlite3_errmsg(db))
|
static void throwSQLiteError(sqlite3 * db, const format & f)
|
||||||
|
__attribute__ ((noreturn));
|
||||||
|
|
||||||
|
static void throwSQLiteError(sqlite3 * db, const format & f)
|
||||||
{
|
{
|
||||||
|
int err = sqlite3_errcode(db);
|
||||||
|
if (err == SQLITE_BUSY) {
|
||||||
|
printMsg(lvlError, "warning: SQLite database is busy");
|
||||||
|
throw SQLiteBusy(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw SQLiteError(format("%1%: %2%") % f.str() % sqlite3_errmsg(db));
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
SQLite::~SQLite()
|
SQLite::~SQLite()
|
||||||
|
@ -499,6 +508,8 @@ void LocalStore::registerValidPath(const ValidPathInfo & info)
|
||||||
ValidPathInfo info2(info);
|
ValidPathInfo info2(info);
|
||||||
if (info2.registrationTime == 0) info2.registrationTime = time(0);
|
if (info2.registrationTime == 0) info2.registrationTime = time(0);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
try {
|
||||||
SQLiteTxn txn(db);
|
SQLiteTxn txn(db);
|
||||||
|
|
||||||
unsigned long long id = addValidPath(info2);
|
unsigned long long id = addValidPath(info2);
|
||||||
|
@ -507,6 +518,12 @@ void LocalStore::registerValidPath(const ValidPathInfo & info)
|
||||||
addReference(id, queryValidPathId(*i));
|
addReference(id, queryValidPathId(*i));
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
break;
|
||||||
|
} catch (SQLiteBusy & e) {
|
||||||
|
/* Retry; the `txn' destructor will roll back the current
|
||||||
|
transaction. */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1248,6 +1265,8 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr
|
||||||
|
|
||||||
assertStorePath(path);
|
assertStorePath(path);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
try {
|
||||||
SQLiteTxn txn(db);
|
SQLiteTxn txn(db);
|
||||||
|
|
||||||
if (isValidPath(path)) {
|
if (isValidPath(path)) {
|
||||||
|
@ -1259,9 +1278,12 @@ void LocalStore::deleteFromStore(const Path & path, unsigned long long & bytesFr
|
||||||
invalidatePath(path);
|
invalidatePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePathWrapped(path, bytesFreed, blocksFreed);
|
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
break;
|
||||||
|
} catch (SQLiteBusy & e) { };
|
||||||
|
}
|
||||||
|
|
||||||
|
deletePathWrapped(path, bytesFreed, blocksFreed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue