diff --git a/src/libstore/binary-cache-store.cc b/src/libstore/binary-cache-store.cc index b5a47c6ce0f..f164f86a0a9 100644 --- a/src/libstore/binary-cache-store.cc +++ b/src/libstore/binary-cache-store.cc @@ -13,6 +13,7 @@ #include "nix/util/callback.hh" #include "nix/util/signals.hh" #include "nix/util/archive.hh" +#include "nix/store/nar-cache.hh" #include #include @@ -26,6 +27,7 @@ namespace nix { BinaryCacheStore::BinaryCacheStore(Config & config) : config{config} + , narCache{config.localNarCache.get() ? std::make_shared(*config.localNarCache.get()) : nullptr} { if (config.secretKeyFile != "") signers.push_back(std::make_unique(SecretKey{readFile(config.secretKeyFile)})); @@ -552,7 +554,7 @@ void BinaryCacheStore::registerDrvOutput(const Realisation & info) ref BinaryCacheStore::getRemoteFSAccessor(bool requireValidPath) { - return make_ref(ref(shared_from_this()), requireValidPath, config.localNarCache); + return make_ref(ref(shared_from_this()), requireValidPath, narCache); } ref BinaryCacheStore::getFSAccessor(bool requireValidPath) diff --git a/src/libstore/include/nix/store/binary-cache-store.hh b/src/libstore/include/nix/store/binary-cache-store.hh index 80c0bc9d0cb..7c9ed875b61 100644 --- a/src/libstore/include/nix/store/binary-cache-store.hh +++ b/src/libstore/include/nix/store/binary-cache-store.hh @@ -12,6 +12,7 @@ namespace nix { struct NarInfo; +class NarCache; class RemoteFSAccessor; struct BinaryCacheStoreConfig : virtual StoreConfig @@ -89,6 +90,8 @@ protected: constexpr const static std::string cacheInfoFile = "nix-cache-info"; + std::shared_ptr narCache; + BinaryCacheStore(Config &); /** diff --git a/src/libstore/include/nix/store/meson.build b/src/libstore/include/nix/store/meson.build index c7026818ea7..405d19b1c6b 100644 --- a/src/libstore/include/nix/store/meson.build +++ b/src/libstore/include/nix/store/meson.build @@ -56,6 +56,7 @@ headers = [ config_pub_h ] + files( 'machines.hh', 'make-content-addressed.hh', 'names.hh', + 'nar-cache.hh', 'nar-info-disk-cache.hh', 'nar-info.hh', 'outputs-spec.hh', diff --git a/src/libstore/include/nix/store/nar-cache.hh b/src/libstore/include/nix/store/nar-cache.hh new file mode 100644 index 00000000000..15cb74ca575 --- /dev/null +++ b/src/libstore/include/nix/store/nar-cache.hh @@ -0,0 +1,33 @@ +#pragma once + +#include "nix/util/hash.hh" +#include "nix/util/nar-accessor.hh" + +#include + +namespace nix { + +class NarCache +{ + const std::filesystem::path cacheDir; + + std::filesystem::path makeCacheFile(const Hash & narHash, const std::string & ext); + +public: + + NarCache(std::filesystem::path cacheDir); + + void upsertNar(const Hash & narHash, Source & source); + + void upsertNarListing(const Hash & narHash, std::string_view narListingData); + + // FIXME: use a sink. + std::optional getNar(const Hash & narHash); + + // FIXME: use a sink. + GetNarBytes getNarBytes(const Hash & narHash); + + std::optional getNarListing(const Hash & narHash); +}; + +} // namespace nix diff --git a/src/libstore/include/nix/store/remote-fs-accessor.hh b/src/libstore/include/nix/store/remote-fs-accessor.hh index 479a7393207..ed0d244ba33 100644 --- a/src/libstore/include/nix/store/remote-fs-accessor.hh +++ b/src/libstore/include/nix/store/remote-fs-accessor.hh @@ -7,6 +7,8 @@ namespace nix { +struct NarCache; + class RemoteFSAccessor : public SourceAccessor { ref store; @@ -25,7 +27,7 @@ class RemoteFSAccessor : public SourceAccessor bool requireValidPath; - std::optional cacheDir; + std::shared_ptr narCache; std::pair, CanonPath> fetch(const CanonPath & path); @@ -38,8 +40,7 @@ public: */ std::shared_ptr accessObject(const StorePath & path); - RemoteFSAccessor( - ref store, bool requireValidPath = true, std::optional cacheDir = {}); + RemoteFSAccessor(ref store, bool requireValidPath = true, std::shared_ptr narCache = {}); std::optional maybeLstat(const CanonPath & path) override; diff --git a/src/libstore/meson.build b/src/libstore/meson.build index 0e5a9cb7bb4..99db3c5ef65 100644 --- a/src/libstore/meson.build +++ b/src/libstore/meson.build @@ -318,6 +318,7 @@ sources = files( 'make-content-addressed.cc', 'misc.cc', 'names.cc', + 'nar-cache.cc', 'nar-info-disk-cache.cc', 'nar-info.cc', 'optimise-store.cc', diff --git a/src/libstore/nar-cache.cc b/src/libstore/nar-cache.cc new file mode 100644 index 00000000000..5373676025d --- /dev/null +++ b/src/libstore/nar-cache.cc @@ -0,0 +1,64 @@ +#include "nix/store/nar-cache.hh" +#include "nix/util/file-system.hh" + +#include +#include +#include + +namespace nix { + +NarCache::NarCache(std::filesystem::path cacheDir_) + : cacheDir(std::move(cacheDir_)) +{ + assert(!cacheDir.empty()); + createDirs(cacheDir); +} + +std::filesystem::path NarCache::makeCacheFile(const Hash & narHash, const std::string & ext) +{ + return (cacheDir / narHash.to_string(HashFormat::Nix32, false)) + "." + ext; +} + +void NarCache::upsertNar(const Hash & narHash, Source & source) +{ + try { + /* FIXME: do this asynchronously. */ + writeFile(makeCacheFile(narHash, "nar"), source); + } catch (SystemError &) { + ignoreExceptionExceptInterrupt(); + } +} + +void NarCache::upsertNarListing(const Hash & narHash, std::string_view narListingData) +{ + try { + writeFile(makeCacheFile(narHash, "ls"), narListingData); + } catch (SystemError &) { + ignoreExceptionExceptInterrupt(); + } +} + +std::optional NarCache::getNar(const Hash & narHash) +{ + try { + return nix::readFile(makeCacheFile(narHash, "nar")); + } catch (SystemError &) { + return std::nullopt; + } +} + +GetNarBytes NarCache::getNarBytes(const Hash & narHash) +{ + return seekableGetNarBytes(makeCacheFile(narHash, "nar")); +} + +std::optional NarCache::getNarListing(const Hash & narHash) +{ + try { + return nix::readFile(makeCacheFile(narHash, "ls")); + } catch (SystemError &) { + return std::nullopt; + } +} + +} // namespace nix diff --git a/src/libstore/remote-fs-accessor.cc b/src/libstore/remote-fs-accessor.cc index 7297723e16b..5d712ae1b26 100644 --- a/src/libstore/remote-fs-accessor.cc +++ b/src/libstore/remote-fs-accessor.cc @@ -1,21 +1,14 @@ #include #include "nix/store/remote-fs-accessor.hh" -#include "nix/util/nar-accessor.hh" - -#include -#include -#include +#include "nix/store/nar-cache.hh" namespace nix { -RemoteFSAccessor::RemoteFSAccessor( - ref store, bool requireValidPath, std::optional cacheDir_) +RemoteFSAccessor::RemoteFSAccessor(ref store, bool requireValidPath, std::shared_ptr narCache) : store(store) , requireValidPath(requireValidPath) - , cacheDir(std::move(cacheDir_)) + , narCache(std::move(narCache)) { - if (cacheDir) - createDirs(*cacheDir); } std::pair, CanonPath> RemoteFSAccessor::fetch(const CanonPath & path) @@ -47,48 +40,22 @@ std::shared_ptr RemoteFSAccessor::accessObject(const StorePath & return std::move(sink.s); }; - if (cacheDir) { - auto makeCacheFile = [&](const std::string & ext) { - auto res = *cacheDir / info->narHash.to_string(HashFormat::Nix32, false); - res += "."; - res += ext; - return res; - }; - - auto cacheFile = makeCacheFile("nar"); - auto listingFile = makeCacheFile("ls"); - - if (nix::pathExists(cacheFile)) { - try { - return cacheAccessor(makeLazyNarAccessor( - nlohmann::json::parse(nix::readFile(listingFile)).template get(), - seekableGetNarBytes(cacheFile))); - } catch (SystemError &) { - } - - try { - return cacheAccessor(makeNarAccessor(nix::readFile(cacheFile))); - } catch (SystemError &) { - } - } + if (narCache) { + if (auto listingData = narCache->getNarListing(info->narHash)) + return cacheAccessor(makeLazyNarAccessor( + nlohmann::json::parse(*listingData).template get(), narCache->getNarBytes(info->narHash))); + + if (auto nar = narCache->getNar(info->narHash)) + return cacheAccessor(makeNarAccessor(std::move(*nar))); auto nar = getNar(); - try { - /* FIXME: do this asynchronously. */ - writeFile(cacheFile, nar); - } catch (...) { - ignoreExceptionExceptInterrupt(); - } + StringSource source{nar}; + narCache->upsertNar(info->narHash, source); auto narAccessor = makeNarAccessor(std::move(nar)); - try { - nlohmann::json j = narAccessor->getListing(); - writeFile(listingFile, j.dump()); - } catch (...) { - ignoreExceptionExceptInterrupt(); - } + narCache->upsertNarListing(info->narHash, nlohmann::json(narAccessor->getListing()).dump()); return cacheAccessor(narAccessor); }