Convenience macros for retrying a SQLite transaction

This commit is contained in:
Eelco Dolstra 2013-10-16 14:46:35 +02:00
parent bce14d0f61
commit 4bd5282573
1 changed files with 42 additions and 46 deletions

View File

@ -75,6 +75,11 @@ static void throwSQLiteError(sqlite3 * db, const format & f)
} }
/* Convenience macros for retrying a SQLite transaction. */
#define retry_sqlite while (1) { try {
#define end_retry_sqlite break; } catch (SQLiteBusy & e) { } }
SQLite::~SQLite() SQLite::~SQLite()
{ {
try { try {
@ -1219,39 +1224,33 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
* expense of some speed of the path registering operation. */ * expense of some speed of the path registering operation. */
if (settings.syncBeforeRegistering) sync(); if (settings.syncBeforeRegistering) sync();
while (1) { retry_sqlite {
try { SQLiteTxn txn(db);
SQLiteTxn txn(db); PathSet paths;
PathSet paths;
foreach (ValidPathInfos::const_iterator, i, infos) { foreach (ValidPathInfos::const_iterator, i, infos) {
assert(i->hash.type == htSHA256); assert(i->hash.type == htSHA256);
if (isValidPath(i->path)) if (isValidPath(i->path))
updatePathInfo(*i); updatePathInfo(*i);
else else
addValidPath(*i); addValidPath(*i);
paths.insert(i->path); paths.insert(i->path);
}
foreach (ValidPathInfos::const_iterator, i, infos) {
unsigned long long referrer = queryValidPathId(i->path);
foreach (PathSet::iterator, j, i->references)
addReference(referrer, queryValidPathId(*j));
}
/* Do a topological sort of the paths. This will throw an
error if a cycle is detected and roll back the
transaction. Cycles can only occur when a derivation
has multiple outputs. */
topoSortPaths(*this, paths);
txn.commit();
break;
} catch (SQLiteBusy & e) {
/* Retry; the `txn' destructor will roll back the current
transaction. */
} }
}
foreach (ValidPathInfos::const_iterator, i, infos) {
unsigned long long referrer = queryValidPathId(i->path);
foreach (PathSet::iterator, j, i->references)
addReference(referrer, queryValidPathId(*j));
}
/* Do a topological sort of the paths. This will throw an
error if a cycle is detected and roll back the
transaction. Cycles can only occur when a derivation
has multiple outputs. */
topoSortPaths(*this, paths);
txn.commit();
} end_retry_sqlite;
} }
@ -1642,23 +1641,20 @@ void LocalStore::invalidatePathChecked(const Path & path)
{ {
assertStorePath(path); assertStorePath(path);
while (1) { retry_sqlite {
try { SQLiteTxn txn(db);
SQLiteTxn txn(db);
if (isValidPath(path)) { if (isValidPath(path)) {
PathSet referrers; queryReferrers(path, referrers); PathSet referrers; queryReferrers(path, referrers);
referrers.erase(path); /* ignore self-references */ referrers.erase(path); /* ignore self-references */
if (!referrers.empty()) if (!referrers.empty())
throw PathInUse(format("cannot delete path `%1%' because it is in use by %2%") throw PathInUse(format("cannot delete path `%1%' because it is in use by %2%")
% path % showPaths(referrers)); % path % showPaths(referrers));
invalidatePath(path); invalidatePath(path);
} }
txn.commit(); txn.commit();
break; } end_retry_sqlite;
} catch (SQLiteBusy & e) { };
}
} }