diff --git a/src/libstore/include/nix/store/globals.hh b/src/libstore/include/nix/store/globals.hh index c827aea56..3f2f122eb 100644 --- a/src/libstore/include/nix/store/globals.hh +++ b/src/libstore/include/nix/store/globals.hh @@ -86,6 +86,17 @@ struct NarInfoDiskCacheSettings : public virtual Config would prevent trying to pull the path again and failing with a hash mismatch if the build isn't reproducible. )"}; + + Setting ttlMeta{ + this, + 7 * 24 * 3600, + "narinfo-cache-meta-ttl", + R"( + The TTL in seconds for caching binary cache metadata (i.e. + `/nix-cache-info`). This determines how long information about a + binary cache (such as its store directory, priority, and whether it + wants mass queries) is considered valid before being refreshed. + )"}; }; class Settings : public virtual Config, diff --git a/src/libstore/nar-info-disk-cache.cc b/src/libstore/nar-info-disk-cache.cc index 18932ca12..dfb679598 100644 --- a/src/libstore/nar-info-disk-cache.cc +++ b/src/libstore/nar-info-disk-cache.cc @@ -63,9 +63,6 @@ struct NarInfoDiskCacheImpl : NarInfoDiskCache /* How often to purge expired entries from the cache. */ const int purgeInterval = 24 * 3600; - /* How long to cache binary cache info (i.e. /nix-cache-info) */ - const int cacheInfoTtl = 7 * 24 * 3600; - struct Cache { int id; @@ -184,7 +181,7 @@ private: { auto i = state.caches.find(uri); if (i == state.caches.end()) { - auto queryCache(state.queryCache.use()(uri)(time(0) - cacheInfoTtl)); + auto queryCache(state.queryCache.use()(uri)(time(0) - settings.ttlMeta)); if (!queryCache.next()) return std::nullopt; auto cache = Cache{ diff --git a/src/nix/main.cc b/src/nix/main.cc index dddb757af..992f37548 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -564,12 +564,16 @@ void mainWrapped(int argc, char ** argv) fileTransferSettings.tries = 0; if (!fileTransferSettings.connectTimeout.overridden) fileTransferSettings.connectTimeout = 1; + auto & ttlMeta = settings.getNarInfoDiskCacheSettings().ttlMeta; + if (!ttlMeta.overridden) + ttlMeta = std::numeric_limits::max(); } if (args.refresh) { fetchSettings.tarballTtl = 0; settings.getNarInfoDiskCacheSettings().ttlNegative = 0; settings.getNarInfoDiskCacheSettings().ttlPositive = 0; + settings.getNarInfoDiskCacheSettings().ttlMeta = 0; } if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) { diff --git a/tests/functional/binary-cache.sh b/tests/functional/binary-cache.sh index 445845bba..066fa026e 100755 --- a/tests/functional/binary-cache.sh +++ b/tests/functional/binary-cache.sh @@ -312,3 +312,24 @@ nix-store --delete "$outPath" "$docPath" # -vvv is the level that logs during the loop timeout 60 nix-build --no-out-link -E "$expr" --option substituters "file://$cacheDir" \ --option trusted-binary-caches "file://$cacheDir" --no-require-sigs + + +# Test that the narinfo-cache-meta-ttl causes nix-cache-info to be cached, +# and that --refresh overrides it. + +# Populate the metadata cache by querying store info over HTTP. +_NIX_FORCE_HTTP=1 nix store info --store "file://$cacheDir" + +# Remove nix-cache-info from the binary cache. +rm "$cacheDir/nix-cache-info" + +# nix store info should still work because the metadata is cached +# (narinfo-cache-meta-ttl defaults to 7 days). +_NIX_FORCE_HTTP=1 nix store info --store "file://$cacheDir" + +# But with --refresh, it should fail because nix-cache-info is gone +# and the cached metadata TTL is overridden to 0. +_NIX_FORCE_HTTP=1 expectStderr 1 nix store info --store "file://$cacheDir" --refresh | grepQuiet "uploading.*is not supported" + +# Remove --refresh and it should work again. +_NIX_FORCE_HTTP=1 nix store info --store "file://$cacheDir"