about summary refs log tree commit diff
path: root/src/libstore/local-store.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-16T13·58+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2013-10-16T13·58+0200
commita737f51fd96be2866a33eb67732e034bcc65a659 (patch)
tree2e46e11fbc12c0fcbf2025aabba1486d8dd4c91f /src/libstore/local-store.cc
parentff02f5336cd0cff0e97fbcf3c54b5b23827702d6 (diff)
Retry all SQLite operations
To deal with SQLITE_PROTOCOL, we also need to retry read-only
operations.
Diffstat (limited to 'src/libstore/local-store.cc')
-rw-r--r--src/libstore/local-store.cc293
1 files changed, 165 insertions, 128 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index 9f324608c2..24d6acc2f4 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -692,56 +692,64 @@ void LocalStore::addReference(unsigned long long referrer, unsigned long long re
 
 void LocalStore::registerFailedPath(const Path & path)
 {
-    SQLiteStmtUse use(stmtRegisterFailedPath);
-    stmtRegisterFailedPath.bind(path);
-    stmtRegisterFailedPath.bind(time(0));
-    if (sqlite3_step(stmtRegisterFailedPath) != SQLITE_DONE)
-        throwSQLiteError(db, format("registering failed path `%1%'") % path);
+    retry_sqlite {
+        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)
 {
-    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;
+    retry_sqlite {
+        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()
 {
-    SQLiteStmtUse use(stmtQueryFailedPaths);
-
-    PathSet res;
-    int r;
-    while ((r = sqlite3_step(stmtQueryFailedPaths)) == SQLITE_ROW) {
-        const char * s = (const char *) sqlite3_column_text(stmtQueryFailedPaths, 0);
-        assert(s);
-        res.insert(s);
-    }
+    retry_sqlite {
+        SQLiteStmtUse use(stmtQueryFailedPaths);
+
+        PathSet res;
+        int r;
+        while ((r = sqlite3_step(stmtQueryFailedPaths)) == SQLITE_ROW) {
+            const char * s = (const char *) sqlite3_column_text(stmtQueryFailedPaths, 0);
+            assert(s);
+            res.insert(s);
+        }
 
-    if (r != SQLITE_DONE)
-        throwSQLiteError(db, "error querying failed paths");
+        if (r != SQLITE_DONE)
+            throwSQLiteError(db, "error querying failed paths");
 
-    return res;
+        return res;
+    } end_retry_sqlite;
 }
 
 
 void LocalStore::clearFailedPaths(const PathSet & paths)
 {
-    SQLiteTxn txn(db);
+    retry_sqlite {
+        SQLiteTxn txn(db);
 
-    foreach (PathSet::const_iterator, i, paths) {
-        SQLiteStmtUse use(stmtClearFailedPath);
-        stmtClearFailedPath.bind(*i);
-        if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
-            throwSQLiteError(db, format("clearing failed path `%1%' in database") % *i);
-    }
+        foreach (PathSet::const_iterator, i, paths) {
+            SQLiteStmtUse use(stmtClearFailedPath);
+            stmtClearFailedPath.bind(*i);
+            if (sqlite3_step(stmtClearFailedPath) != SQLITE_DONE)
+                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);
 
-    /* Get the path info. */
-    SQLiteStmtUse use1(stmtQueryPathInfo);
+    retry_sqlite {
 
-    stmtQueryPathInfo.bind(path);
+        /* Get the path info. */
+        SQLiteStmtUse use1(stmtQueryPathInfo);
 
-    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");
+        stmtQueryPathInfo.bind(path);
 
-    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);
-    assert(s);
-    info.hash = parseHashField(path, s);
+        info.id = sqlite3_column_int(stmtQueryPathInfo, 0);
 
-    info.registrationTime = sqlite3_column_int(stmtQueryPathInfo, 2);
+        const char * s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 1);
+        assert(s);
+        info.hash = parseHashField(path, s);
 
-    s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
-    if (s) info.deriver = s;
+        info.registrationTime = sqlite3_column_int(stmtQueryPathInfo, 2);
 
-    /* Note that narSize = NULL yields 0. */
-    info.narSize = sqlite3_column_int64(stmtQueryPathInfo, 4);
+        s = (const char *) sqlite3_column_text(stmtQueryPathInfo, 3);
+        if (s) info.deriver = s;
 
-    /* Get the references. */
-    SQLiteStmtUse use2(stmtQueryReferences);
+        /* Note that narSize = NULL yields 0. */
+        info.narSize = sqlite3_column_int64(stmtQueryPathInfo, 4);
 
-    stmtQueryReferences.bind(info.id);
+        /* Get the references. */
+        SQLiteStmtUse use2(stmtQueryReferences);
 
-    while ((r = sqlite3_step(stmtQueryReferences)) == SQLITE_ROW) {
-        s = (const char *) sqlite3_column_text(stmtQueryReferences, 0);
-        assert(s);
-        info.references.insert(s);
-    }
+        stmtQueryReferences.bind(info.id);
 
-    if (r != SQLITE_DONE)
-        throwSQLiteError(db, format("error getting references of `%1%'") % path);
+        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;
+        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);
     stmtQueryPathInfo.bind(path);
@@ -845,33 +856,44 @@ bool LocalStore::isValidPath(const Path & path)
 }
 
 
-PathSet LocalStore::queryValidPaths(const PathSet & paths)
+bool LocalStore::isValidPath(const Path & path)
 {
-    PathSet res;
-    foreach (PathSet::const_iterator, i, paths)
-        if (isValidPath(*i)) res.insert(*i);
-    return res;
+    retry_sqlite {
+        return isValidPath_(path);
+    } end_retry_sqlite;
 }
 
 
-PathSet LocalStore::queryAllValidPaths()
+PathSet LocalStore::queryValidPaths(const PathSet & paths)
 {
-    SQLiteStmt stmt;
-    stmt.create(db, "select path from ValidPaths");
+    retry_sqlite {
+        PathSet res;
+        foreach (PathSet::const_iterator, i, paths)
+            if (isValidPath_(*i)) res.insert(*i);
+        return res;
+    } end_retry_sqlite;
+}
 
-    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);
-    }
+PathSet LocalStore::queryAllValidPaths()
+{
+    retry_sqlite {
+        SQLiteStmt stmt;
+        stmt.create(db, "select path from ValidPaths");
+
+        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);
+        }
 
-    if (r != SQLITE_DONE)
-        throwSQLiteError(db, "error getting valid paths");
+        if (r != SQLITE_DONE)
+            throwSQLiteError(db, "error getting valid paths");
 
-    return res;
+        return res;
+    } end_retry_sqlite;
 }
 
 
@@ -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);
 
     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)
 {
     return queryPathInfo(path).deriver;
@@ -913,61 +942,67 @@ PathSet LocalStore::queryValidDerivers(const Path & path)
 {
     assertStorePath(path);
 
-    SQLiteStmtUse use(stmtQueryValidDerivers);
-    stmtQueryValidDerivers.bind(path);
-
-    PathSet derivers;
-    int r;
-    while ((r = sqlite3_step(stmtQueryValidDerivers)) == SQLITE_ROW) {
-        const char * s = (const char *) sqlite3_column_text(stmtQueryValidDerivers, 1);
-        assert(s);
-        derivers.insert(s);
-    }
+    retry_sqlite {
+        SQLiteStmtUse use(stmtQueryValidDerivers);
+        stmtQueryValidDerivers.bind(path);
+
+        PathSet derivers;
+        int r;
+        while ((r = sqlite3_step(stmtQueryValidDerivers)) == SQLITE_ROW) {
+            const char * s = (const char *) sqlite3_column_text(stmtQueryValidDerivers, 1);
+            assert(s);
+            derivers.insert(s);
+        }
 
-    if (r != SQLITE_DONE)
-        throwSQLiteError(db, format("error getting valid derivers of `%1%'") % path);
+        if (r != SQLITE_DONE)
+            throwSQLiteError(db, format("error getting valid derivers of `%1%'") % path);
 
-    return derivers;
+        return derivers;
+    } end_retry_sqlite;
 }
 
 
 PathSet LocalStore::queryDerivationOutputs(const Path & path)
 {
-    SQLiteStmtUse use(stmtQueryDerivationOutputs);
-    stmtQueryDerivationOutputs.bind(queryValidPathId(path));
-
-    PathSet outputs;
-    int r;
-    while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
-        const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 1);
-        assert(s);
-        outputs.insert(s);
-    }
+    retry_sqlite {
+        SQLiteStmtUse use(stmtQueryDerivationOutputs);
+        stmtQueryDerivationOutputs.bind(queryValidPathId(path));
+
+        PathSet outputs;
+        int r;
+        while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
+            const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 1);
+            assert(s);
+            outputs.insert(s);
+        }
 
-    if (r != SQLITE_DONE)
-        throwSQLiteError(db, format("error getting outputs of `%1%'") % path);
+        if (r != SQLITE_DONE)
+            throwSQLiteError(db, format("error getting outputs of `%1%'") % path);
 
-    return outputs;
+        return outputs;
+    } end_retry_sqlite;
 }
 
 
 StringSet LocalStore::queryDerivationOutputNames(const Path & path)
 {
-    SQLiteStmtUse use(stmtQueryDerivationOutputs);
-    stmtQueryDerivationOutputs.bind(queryValidPathId(path));
-
-    StringSet outputNames;
-    int r;
-    while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
-        const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 0);
-        assert(s);
-        outputNames.insert(s);
-    }
+    retry_sqlite {
+        SQLiteStmtUse use(stmtQueryDerivationOutputs);
+        stmtQueryDerivationOutputs.bind(queryValidPathId(path));
+
+        StringSet outputNames;
+        int r;
+        while ((r = sqlite3_step(stmtQueryDerivationOutputs)) == SQLITE_ROW) {
+            const char * s = (const char *) sqlite3_column_text(stmtQueryDerivationOutputs, 0);
+            assert(s);
+            outputNames.insert(s);
+        }
 
-    if (r != SQLITE_DONE)
-        throwSQLiteError(db, format("error getting output names of `%1%'") % path);
+        if (r != SQLITE_DONE)
+            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;
 
-    SQLiteStmtUse use(stmtQueryPathFromHashPart);
-    stmtQueryPathFromHashPart.bind(prefix);
+    retry_sqlite {
+        SQLiteStmtUse use(stmtQueryPathFromHashPart);
+        stmtQueryPathFromHashPart.bind(prefix);
 
-    int res = sqlite3_step(stmtQueryPathFromHashPart);
-    if (res == SQLITE_DONE) return "";
-    if (res != SQLITE_ROW) throwSQLiteError(db, "finding path in database");
+        int res = sqlite3_step(stmtQueryPathFromHashPart);
+        if (res == SQLITE_DONE) return "";
+        if (res != SQLITE_ROW) throwSQLiteError(db, "finding path in database");
 
-    const char * s = (const char *) sqlite3_column_text(stmtQueryPathFromHashPart, 0);
-    return s && prefix.compare(0, prefix.size(), s, prefix.size()) == 0 ? s : "";
+        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;
 }
 
 
@@ -1229,7 +1266,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos)
 
         foreach (ValidPathInfos::const_iterator, i, infos) {
             assert(i->hash.type == htSHA256);
-            if (isValidPath(i->path))
+            if (isValidPath_(i->path))
                 updatePathInfo(*i);
             else
                 addValidPath(*i);
@@ -1643,8 +1680,8 @@ void LocalStore::invalidatePathChecked(const Path & path)
     retry_sqlite {
         SQLiteTxn txn(db);
 
-        if (isValidPath(path)) {
-            PathSet referrers; queryReferrers(path, referrers);
+        if (isValidPath_(path)) {
+            PathSet referrers; queryReferrers_(path, referrers);
             referrers.erase(path); /* ignore self-references */
             if (!referrers.empty())
                 throw PathInUse(format("cannot delete path `%1%' because it is in use by %2%")