From ca580bec35ea4d1984e36864158d7be99cfcb34b Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 17 Oct 2017 21:15:33 +0200 Subject: BinaryCacheStore: Support local caching of NARs This speeds up commands like "nix cat-store". For example: $ time nix cat-store --store https://cache.nixos.org?local-nar-cache=/tmp/nar-cache /nix/store/i60yncmq6w9dyv37zd2k454g0fkl3arl-systemd-234/etc/udev/udev.conf real 0m4.336s $ time nix cat-store --store https://cache.nixos.org?local-nar-cache=/tmp/nar-cache /nix/store/i60yncmq6w9dyv37zd2k454g0fkl3arl-systemd-234/etc/udev/udev.conf real 0m0.045s The primary motivation is to allow hydra-server to serve files from S3 binary caches. Previously Hydra had a hack to do "nix-store -r ", but that fetches the entire closure so is prohibitively expensive. There is no garbage collection of the NAR cache yet. Also, the entire NAR is read when accessing a single member file. We could generate the NAR listing to provide random access. Note: the NAR cache is indexed by the store path hash, not the content hash, so NAR caches should not be shared between binary caches, unless you're sure that all your builds are binary-reproducible. --- src/libstore/binary-cache-store.cc | 2 +- src/libstore/binary-cache-store.hh | 1 + src/libstore/remote-fs-accessor.cc | 22 +++++++++++++++++++--- src/libstore/remote-fs-accessor.hh | 5 ++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index 9d497110f621..f1179f1890a0 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -319,7 +319,7 @@ Path BinaryCacheStore::addTextToStore(const string & name, const string & s, ref BinaryCacheStore::getFSAccessor() { - return make_ref(ref(shared_from_this())); + return make_ref(ref(shared_from_this()), localNarCache); } std::shared_ptr BinaryCacheStore::getBuildLog(const Path & path) diff --git a/src/libstore/binary-cache-store.hh b/src/libstore/binary-cache-store.hh index f9c1c2cbe8a8..d3b0e0bd9332 100644 --- a/src/libstore/binary-cache-store.hh +++ b/src/libstore/binary-cache-store.hh @@ -18,6 +18,7 @@ public: const Setting compression{this, "xz", "compression", "NAR compression method ('xz', 'bzip2', or 'none')"}; const Setting writeNARListing{this, false, "write-nar-listing", "whether to write a JSON file listing the files in each NAR"}; const Setting secretKeyFile{this, "", "secret-key", "path to secret key used to sign the binary cache"}; + const Setting localNarCache{this, "", "local-nar-cache", "path to a local cache of NARs"}; private: diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc index 098151f8c0f6..da4e30b22633 100644 --- a/src/libstore/remote-fs-accessor.cc +++ b/src/libstore/remote-fs-accessor.cc @@ -3,10 +3,12 @@ namespace nix { - -RemoteFSAccessor::RemoteFSAccessor(ref store) +RemoteFSAccessor::RemoteFSAccessor(ref store, const Path & cacheDir) : store(store) + , cacheDir(cacheDir) { + if (cacheDir != "") + createDirs(cacheDir); } std::pair, Path> RemoteFSAccessor::fetch(const Path & path_) @@ -23,7 +25,21 @@ std::pair, Path> RemoteFSAccessor::fetch(const Path & path_) if (i != nars.end()) return {i->second, restPath}; StringSink sink; - store->narFromPath(storePath, sink); + + Path cacheFile = cacheDir != "" ? fmt("%s/%s.nar", cacheDir, storePathToHash(storePath)) : ""; + + try { + if (cacheFile != "") + *sink.s = nix::readFile(cacheFile); + } catch (SysError &) { } + + if (sink.s->empty()) { + store->narFromPath(storePath, sink); + + if (cacheFile != "") + /* FIXME: do this asynchronously. */ + writeFile(cacheFile, *sink.s); + } auto accessor = makeNarAccessor(sink.s); nars.emplace(storePath, accessor); diff --git a/src/libstore/remote-fs-accessor.hh b/src/libstore/remote-fs-accessor.hh index df8b7b16291e..d359ecc9c871 100644 --- a/src/libstore/remote-fs-accessor.hh +++ b/src/libstore/remote-fs-accessor.hh @@ -12,13 +12,16 @@ class RemoteFSAccessor : public FSAccessor std::map> nars; + Path cacheDir; + std::pair, Path> fetch(const Path & path_); friend class BinaryCacheStore; public: - RemoteFSAccessor(ref store); + RemoteFSAccessor(ref store, + const /* FIXME: use std::optional */ Path & cacheDir = ""); Stat stat(const Path & path) override; -- cgit 1.4.1