Turn retrying SQLite transactions into a higher-order function

This commit is contained in:
Eelco Dolstra 2016-03-30 12:04:27 +02:00
parent 39a6abc0bc
commit 2ae43ced9a

View file

@ -70,9 +70,18 @@ MakeError(SQLiteBusy, SQLiteError);
} }
/* Convenience macros for retrying a SQLite transaction. */ /* Convenience function for retrying a SQLite transaction when the
#define retry_sqlite while (1) { try { database is busy. */
#define end_retry_sqlite break; } catch (SQLiteBusy & e) { } } template<typename T>
T retrySQLite(std::function<T()> fun)
{
while (true) {
try {
return fun();
} catch (SQLiteBusy & e) {
}
}
}
SQLite::~SQLite() SQLite::~SQLite()
@ -746,32 +755,32 @@ void LocalStore::addReference(unsigned long long referrer, unsigned long long re
void LocalStore::registerFailedPath(const Path & path) void LocalStore::registerFailedPath(const Path & path)
{ {
retry_sqlite { retrySQLite<void>([&]() {
SQLiteStmtUse use(stmtRegisterFailedPath); SQLiteStmtUse use(stmtRegisterFailedPath);
stmtRegisterFailedPath.bind(path); stmtRegisterFailedPath.bind(path);
stmtRegisterFailedPath.bind(time(0)); stmtRegisterFailedPath.bind(time(0));
if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE) if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE)
throwSQLiteError(db, format("registering failed path %1%") % path); throwSQLiteError(db, format("registering failed path %1%") % path);
} end_retry_sqlite; });
} }
bool LocalStore::hasPathFailed(const Path & path) bool LocalStore::hasPathFailed(const Path & path)
{ {
retry_sqlite { return retrySQLite<bool>([&]() {
SQLiteStmtUse use(stmtHasPathFailed); SQLiteStmtUse use(stmtHasPathFailed);
stmtHasPathFailed.bind(path); stmtHasPathFailed.bind(path);
int res = sqlite3_step(stmtHasPathFailed); int res = sqlite3_step(stmtHasPathFailed);
if (res != SQLITE_DONE && res != SQLITE_ROW) if (res != SQLITE_DONE && res != SQLITE_ROW)
throwSQLiteError(db, "querying whether path failed"); throwSQLiteError(db, "querying whether path failed");
return res == SQLITE_ROW; return res == SQLITE_ROW;
} end_retry_sqlite; });
} }
PathSet LocalStore::queryFailedPaths() PathSet LocalStore::queryFailedPaths()
{ {
retry_sqlite { return retrySQLite<PathSet>([&]() {
SQLiteStmtUse use(stmtQueryFailedPaths); SQLiteStmtUse use(stmtQueryFailedPaths);
PathSet res; PathSet res;
@ -786,13 +795,13 @@ PathSet LocalStore::queryFailedPaths()
throwSQLiteError(db, "error querying failed paths"); throwSQLiteError(db, "error querying failed paths");
return res; return res;
} end_retry_sqlite; });
} }
void LocalStore::clearFailedPaths(const PathSet & paths) void LocalStore::clearFailedPaths(const PathSet & paths)
{ {
retry_sqlite { retrySQLite<void>([&]() {
SQLiteTxn txn(db); SQLiteTxn txn(db);
for (auto & i : paths) { for (auto & i : paths) {
@ -803,7 +812,7 @@ void LocalStore::clearFailedPaths(const PathSet & paths)
} }
txn.commit(); txn.commit();
} end_retry_sqlite; });
} }
@ -828,7 +837,7 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
assertStorePath(path); assertStorePath(path);
retry_sqlite { return retrySQLite<ValidPathInfo>([&]() {
/* Get the path info. */ /* Get the path info. */
SQLiteStmtUse use1(stmtQueryPathInfo); SQLiteStmtUse use1(stmtQueryPathInfo);
@ -868,7 +877,7 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
throwSQLiteError(db, format("error getting references of %1%") % path); throwSQLiteError(db, format("error getting references of %1%") % path);
return info; return info;
} end_retry_sqlite; });
} }
@ -912,26 +921,26 @@ bool LocalStore::isValidPath_(const Path & path)
bool LocalStore::isValidPath(const Path & path) bool LocalStore::isValidPath(const Path & path)
{ {
retry_sqlite { return retrySQLite<bool>([&]() {
return isValidPath_(path); return isValidPath_(path);
} end_retry_sqlite; });
} }
PathSet LocalStore::queryValidPaths(const PathSet & paths) PathSet LocalStore::queryValidPaths(const PathSet & paths)
{ {
retry_sqlite { return retrySQLite<PathSet>([&]() {
PathSet res; PathSet res;
for (auto & i : paths) for (auto & i : paths)
if (isValidPath_(i)) res.insert(i); if (isValidPath_(i)) res.insert(i);
return res; return res;
} end_retry_sqlite; });
} }
PathSet LocalStore::queryAllValidPaths() PathSet LocalStore::queryAllValidPaths()
{ {
retry_sqlite { return retrySQLite<PathSet>([&]() {
SQLiteStmt stmt; SQLiteStmt stmt;
stmt.create(db, "select path from ValidPaths"); stmt.create(db, "select path from ValidPaths");
@ -947,7 +956,7 @@ PathSet LocalStore::queryAllValidPaths()
throwSQLiteError(db, "error getting valid paths"); throwSQLiteError(db, "error getting valid paths");
return res; return res;
} end_retry_sqlite; });
} }
@ -972,9 +981,9 @@ void LocalStore::queryReferrers_(const Path & path, PathSet & referrers)
void LocalStore::queryReferrers(const Path & path, PathSet & referrers) void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
{ {
assertStorePath(path); assertStorePath(path);
retry_sqlite { return retrySQLite<void>([&]() {
queryReferrers_(path, referrers); queryReferrers_(path, referrers);
} end_retry_sqlite; });
} }
@ -988,7 +997,7 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
{ {
assertStorePath(path); assertStorePath(path);
retry_sqlite { return retrySQLite<PathSet>([&]() {
SQLiteStmtUse use(stmtQueryValidDerivers); SQLiteStmtUse use(stmtQueryValidDerivers);
stmtQueryValidDerivers.bind(path); stmtQueryValidDerivers.bind(path);
@ -1004,13 +1013,13 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
throwSQLiteError(db, format("error getting valid derivers of %1%") % path); throwSQLiteError(db, format("error getting valid derivers of %1%") % path);
return derivers; return derivers;
} end_retry_sqlite; });
} }
PathSet LocalStore::queryDerivationOutputs(const Path & path) PathSet LocalStore::queryDerivationOutputs(const Path & path)
{ {
retry_sqlite { return retrySQLite<PathSet>([&]() {
SQLiteStmtUse use(stmtQueryDerivationOutputs); SQLiteStmtUse use(stmtQueryDerivationOutputs);
stmtQueryDerivationOutputs.bind(queryValidPathId(path)); stmtQueryDerivationOutputs.bind(queryValidPathId(path));
@ -1026,13 +1035,13 @@ PathSet LocalStore::queryDerivationOutputs(const Path & path)
throwSQLiteError(db, format("error getting outputs of %1%") % path); throwSQLiteError(db, format("error getting outputs of %1%") % path);
return outputs; return outputs;
} end_retry_sqlite; });
} }
StringSet LocalStore::queryDerivationOutputNames(const Path & path) StringSet LocalStore::queryDerivationOutputNames(const Path & path)
{ {
retry_sqlite { return retrySQLite<StringSet>([&]() {
SQLiteStmtUse use(stmtQueryDerivationOutputs); SQLiteStmtUse use(stmtQueryDerivationOutputs);
stmtQueryDerivationOutputs.bind(queryValidPathId(path)); stmtQueryDerivationOutputs.bind(queryValidPathId(path));
@ -1048,7 +1057,7 @@ StringSet LocalStore::queryDerivationOutputNames(const Path & path)
throwSQLiteError(db, format("error getting output names of %1%") % path); throwSQLiteError(db, format("error getting output names of %1%") % path);
return outputNames; return outputNames;
} end_retry_sqlite; });
} }
@ -1058,7 +1067,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
Path prefix = settings.nixStore + "/" + hashPart; Path prefix = settings.nixStore + "/" + hashPart;
retry_sqlite { return retrySQLite<Path>([&]() {
SQLiteStmtUse use(stmtQueryPathFromHashPart); SQLiteStmtUse use(stmtQueryPathFromHashPart);
stmtQueryPathFromHashPart.bind(prefix); stmtQueryPathFromHashPart.bind(prefix);
@ -1068,7 +1077,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
const char * s = (const char *) sqlite3_column_text(stmtQueryPathFromHashPart, 0); const char * s = (const char *) sqlite3_column_text(stmtQueryPathFromHashPart, 0);
return s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0 ? s : ""; return s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0 ? s : "";
} end_retry_sqlite; });
} }
@ -1291,7 +1300,7 @@ 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();
retry_sqlite { return retrySQLite<void>([&]() {
SQLiteTxn txn(db); SQLiteTxn txn(db);
PathSet paths; PathSet paths;
@ -1328,7 +1337,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
topoSortPaths(paths); topoSortPaths(paths);
txn.commit(); txn.commit();
} end_retry_sqlite; });
} }
@ -1712,7 +1721,7 @@ void LocalStore::invalidatePathChecked(const Path & path)
{ {
assertStorePath(path); assertStorePath(path);
retry_sqlite { retrySQLite<void>([&]() {
SQLiteTxn txn(db); SQLiteTxn txn(db);
if (isValidPath_(path)) { if (isValidPath_(path)) {
@ -1725,7 +1734,7 @@ void LocalStore::invalidatePathChecked(const Path & path)
} }
txn.commit(); txn.commit();
} end_retry_sqlite; });
} }