forked from lix-project/lix
Retry all SQLite operations
To deal with SQLITE_PROTOCOL, we also need to retry read-only operations.
This commit is contained in:
parent
ff02f5336c
commit
a737f51fd9
|
@ -692,56 +692,64 @@ void LocalStore::addReference(unsigned long long referrer, unsigned long long re
|
||||||
|
|
||||||
void LocalStore::registerFailedPath(const Path & path)
|
void LocalStore::registerFailedPath(const Path & path)
|
||||||
{
|
{
|
||||||
SQLiteStmtUse use(stmtRegisterFailedPath);
|
retry_sqlite {
|
||||||
stmtRegisterFailedPath.bind(path);
|
SQLiteStmtUse use(stmtRegisterFailedPath);
|
||||||
stmtRegisterFailedPath.bind(time(0));
|
stmtRegisterFailedPath.bind(path);
|
||||||
if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE)
|
stmtRegisterFailedPath.bind(time(0));
|
||||||
throwSQLiteError(db, format("registering failed path `%1%'") % path);
|
if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE)
|
||||||
|
throwSQLiteError(db, format("registering failed path `%1%'") % path);
|
||||||
|
} end_retry_sqlite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LocalStore::hasPathFailed(const Path & path)
|
bool LocalStore::hasPathFailed(const Path & path)
|
||||||
{
|
{
|
||||||
SQLiteStmtUse use(stmtHasPathFailed);
|
retry_sqlite {
|
||||||
stmtHasPathFailed.bind(path);
|
SQLiteStmtUse use(stmtHasPathFailed);
|
||||||
int res = sqlite3_step(stmtHasPathFailed);
|
stmtHasPathFailed.bind(path);
|
||||||
if (res != SQLITE_DONE && res != SQLITE_ROW)
|
int res = sqlite3_step(stmtHasPathFailed);
|
||||||
throwSQLiteError(db, "querying whether path failed");
|
if (res != SQLITE_DONE && res != SQLITE_ROW)
|
||||||
return res == SQLITE_ROW;
|
throwSQLiteError(db, "querying whether path failed");
|
||||||
|
return res == SQLITE_ROW;
|
||||||
|
} end_retry_sqlite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PathSet LocalStore::queryFailedPaths()
|
PathSet LocalStore::queryFailedPaths()
|
||||||
{
|
{
|
||||||
SQLiteStmtUse use(stmtQueryFailedPaths);
|
retry_sqlite {
|
||||||
|
SQLiteStmtUse use(stmtQueryFailedPaths);
|
||||||
|
|
||||||
PathSet res;
|
PathSet res;
|
||||||
int r;
|
int r;
|
||||||
while ((r = sqlite3_step(stmtQueryFailedPaths)) == SQLITE_ROW) {
|
while ((r = sqlite3_step(stmtQueryFailedPaths)) == SQLITE_ROW) {
|
||||||
const char * s = (const char *) sqlite3_column_text(stmtQueryFailedPaths, 0);
|
const char * s = (const char *) sqlite3_column_text(stmtQueryFailedPaths, 0);
|
||||||
assert(s);
|
assert(s);
|
||||||
res.insert(s);
|
res.insert(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != SQLITE_DONE)
|
if (r != SQLITE_DONE)
|
||||||
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)
|
||||||
{
|
{
|
||||||
SQLiteTxn txn(db);
|
retry_sqlite {
|
||||||
|
SQLiteTxn txn(db);
|
||||||
|
|
||||||
foreach (PathSet::const_iterator, i, paths) {
|
foreach (PathSet::const_iterator, i, paths) {
|
||||||
SQLiteStmtUse use(stmtClearFailedPath);
|
SQLiteStmtUse use(stmtClearFailedPath);
|
||||||
stmtClearFailedPath.bind(*i);
|
stmtClearFailedPath.bind(*i);
|
||||||
if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
|
if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
|
||||||
throwSQLiteError(db, format("clearing failed path `%1%' in database") % *i);
|
throwSQLiteError(db, format("clearing failed path `%1%' in database") % *i);
|
||||||
}
|
}
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
|
} end_retry_sqlite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -766,44 +774,47 @@ ValidPathInfo LocalStore::queryPathInfo(const Path & path)
|
||||||
|
|
||||||
assertStorePath(path);
|
assertStorePath(path);
|
||||||
|
|
||||||
/* Get the path info. */
|
retry_sqlite {
|
||||||
SQLiteStmtUse use1(stmtQueryPathInfo);
|
|
||||||
|
|
||||||
stmtQueryPathInfo.bind(path);
|
/* Get the path info. */
|
||||||
|
SQLiteStmtUse use1(stmtQueryPathInfo);
|
||||||
|
|
||||||
int r = sqlite3_step(stmtQueryPathInfo);
|
stmtQueryPathInfo.bind(path);
|
||||||
if (r == SQLITE_DONE) throw Error(format("path `%1%' is not valid") % path);
|
|
||||||
if (r != SQLITE_ROW) throwSQLiteError(db, "querying path in database");
|
|
||||||
|
|
||||||
info.id = sqlite3_column_int(stmtQueryPathInfo, 0);
|
int r = sqlite3_step(stmtQueryPathInfo);
|
||||||
|
if (r == SQLITE_DONE) throw Error(format("path `%1%' is not valid") % path);
|
||||||
|
if (r != SQLITE_ROW) throwSQLiteError(db, "querying path in database");
|
||||||
|
|
||||||
const char * s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 1);
|
info.id = sqlite3_column_int(stmtQueryPathInfo, 0);
|
||||||
assert(s);
|
|
||||||
info.hash = parseHashField(path, s);
|
|
||||||
|
|
||||||
info.registrationTime = sqlite3_column_int(stmtQueryPathInfo, 2);
|
const char * s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 1);
|
||||||
|
|
||||||
s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
|
|
||||||
if (s) info.deriver = s;
|
|
||||||
|
|
||||||
/* Note that narSize = NULL yields 0. */
|
|
||||||
info.narSize = sqlite3_column_int64(stmtQueryPathInfo, 4);
|
|
||||||
|
|
||||||
/* Get the references. */
|
|
||||||
SQLiteStmtUse use2(stmtQueryReferences);
|
|
||||||
|
|
||||||
stmtQueryReferences.bind(info.id);
|
|
||||||
|
|
||||||
while ((r = sqlite3_step(stmtQueryReferences)) == SQLITE_ROW) {
|
|
||||||
s = (const char *) sqlite3_column_text(stmtQueryReferences, 0);
|
|
||||||
assert(s);
|
assert(s);
|
||||||
info.references.insert(s);
|
info.hash = parseHashField(path, s);
|
||||||
}
|
|
||||||
|
|
||||||
if (r != SQLITE_DONE)
|
info.registrationTime = sqlite3_column_int(stmtQueryPathInfo, 2);
|
||||||
throwSQLiteError(db, format("error getting references of `%1%'") % path);
|
|
||||||
|
|
||||||
return info;
|
s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
|
||||||
|
if (s) info.deriver = s;
|
||||||
|
|
||||||
|
/* Note that narSize = NULL yields 0. */
|
||||||
|
info.narSize = sqlite3_column_int64(stmtQueryPathInfo, 4);
|
||||||
|
|
||||||
|
/* Get the references. */
|
||||||
|
SQLiteStmtUse use2(stmtQueryReferences);
|
||||||
|
|
||||||
|
stmtQueryReferences.bind(info.id);
|
||||||
|
|
||||||
|
while ((r = sqlite3_step(stmtQueryReferences)) == SQLITE_ROW) {
|
||||||
|
s = (const char *) sqlite3_column_text(stmtQueryReferences, 0);
|
||||||
|
assert(s);
|
||||||
|
info.references.insert(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r != SQLITE_DONE)
|
||||||
|
throwSQLiteError(db, format("error getting references of `%1%'") % path);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
} end_retry_sqlite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -834,7 +845,7 @@ unsigned long long LocalStore::queryValidPathId(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LocalStore::isValidPath(const Path & path)
|
bool LocalStore::isValidPath_(const Path & path)
|
||||||
{
|
{
|
||||||
SQLiteStmtUse use(stmtQueryPathInfo);
|
SQLiteStmtUse use(stmtQueryPathInfo);
|
||||||
stmtQueryPathInfo.bind(path);
|
stmtQueryPathInfo.bind(path);
|
||||||
|
@ -845,33 +856,44 @@ bool LocalStore::isValidPath(const Path & path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LocalStore::isValidPath(const Path & path)
|
||||||
|
{
|
||||||
|
retry_sqlite {
|
||||||
|
return isValidPath_(path);
|
||||||
|
} end_retry_sqlite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PathSet LocalStore::queryValidPaths(const PathSet & paths)
|
PathSet LocalStore::queryValidPaths(const PathSet & paths)
|
||||||
{
|
{
|
||||||
PathSet res;
|
retry_sqlite {
|
||||||
foreach (PathSet::const_iterator, i, paths)
|
PathSet res;
|
||||||
if (isValidPath(*i)) res.insert(*i);
|
foreach (PathSet::const_iterator, i, paths)
|
||||||
return res;
|
if (isValidPath_(*i)) res.insert(*i);
|
||||||
|
return res;
|
||||||
|
} end_retry_sqlite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PathSet LocalStore::queryAllValidPaths()
|
PathSet LocalStore::queryAllValidPaths()
|
||||||
{
|
{
|
||||||
SQLiteStmt stmt;
|
retry_sqlite {
|
||||||
stmt.create(db, "select path from ValidPaths");
|
SQLiteStmt stmt;
|
||||||
|
stmt.create(db, "select path from ValidPaths");
|
||||||
|
|
||||||
PathSet res;
|
PathSet res;
|
||||||
|
int r;
|
||||||
|
while ((r = sqlite3_step(stmt)) == SQLITE_ROW) {
|
||||||
|
const char * s = (const char *) sqlite3_column_text(stmt, 0);
|
||||||
|
assert(s);
|
||||||
|
res.insert(s);
|
||||||
|
}
|
||||||
|
|
||||||
int r;
|
if (r != SQLITE_DONE)
|
||||||
while ((r = sqlite3_step(stmt)) == SQLITE_ROW) {
|
throwSQLiteError(db, "error getting valid paths");
|
||||||
const char * s = (const char *) sqlite3_column_text(stmt, 0);
|
|
||||||
assert(s);
|
|
||||||
res.insert(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r != SQLITE_DONE)
|
return res;
|
||||||
throwSQLiteError(db, "error getting valid paths");
|
} end_retry_sqlite;
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -883,10 +905,8 @@ void LocalStore::queryReferences(const Path & path,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
|
void LocalStore::queryReferrers_(const Path & path, PathSet & referrers)
|
||||||
{
|
{
|
||||||
assertStorePath(path);
|
|
||||||
|
|
||||||
SQLiteStmtUse use(stmtQueryReferrers);
|
SQLiteStmtUse use(stmtQueryReferrers);
|
||||||
|
|
||||||
stmtQueryReferrers.bind(path);
|
stmtQueryReferrers.bind(path);
|
||||||
|
@ -903,6 +923,15 @@ void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LocalStore::queryReferrers(const Path & path, PathSet & referrers)
|
||||||
|
{
|
||||||
|
assertStorePath(path);
|
||||||
|
retry_sqlite {
|
||||||
|
queryReferrers_(path, referrers);
|
||||||
|
} end_retry_sqlite;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Path LocalStore::queryDeriver(const Path & path)
|
Path LocalStore::queryDeriver(const Path & path)
|
||||||
{
|
{
|
||||||
return queryPathInfo(path).deriver;
|
return queryPathInfo(path).deriver;
|
||||||
|
@ -913,61 +942,67 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
|
||||||
{
|
{
|
||||||
assertStorePath(path);
|
assertStorePath(path);
|
||||||
|
|
||||||
SQLiteStmtUse use(stmtQueryValidDerivers);
|
retry_sqlite {
|
||||||
stmtQueryValidDerivers.bind(path);
|
SQLiteStmtUse use(stmtQueryValidDerivers);
|
||||||
|
stmtQueryValidDerivers.bind(path);
|
||||||
|
|
||||||
PathSet derivers;
|
PathSet derivers;
|
||||||
int r;
|
int r;
|
||||||
while ((r = sqlite3_step(stmtQueryValidDerivers)) == SQLITE_ROW) {
|
while ((r = sqlite3_step(stmtQueryValidDerivers)) == SQLITE_ROW) {
|
||||||
const char * s = (const char *) sqlite3_column_text(stmtQueryValidDerivers, 1);
|
const char * s = (const char *) sqlite3_column_text(stmtQueryValidDerivers, 1);
|
||||||
assert(s);
|
assert(s);
|
||||||
derivers.insert(s);
|
derivers.insert(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != SQLITE_DONE)
|
if (r != SQLITE_DONE)
|
||||||
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)
|
||||||
{
|
{
|
||||||
SQLiteStmtUse use(stmtQueryDerivationOutputs);
|
retry_sqlite {
|
||||||
stmtQueryDerivationOutputs.bind(queryValidPathId(path));
|
SQLiteStmtUse use(stmtQueryDerivationOutputs);
|
||||||
|
stmtQueryDerivationOutputs.bind(queryValidPathId(path));
|
||||||
|
|
||||||
PathSet outputs;
|
PathSet outputs;
|
||||||
int r;
|
int r;
|
||||||
while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
|
while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
|
||||||
const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 1);
|
const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 1);
|
||||||
assert(s);
|
assert(s);
|
||||||
outputs.insert(s);
|
outputs.insert(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != SQLITE_DONE)
|
if (r != SQLITE_DONE)
|
||||||
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)
|
||||||
{
|
{
|
||||||
SQLiteStmtUse use(stmtQueryDerivationOutputs);
|
retry_sqlite {
|
||||||
stmtQueryDerivationOutputs.bind(queryValidPathId(path));
|
SQLiteStmtUse use(stmtQueryDerivationOutputs);
|
||||||
|
stmtQueryDerivationOutputs.bind(queryValidPathId(path));
|
||||||
|
|
||||||
StringSet outputNames;
|
StringSet outputNames;
|
||||||
int r;
|
int r;
|
||||||
while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
|
while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
|
||||||
const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 0);
|
const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 0);
|
||||||
assert(s);
|
assert(s);
|
||||||
outputNames.insert(s);
|
outputNames.insert(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != SQLITE_DONE)
|
if (r != SQLITE_DONE)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -977,15 +1012,17 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
|
||||||
|
|
||||||
Path prefix = settings.nixStore + "/" + hashPart;
|
Path prefix = settings.nixStore + "/" + hashPart;
|
||||||
|
|
||||||
SQLiteStmtUse use(stmtQueryPathFromHashPart);
|
retry_sqlite {
|
||||||
stmtQueryPathFromHashPart.bind(prefix);
|
SQLiteStmtUse use(stmtQueryPathFromHashPart);
|
||||||
|
stmtQueryPathFromHashPart.bind(prefix);
|
||||||
|
|
||||||
int res = sqlite3_step(stmtQueryPathFromHashPart);
|
int res = sqlite3_step(stmtQueryPathFromHashPart);
|
||||||
if (res == SQLITE_DONE) return "";
|
if (res == SQLITE_DONE) return "";
|
||||||
if (res != SQLITE_ROW) throwSQLiteError(db, "finding path in database");
|
if (res != SQLITE_ROW) throwSQLiteError(db, "finding path in database");
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1229,7 +1266,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
|
||||||
|
|
||||||
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);
|
||||||
|
@ -1643,8 +1680,8 @@ void LocalStore::invalidatePathChecked(const Path & path)
|
||||||
retry_sqlite {
|
retry_sqlite {
|
||||||
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%")
|
||||||
|
|
|
@ -304,6 +304,10 @@ private:
|
||||||
void checkDerivationOutputs(const Path & drvPath, const Derivation & drv);
|
void checkDerivationOutputs(const Path & drvPath, const Derivation & drv);
|
||||||
|
|
||||||
void optimisePath_(OptimiseStats & stats, const Path & path);
|
void optimisePath_(OptimiseStats & stats, const Path & path);
|
||||||
|
|
||||||
|
// Internal versions that are not wrapped in retry_sqlite.
|
||||||
|
bool isValidPath_(const Path & path);
|
||||||
|
void queryReferrers_(const Path & path, PathSet & referrers);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue