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