aboutsummaryrefslogtreecommitdiff
path: root/src/libfetchers/cache.cc
diff options
context:
space:
mode:
authorCarlo Nucera <carlo.nucera@protonmail.com>2020-05-28 10:58:22 -0400
committerCarlo Nucera <carlo.nucera@protonmail.com>2020-05-28 10:58:22 -0400
commit4f597fb901dec55a86a2b29a122b9007177b2358 (patch)
treec89fff8fb0670fb55eb0c2593b6b48575a2ef914 /src/libfetchers/cache.cc
parent87b32bab05ff91981c8847d66cd5502feb44f3b5 (diff)
parentf60ce4fa207a210e23a1142d3a8ead611526e6e1 (diff)
Merge branch 'master' of github.com:NixOS/nix into enum-class
Diffstat (limited to 'src/libfetchers/cache.cc')
-rw-r--r--src/libfetchers/cache.cc121
1 files changed, 121 insertions, 0 deletions
diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc
new file mode 100644
index 000000000..e1c7f3dee
--- /dev/null
+++ b/src/libfetchers/cache.cc
@@ -0,0 +1,121 @@
+#include "cache.hh"
+#include "sqlite.hh"
+#include "sync.hh"
+#include "store-api.hh"
+
+#include <nlohmann/json.hpp>
+
+namespace nix::fetchers {
+
+static const char * schema = R"sql(
+
+create table if not exists Cache (
+ input text not null,
+ info text not null,
+ path text not null,
+ immutable integer not null,
+ timestamp integer not null,
+ primary key (input)
+);
+)sql";
+
+struct CacheImpl : Cache
+{
+ struct State
+ {
+ SQLite db;
+ SQLiteStmt add, lookup;
+ };
+
+ Sync<State> _state;
+
+ CacheImpl()
+ {
+ auto state(_state.lock());
+
+ auto dbPath = getCacheDir() + "/nix/fetcher-cache-v1.sqlite";
+ createDirs(dirOf(dbPath));
+
+ state->db = SQLite(dbPath);
+ state->db.isCache();
+ state->db.exec(schema);
+
+ state->add.create(state->db,
+ "insert or replace into Cache(input, info, path, immutable, timestamp) values (?, ?, ?, ?, ?)");
+
+ state->lookup.create(state->db,
+ "select info, path, immutable, timestamp from Cache where input = ?");
+ }
+
+ void add(
+ ref<Store> store,
+ const Attrs & inAttrs,
+ const Attrs & infoAttrs,
+ const StorePath & storePath,
+ bool immutable) override
+ {
+ _state.lock()->add.use()
+ (attrsToJson(inAttrs).dump())
+ (attrsToJson(infoAttrs).dump())
+ (store->printStorePath(storePath))
+ (immutable)
+ (time(0)).exec();
+ }
+
+ std::optional<std::pair<Attrs, StorePath>> lookup(
+ ref<Store> store,
+ const Attrs & inAttrs) override
+ {
+ if (auto res = lookupExpired(store, inAttrs)) {
+ if (!res->expired)
+ return std::make_pair(std::move(res->infoAttrs), std::move(res->storePath));
+ debug("ignoring expired cache entry '%s'",
+ attrsToJson(inAttrs).dump());
+ }
+ return {};
+ }
+
+ std::optional<Result> lookupExpired(
+ ref<Store> store,
+ const Attrs & inAttrs) override
+ {
+ auto state(_state.lock());
+
+ auto inAttrsJson = attrsToJson(inAttrs).dump();
+
+ auto stmt(state->lookup.use()(inAttrsJson));
+ if (!stmt.next()) {
+ debug("did not find cache entry for '%s'", inAttrsJson);
+ return {};
+ }
+
+ auto infoJson = stmt.getStr(0);
+ auto storePath = store->parseStorePath(stmt.getStr(1));
+ auto immutable = stmt.getInt(2) != 0;
+ auto timestamp = stmt.getInt(3);
+
+ store->addTempRoot(storePath);
+ if (!store->isValidPath(storePath)) {
+ // FIXME: we could try to substitute 'storePath'.
+ debug("ignoring disappeared cache entry '%s'", inAttrsJson);
+ return {};
+ }
+
+ debug("using cache entry '%s' -> '%s', '%s'",
+ inAttrsJson, infoJson, store->printStorePath(storePath));
+
+ return Result {
+ .expired = !immutable && (settings.tarballTtl.get() == 0 || timestamp + settings.tarballTtl < time(0)),
+ .infoAttrs = jsonToAttrs(nlohmann::json::parse(infoJson)),
+ .storePath = std::move(storePath)
+ };
+ }
+};
+
+ref<Cache> getCache()
+{
+ static auto cache = std::make_shared<CacheImpl>();
+ return ref<Cache>(cache);
+}
+
+}