diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index c5a95268b..3805942ce 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -28,6 +28,7 @@ #include "nix/expr/print.hh" #include "nix/util/ref.hh" #include "nix/expr/value.hh" +#include "nix/fetchers/input-cache.hh" #include "nix/util/strings.hh" @@ -458,6 +459,7 @@ ProcessLineResult NixRepl::processLine(std::string line) else if (command == ":l" || command == ":load") { state->resetFileCache(); + fetchers::InputCache::getCache()->clear(); loadFile(arg); } @@ -467,6 +469,7 @@ ProcessLineResult NixRepl::processLine(std::string line) else if (command == ":r" || command == ":reload") { state->resetFileCache(); + fetchers::InputCache::getCache()->clear(); reloadFiles(); } diff --git a/src/libfetchers/include/nix/fetchers/input-cache.hh b/src/libfetchers/include/nix/fetchers/input-cache.hh new file mode 100644 index 000000000..62092baef --- /dev/null +++ b/src/libfetchers/include/nix/fetchers/input-cache.hh @@ -0,0 +1,22 @@ +#include "fetchers.hh" + +namespace nix::fetchers { + +struct CachedInput +{ + Input lockedInput; + ref accessor; +}; + +struct InputCache +{ + virtual std::optional lookup(const Input & originalInput) const = 0; + + virtual void upsert(Input key, CachedInput cachedInput) = 0; + + virtual void clear() = 0; + + static ref getCache(); +}; + +} diff --git a/src/libfetchers/include/nix/fetchers/meson.build b/src/libfetchers/include/nix/fetchers/meson.build index 3a752d9cb..e6ddedd97 100644 --- a/src/libfetchers/include/nix/fetchers/meson.build +++ b/src/libfetchers/include/nix/fetchers/meson.build @@ -9,6 +9,7 @@ headers = files( 'filtering-source-accessor.hh', 'git-lfs-fetch.hh', 'git-utils.hh', + 'input-cache.hh', 'registry.hh', 'store-path-accessor.hh', 'tarball.hh', diff --git a/src/libfetchers/input-cache.cc b/src/libfetchers/input-cache.cc new file mode 100644 index 000000000..44d33428d --- /dev/null +++ b/src/libfetchers/input-cache.cc @@ -0,0 +1,41 @@ +#include "nix/fetchers/input-cache.hh" +#include "nix/util/sync.hh" + +namespace nix::fetchers { + +struct InputCacheImpl : InputCache +{ + Sync> cache_; + + std::optional lookup(const Input & originalInput) const override + { + auto cache(cache_.readLock()); + auto i = cache->find(originalInput); + if (i == cache->end()) + return std::nullopt; + debug( + "mapping '%s' to previously seen input '%s' -> '%s", + originalInput.to_string(), + i->first.to_string(), + i->second.lockedInput.to_string()); + return i->second; + } + + void upsert(Input key, CachedInput cachedInput) override + { + cache_.lock()->insert_or_assign(std::move(key), std::move(cachedInput)); + } + + void clear() override + { + cache_.lock()->clear(); + } +}; + +ref InputCache::getCache() +{ + static auto cache = make_ref(); + return cache; +} + +} diff --git a/src/libfetchers/meson.build b/src/libfetchers/meson.build index 6e7129f4c..321146ca4 100644 --- a/src/libfetchers/meson.build +++ b/src/libfetchers/meson.build @@ -44,6 +44,7 @@ sources = files( 'git.cc', 'github.cc', 'indirect.cc', + 'input-cache.cc', 'mercurial.cc', 'path.cc', 'registry.cc', diff --git a/src/libflake-c/nix_api_flake.cc b/src/libflake-c/nix_api_flake.cc index 06b139f91..0cc9a6a10 100644 --- a/src/libflake-c/nix_api_flake.cc +++ b/src/libflake-c/nix_api_flake.cc @@ -7,6 +7,7 @@ #include "nix_api_fetchers.h" #include "nix/flake/flake.hh" +#include "nix/fetchers/input-cache.hh" nix_flake_settings * nix_flake_settings_new(nix_c_context * context) { @@ -177,6 +178,7 @@ nix_locked_flake * nix_flake_lock( { nix_clear_err(context); try { + nix::fetchers::InputCache::getCache()->clear(); auto lockedFlake = nix::make_ref(nix::flake::lockFlake( *flakeSettings->settings, eval_state->state, *flakeReference->flakeRef, *flags->lockFlags)); return new nix_locked_flake{lockedFlake}; diff --git a/src/libflake/flake/flake.cc b/src/libflake/flake/flake.cc index 30093bd4d..ca2a34f5f 100644 --- a/src/libflake/flake/flake.cc +++ b/src/libflake/flake/flake.cc @@ -14,6 +14,7 @@ #include "nix/store/local-fs-store.hh" #include "nix/fetchers/fetch-to-store.hh" #include "nix/util/memory-source-accessor.hh" +#include "nix/fetchers/input-cache.hh" #include @@ -23,32 +24,14 @@ using namespace flake; namespace flake { -struct CachedInput -{ - Input lockedInput; - ref accessor; -}; - -typedef std::map InputCache; - -static std::optional lookupInInputCache( - const InputCache & inputCache, - const Input & originalInput) -{ - auto i = inputCache.find(originalInput); - if (i == inputCache.end()) return std::nullopt; - debug("mapping '%s' to previously seen input '%s' -> '%s", - originalInput.to_string(), i->first.to_string(), i->second.lockedInput.to_string()); - return i->second; -} - static std::tuple, Input, Input> getAccessorCached( EvalState & state, const Input & originalInput, - bool useRegistries, - InputCache & inputCache) + bool useRegistries) { - auto fetched = lookupInInputCache(inputCache, originalInput); + auto inputCache = InputCache::getCache(); + + auto fetched = inputCache->lookup(originalInput); Input resolvedInput = originalInput; if (!fetched) { @@ -64,18 +47,18 @@ static std::tuple, Input, Input> getAccessorCached( return type == fetchers::Registry::Flag || type == fetchers::Registry::Global; }); resolvedInput = std::move(res); - fetched = lookupInInputCache(inputCache, originalInput); + fetched = inputCache->lookup(resolvedInput); if (!fetched) { auto [accessor, lockedInput] = resolvedInput.getAccessor(state.store); fetched.emplace(CachedInput{.lockedInput = lockedInput, .accessor = accessor}); } - inputCache.insert_or_assign(resolvedInput, *fetched); + inputCache->upsert(resolvedInput, *fetched); } else { throw Error("'%s' is an indirect flake reference, but registry lookups are not allowed", originalInput.to_string()); } } - inputCache.insert_or_assign(originalInput, *fetched); + inputCache->upsert(originalInput, *fetched); } debug("got tree '%s' from '%s'", fetched->accessor, fetched->lockedInput.to_string()); @@ -397,12 +380,11 @@ static Flake getFlake( EvalState & state, const FlakeRef & originalRef, bool useRegistries, - InputCache & inputCache, const InputAttrPath & lockRootAttrPath) { // Fetch a lazy tree first. auto [accessor, resolvedInput, lockedInput] = getAccessorCached( - state, originalRef.input, useRegistries, inputCache); + state, originalRef.input, useRegistries); auto resolvedRef = FlakeRef(std::move(resolvedInput), originalRef.subdir); auto lockedRef = FlakeRef(std::move(lockedInput), originalRef.subdir); @@ -418,7 +400,7 @@ static Flake getFlake( // FIXME: need to remove attrs that are invalidated by the changed input attrs, such as 'narHash'. newLockedRef.input.attrs.erase("narHash"); auto [accessor2, resolvedInput2, lockedInput2] = getAccessorCached( - state, newLockedRef.input, false, inputCache); + state, newLockedRef.input, false); accessor = accessor2; lockedRef = FlakeRef(std::move(lockedInput2), newLockedRef.subdir); } @@ -432,8 +414,7 @@ static Flake getFlake( Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool useRegistries) { - InputCache inputCache; - return getFlake(state, originalRef, useRegistries, inputCache, {}); + return getFlake(state, originalRef, useRegistries, {}); } static LockFile readLockFile( @@ -455,11 +436,9 @@ LockedFlake lockFlake( { experimentalFeatureSettings.require(Xp::Flakes); - InputCache inputCache; - auto useRegistries = lockFlags.useRegistries.value_or(settings.useRegistries); - auto flake = getFlake(state, topRef, useRegistries, inputCache, {}); + auto flake = getFlake(state, topRef, useRegistries, {}); if (lockFlags.applyNixConfig) { flake.config.apply(settings); @@ -634,7 +613,7 @@ LockedFlake lockFlake( if (auto resolvedPath = resolveRelativePath()) { return readFlake(state, ref, ref, ref, *resolvedPath, inputAttrPath); } else { - return getFlake(state, ref, useRegistries, inputCache, inputAttrPath); + return getFlake(state, ref, useRegistries, inputAttrPath); } }; @@ -783,7 +762,7 @@ LockedFlake lockFlake( return {*resolvedPath, *input.ref}; } else { auto [accessor, resolvedInput, lockedInput] = getAccessorCached( - state, input.ref->input, useRegistries, inputCache); + state, input.ref->input, useRegistries); auto lockedRef = FlakeRef(std::move(lockedInput), input.ref->subdir);