about summary refs log tree commit diff
path: root/src/libstore/nar-info-disk-cache.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-02-28T12·44+0100
committerEelco Dolstra <edolstra@gmail.com>2017-02-28T12·44+0100
commit34b12bad597a5d9f67408bebefc1bcb65c27bc4a (patch)
tree328da5f5ebb1b388943c90245480550aa1bf3270 /src/libstore/nar-info-disk-cache.cc
parent80027144ae765544aa96d9c38dc2dd345bcf703d (diff)
NarInfoDiskCache: Handle SQLite busy errors
Diffstat (limited to 'src/libstore/nar-info-disk-cache.cc')
-rw-r--r--src/libstore/nar-info-disk-cache.cc219
1 files changed, 115 insertions, 104 deletions
diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc
index 13b67b81f3..180a936edb 100644
--- a/src/libstore/nar-info-disk-cache.cc
+++ b/src/libstore/nar-info-disk-cache.cc
@@ -106,25 +106,27 @@ public:
             "select * from NARs where cache = ? and hashPart = ? and ((present = 0 and timestamp > ?) or (present = 1 and timestamp > ?))");
 
         /* Periodically purge expired entries from the database. */
-        auto now = time(0);
-
-        SQLiteStmt queryLastPurge(state->db, "select value from LastPurge");
-        auto queryLastPurge_(queryLastPurge.use());
-
-        if (!queryLastPurge_.next() || queryLastPurge_.getInt(0) < now - purgeInterval) {
-            SQLiteStmt(state->db,
-                "delete from NARs where ((present = 0 and timestamp < ?) or (present = 1 and timestamp < ?))")
-                .use()
-                (now - ttlNegative)
-                (now - ttlPositive)
-                .exec();
-
-            debug("deleted %d entries from the NAR info disk cache", sqlite3_changes(state->db));
-
-            SQLiteStmt(state->db,
-                "insert or replace into LastPurge(dummy, value) values ('', ?)")
-                .use()(now).exec();
-        }
+        retrySQLite<void>([&]() {
+            auto now = time(0);
+
+            SQLiteStmt queryLastPurge(state->db, "select value from LastPurge");
+            auto queryLastPurge_(queryLastPurge.use());
+
+            if (!queryLastPurge_.next() || queryLastPurge_.getInt(0) < now - purgeInterval) {
+                SQLiteStmt(state->db,
+                    "delete from NARs where ((present = 0 and timestamp < ?) or (present = 1 and timestamp < ?))")
+                    .use()
+                    (now - ttlNegative)
+                    (now - ttlPositive)
+                    .exec();
+
+                debug("deleted %d entries from the NAR info disk cache", sqlite3_changes(state->db));
+
+                SQLiteStmt(state->db,
+                    "insert or replace into LastPurge(dummy, value) values ('', ?)")
+                    .use()(now).exec();
+            }
+        });
     }
 
     Cache & getCache(State & state, const std::string & uri)
@@ -136,114 +138,123 @@ public:
 
     void createCache(const std::string & uri, const Path & storeDir, bool wantMassQuery, int priority) override
     {
-        auto state(_state.lock());
+        retrySQLite<void>([&]() {
+            auto state(_state.lock());
 
-        // FIXME: race
+            // FIXME: race
 
-        state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority).exec();
-        assert(sqlite3_changes(state->db) == 1);
-        state->caches[uri] = Cache{(int) sqlite3_last_insert_rowid(state->db), storeDir, wantMassQuery, priority};
+            state->insertCache.use()(uri)(time(0))(storeDir)(wantMassQuery)(priority).exec();
+            assert(sqlite3_changes(state->db) == 1);
+            state->caches[uri] = Cache{(int) sqlite3_last_insert_rowid(state->db), storeDir, wantMassQuery, priority};
+        });
     }
 
     bool cacheExists(const std::string & uri,
         bool & wantMassQuery, int & priority) override
     {
-        auto state(_state.lock());
+        return retrySQLite<bool>([&]() {
+            auto state(_state.lock());
 
-        auto i = state->caches.find(uri);
-        if (i == state->caches.end()) {
-            auto queryCache(state->queryCache.use()(uri));
-            if (!queryCache.next()) return false;
-            state->caches.emplace(uri,
-                Cache{(int) queryCache.getInt(0), queryCache.getStr(1), queryCache.getInt(2) != 0, (int) queryCache.getInt(3)});
-        }
+            auto i = state->caches.find(uri);
+            if (i == state->caches.end()) {
+                auto queryCache(state->queryCache.use()(uri));
+                if (!queryCache.next()) return false;
+                state->caches.emplace(uri,
+                    Cache{(int) queryCache.getInt(0), queryCache.getStr(1), queryCache.getInt(2) != 0, (int) queryCache.getInt(3)});
+            }
 
-        auto & cache(getCache(*state, uri));
+            auto & cache(getCache(*state, uri));
 
-        wantMassQuery = cache.wantMassQuery;
-        priority = cache.priority;
+            wantMassQuery = cache.wantMassQuery;
+            priority = cache.priority;
 
-        return true;
+            return true;
+        });
     }
 
     std::pair<Outcome, std::shared_ptr<NarInfo>> lookupNarInfo(
         const std::string & uri, const std::string & hashPart) override
     {
-        auto state(_state.lock());
+        return retrySQLite<std::pair<Outcome, std::shared_ptr<NarInfo>>>(
+            [&]() -> std::pair<Outcome, std::shared_ptr<NarInfo>> {
+            auto state(_state.lock());
+
+            auto & cache(getCache(*state, uri));
 
-        auto & cache(getCache(*state, uri));
-
-        auto now = time(0);
-
-        auto queryNAR(state->queryNAR.use()
-            (cache.id)
-            (hashPart)
-            (now - ttlNegative)
-            (now - ttlPositive));
-
-        if (!queryNAR.next())
-            return {oUnknown, 0};
-
-        if (!queryNAR.getInt(13))
-            return {oInvalid, 0};
-
-        auto narInfo = make_ref<NarInfo>();
-
-        auto namePart = queryNAR.getStr(2);
-        narInfo->path = cache.storeDir + "/" +
-            hashPart + (namePart.empty() ? "" : "-" + namePart);
-        narInfo->url = queryNAR.getStr(3);
-        narInfo->compression = queryNAR.getStr(4);
-        if (!queryNAR.isNull(5))
-            narInfo->fileHash = parseHash(queryNAR.getStr(5));
-        narInfo->fileSize = queryNAR.getInt(6);
-        narInfo->narHash = parseHash(queryNAR.getStr(7));
-        narInfo->narSize = queryNAR.getInt(8);
-        for (auto & r : tokenizeString<Strings>(queryNAR.getStr(9), " "))
-            narInfo->references.insert(cache.storeDir + "/" + r);
-        if (!queryNAR.isNull(10))
-            narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(10);
-        for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(11), " "))
-            narInfo->sigs.insert(sig);
-
-        return {oValid, narInfo};
+            auto now = time(0);
+
+            auto queryNAR(state->queryNAR.use()
+                (cache.id)
+                (hashPart)
+                (now - ttlNegative)
+                (now - ttlPositive));
+
+            if (!queryNAR.next())
+                return {oUnknown, 0};
+
+            if (!queryNAR.getInt(13))
+                return {oInvalid, 0};
+
+            auto narInfo = make_ref<NarInfo>();
+
+            auto namePart = queryNAR.getStr(2);
+            narInfo->path = cache.storeDir + "/" +
+                hashPart + (namePart.empty() ? "" : "-" + namePart);
+            narInfo->url = queryNAR.getStr(3);
+            narInfo->compression = queryNAR.getStr(4);
+            if (!queryNAR.isNull(5))
+                narInfo->fileHash = parseHash(queryNAR.getStr(5));
+            narInfo->fileSize = queryNAR.getInt(6);
+            narInfo->narHash = parseHash(queryNAR.getStr(7));
+            narInfo->narSize = queryNAR.getInt(8);
+            for (auto & r : tokenizeString<Strings>(queryNAR.getStr(9), " "))
+                narInfo->references.insert(cache.storeDir + "/" + r);
+            if (!queryNAR.isNull(10))
+                narInfo->deriver = cache.storeDir + "/" + queryNAR.getStr(10);
+            for (auto & sig : tokenizeString<Strings>(queryNAR.getStr(11), " "))
+                narInfo->sigs.insert(sig);
+
+            return {oValid, narInfo};
+        });
     }
 
     void upsertNarInfo(
         const std::string & uri, const std::string & hashPart,
         std::shared_ptr<ValidPathInfo> info) override
     {
-        auto state(_state.lock());
-
-        auto & cache(getCache(*state, uri));
-
-        if (info) {
-
-            auto narInfo = std::dynamic_pointer_cast<NarInfo>(info);
-
-            assert(hashPart == storePathToHash(info->path));
-
-            state->insertNAR.use()
-                (cache.id)
-                (hashPart)
-                (storePathToName(info->path))
-                (narInfo ? narInfo->url : "", narInfo != 0)
-                (narInfo ? narInfo->compression : "", narInfo != 0)
-                (narInfo && narInfo->fileHash ? narInfo->fileHash.to_string() : "", narInfo && narInfo->fileHash)
-                (narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize)
-                (info->narHash.to_string())
-                (info->narSize)
-                (concatStringsSep(" ", info->shortRefs()))
-                (info->deriver != "" ? baseNameOf(info->deriver) : "", info->deriver != "")
-                (concatStringsSep(" ", info->sigs))
-                (time(0)).exec();
-
-        } else {
-            state->insertMissingNAR.use()
-                (cache.id)
-                (hashPart)
-                (time(0)).exec();
-        }
+        retrySQLite<void>([&]() {
+            auto state(_state.lock());
+
+            auto & cache(getCache(*state, uri));
+
+            if (info) {
+
+                auto narInfo = std::dynamic_pointer_cast<NarInfo>(info);
+
+                assert(hashPart == storePathToHash(info->path));
+
+                state->insertNAR.use()
+                    (cache.id)
+                    (hashPart)
+                    (storePathToName(info->path))
+                    (narInfo ? narInfo->url : "", narInfo != 0)
+                    (narInfo ? narInfo->compression : "", narInfo != 0)
+                    (narInfo && narInfo->fileHash ? narInfo->fileHash.to_string() : "", narInfo && narInfo->fileHash)
+                    (narInfo ? narInfo->fileSize : 0, narInfo != 0 && narInfo->fileSize)
+                    (info->narHash.to_string())
+                    (info->narSize)
+                    (concatStringsSep(" ", info->shortRefs()))
+                    (info->deriver != "" ? baseNameOf(info->deriver) : "", info->deriver != "")
+                    (concatStringsSep(" ", info->sigs))
+                    (time(0)).exec();
+
+            } else {
+                state->insertMissingNAR.use()
+                    (cache.id)
+                    (hashPart)
+                    (time(0)).exec();
+            }
+        });
     }
 };