1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-11 13:06:01 +01:00

Merge pull request #110 from DeterminateSystems/fix-fetcher-cache

Fix broken fetchToStore() caching
This commit is contained in:
Eelco Dolstra 2025-06-13 22:30:30 +00:00 committed by GitHub
commit 49a059d426
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 44 additions and 49 deletions

View file

@ -31,10 +31,14 @@ StorePath fetchToStore(
// a `PosixSourceAccessor` pointing to a store path. // a `PosixSourceAccessor` pointing to a store path.
std::optional<fetchers::Cache::Key> cacheKey; std::optional<fetchers::Cache::Key> cacheKey;
std::optional<std::string> fingerprint;
if (!filter && (fingerprint = path.accessor->getFingerprint(path.path))) { auto [subpath, fingerprint] =
cacheKey = makeFetchToStoreCacheKey(std::string{name}, *fingerprint, method, path.path.abs()); filter
? std::pair<CanonPath, std::optional<std::string>>{path.path, std::nullopt}
: path.accessor->getFingerprint(path.path);
if (fingerprint) {
cacheKey = makeFetchToStoreCacheKey(std::string{name}, *fingerprint, method, subpath.abs());
if (auto res = fetchers::getCache()->lookupStorePath(*cacheKey, store, mode == FetchMode::DryRun)) { if (auto res = fetchers::getCache()->lookupStorePath(*cacheKey, store, mode == FetchMode::DryRun)) {
debug("store path cache hit for '%s'", path); debug("store path cache hit for '%s'", path);
return res->storePath; return res->storePath;

View file

@ -338,8 +338,7 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
auto accessor = make_ref<SubstitutedSourceAccessor>(makeStorePathAccessor(store, storePath)); auto accessor = make_ref<SubstitutedSourceAccessor>(makeStorePathAccessor(store, storePath));
if (auto fingerprint = getFingerprint(store)) accessor->fingerprint = getFingerprint(store);
accessor->setFingerprint(*fingerprint);
// FIXME: ideally we would use the `showPath()` of the // FIXME: ideally we would use the `showPath()` of the
// "real" accessor for this fetcher type. // "real" accessor for this fetcher type.
@ -353,10 +352,8 @@ std::pair<ref<SourceAccessor>, Input> Input::getAccessorUnchecked(ref<Store> sto
auto [accessor, result] = scheme->getAccessor(store, *this); auto [accessor, result] = scheme->getAccessor(store, *this);
assert(!accessor->getFingerprint(CanonPath::root)); assert(!accessor->fingerprint);
accessor->fingerprint = result.getFingerprint(store);
if (auto fingerprint = getFingerprint(store))
accessor->setFingerprint(*fingerprint);
return {accessor, std::move(result)}; return {accessor, std::move(result)};
} }

View file

@ -58,16 +58,13 @@ std::string FilteringSourceAccessor::showPath(const CanonPath & path)
return displayPrefix + next->showPath(prefix / path) + displaySuffix; return displayPrefix + next->showPath(prefix / path) + displaySuffix;
} }
std::optional<std::string> FilteringSourceAccessor::getFingerprint(const CanonPath & path) std::pair<CanonPath, std::optional<std::string>> FilteringSourceAccessor::getFingerprint(const CanonPath & path)
{ {
if (fingerprint)
return {path, fingerprint};
return next->getFingerprint(prefix / path); return next->getFingerprint(prefix / path);
} }
void FilteringSourceAccessor::setFingerprint(std::string fingerprint)
{
next->setFingerprint(std::move(fingerprint));
}
void FilteringSourceAccessor::checkAccess(const CanonPath & path) void FilteringSourceAccessor::checkAccess(const CanonPath & path)
{ {
if (!isAllowed(path)) if (!isAllowed(path))

View file

@ -50,9 +50,7 @@ struct FilteringSourceAccessor : SourceAccessor
std::string showPath(const CanonPath & path) override; std::string showPath(const CanonPath & path) override;
std::optional<std::string> getFingerprint(const CanonPath & path) override; std::pair<CanonPath, std::optional<std::string>> getFingerprint(const CanonPath & path) override;
void setFingerprint(std::string fingerprint) override;
/** /**
* Call `makeNotAllowedError` to throw a `RestrictedPathError` * Call `makeNotAllowedError` to throw a `RestrictedPathError`

View file

@ -52,16 +52,6 @@ struct ForwardingSourceAccessor : SourceAccessor
{ {
return next->getPhysicalPath(path); return next->getPhysicalPath(path);
} }
std::optional<std::string> getFingerprint(const CanonPath & path) override
{
return next->getFingerprint(path);
}
void setFingerprint(std::string fingerprint) override
{
next->setFingerprint(std::move(fingerprint));
}
}; };
} }

View file

@ -177,28 +177,32 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
SymlinkResolution mode = SymlinkResolution::Full); SymlinkResolution mode = SymlinkResolution::Full);
/** /**
* Return a string that uniquely represents the contents of this * A string that uniquely represents the contents of this
* accessor. This is used for caching lookups (see * accessor. This is used for caching lookups (see `fetchToStore()`).
* `fetchToStore()`).
*
* Fingerprints are generally for the entire accessor, but this
* method takes a `path` argument to support accessors like
* `MountedSourceAccessor` that combine multiple underlying
* accessors. A fingerprint should only be returned if it uniquely
* represents everything under `path`.
*/ */
virtual std::optional<std::string> getFingerprint(const CanonPath & path) std::optional<std::string> fingerprint;
{
return _fingerprint;
}
virtual void setFingerprint(std::string fingerprint) /**
* Return the fingerprint for `path`. This is usually the
* fingerprint of the current accessor, but for composite
* accessors (like `MountedSourceAccessor`), we want to return the
* fingerprint of the "inner" accessor if the current one lacks a
* fingerprint.
*
* So this method is intended to return the most-outer accessor
* that has a fingerprint for `path`. It also returns the path that `path`
* corresponds to in that accessor.
*
* For example: in a `MountedSourceAccessor` that has
* `/nix/store/foo` mounted,
* `getFingerprint("/nix/store/foo/bar")` will return the path
* `/bar` and the fingerprint of the `/nix/store/foo` accessor.
*/
virtual std::pair<CanonPath, std::optional<std::string>> getFingerprint(const CanonPath & path)
{ {
_fingerprint = std::move(fingerprint); return {path, fingerprint};
} }
std::optional<std::string> _fingerprint;
/** /**
* Return the maximum last-modified time of the files in this * Return the maximum last-modified time of the files in this
* tree, if available. * tree, if available.

View file

@ -91,12 +91,11 @@ struct MountedSourceAccessorImpl : MountedSourceAccessor
return nullptr; return nullptr;
} }
std::optional<std::string> getFingerprint(const CanonPath & path) override std::pair<CanonPath, std::optional<std::string>> getFingerprint(const CanonPath & path) override
{ {
if (fingerprint)
return {path, fingerprint};
auto [accessor, subpath] = resolve(path); auto [accessor, subpath] = resolve(path);
// FIXME: check that there are no mounts underneath the mount
// point of `accessor`, since that would invalidate the
// fingerprint. (However we don't have such at the moment.)
return accessor->getFingerprint(subpath); return accessor->getFingerprint(subpath);
} }
}; };

View file

@ -112,6 +112,12 @@ nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir#default"
nix build -o "$TEST_ROOT/result" "$flake1Dir?ref=HEAD#default" nix build -o "$TEST_ROOT/result" "$flake1Dir?ref=HEAD#default"
nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir?ref=HEAD#default" nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir?ref=HEAD#default"
# Check that the fetcher cache works.
if [[ $(nix config show lazy-trees) = false ]]; then
nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir?ref=HEAD#default" -vvvvv 2>&1 | grepQuietInverse "source path.*is uncacheable"
nix build -o "$TEST_ROOT/result" "git+file://$flake1Dir?ref=HEAD#default" -vvvvv 2>&1 | grepQuiet "store path cache hit"
fi
# Check that relative paths are allowed for git flakes. # Check that relative paths are allowed for git flakes.
# This may change in the future once git submodule support is refined. # This may change in the future once git submodule support is refined.
# See: https://discourse.nixos.org/t/57783 and #9708. # See: https://discourse.nixos.org/t/57783 and #9708.