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

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

Fix fetchToStore() caching
This commit is contained in:
Eelco Dolstra 2025-06-11 10:41:57 +00:00 committed by GitHub
commit 550c894712
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 73 additions and 10 deletions

View file

@ -80,6 +80,7 @@ StorePath EvalState::mountInput(
storeFS->mount(CanonPath(store->printStorePath(storePath)), accessor); storeFS->mount(CanonPath(store->printStorePath(storePath)), accessor);
if (requireLockable && (!settings.lazyTrees || !input.isLocked()) && !input.getNarHash()) { if (requireLockable && (!settings.lazyTrees || !input.isLocked()) && !input.getNarHash()) {
// FIXME: use fetchToStore to make it cache this
auto narHash = accessor->hashPath(CanonPath::root); auto narHash = accessor->hashPath(CanonPath::root);
input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true)); input.attrs.insert_or_assign("narHash", narHash.to_string(HashFormat::SRI, true));
} }

View file

@ -31,15 +31,16 @@ 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 && path.accessor->fingerprint) { if (!filter && (fingerprint = path.accessor->getFingerprint(path.path))) {
cacheKey = makeFetchToStoreCacheKey(std::string{name}, *path.accessor->fingerprint, method, path.path.abs()); cacheKey = makeFetchToStoreCacheKey(std::string{name}, *fingerprint, method, path.path.abs());
if (auto res = fetchers::getCache()->lookupStorePath(*cacheKey, store)) { if (auto res = fetchers::getCache()->lookupStorePath(*cacheKey, store)) {
debug("store path cache hit for '%s'", path); debug("store path cache hit for '%s'", path);
return res->storePath; return res->storePath;
} }
} else } else
debug("source path '%s' is uncacheable", path); debug("source path '%s' is uncacheable (%d, %d)", path, filter, (bool) fingerprint);
Activity act(*logger, lvlChatty, actUnknown, Activity act(*logger, lvlChatty, actUnknown,
fmt(mode == FetchMode::DryRun ? "hashing '%s'" : "copying '%s' to the store", path)); fmt(mode == FetchMode::DryRun ? "hashing '%s'" : "copying '%s' to the store", path));
@ -55,7 +56,7 @@ StorePath fetchToStore(
debug(mode == FetchMode::DryRun ? "hashed '%s'" : "copied '%s' to '%s'", path, store.printStorePath(storePath)); debug(mode == FetchMode::DryRun ? "hashed '%s'" : "copied '%s' to '%s'", path, store.printStorePath(storePath));
if (cacheKey && mode == FetchMode::Copy) if (cacheKey)
fetchers::getCache()->upsert(*cacheKey, store, {}, storePath); fetchers::getCache()->upsert(*cacheKey, store, {}, storePath);
return storePath; return storePath;

View file

@ -338,7 +338,8 @@ 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));
accessor->fingerprint = getFingerprint(store); if (auto 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.
@ -352,8 +353,10 @@ 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->fingerprint); assert(!accessor->getFingerprint(CanonPath::root));
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

@ -14,6 +14,12 @@ std::string FilteringSourceAccessor::readFile(const CanonPath & path)
return next->readFile(prefix / path); return next->readFile(prefix / path);
} }
void FilteringSourceAccessor::readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback)
{
checkAccess(path);
return next->readFile(prefix / path, sink, sizeCallback);
}
bool FilteringSourceAccessor::pathExists(const CanonPath & path) bool FilteringSourceAccessor::pathExists(const CanonPath & path)
{ {
return isAllowed(path) && next->pathExists(prefix / path); return isAllowed(path) && next->pathExists(prefix / path);
@ -52,6 +58,16 @@ 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)
{
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

@ -36,6 +36,8 @@ struct FilteringSourceAccessor : SourceAccessor
std::string readFile(const CanonPath & path) override; std::string readFile(const CanonPath & path) override;
void readFile(const CanonPath & path, Sink & sink, std::function<void(uint64_t)> sizeCallback) override;
bool pathExists(const CanonPath & path) override; bool pathExists(const CanonPath & path) override;
Stat lstat(const CanonPath & path) override; Stat lstat(const CanonPath & path) override;
@ -48,6 +50,10 @@ 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;
void setFingerprint(std::string fingerprint) override;
/** /**
* Call `makeNotAllowedError` to throw a `RestrictedPathError` * Call `makeNotAllowedError` to throw a `RestrictedPathError`
* exception if `isAllowed()` returns `false` for `path`. * exception if `isAllowed()` returns `false` for `path`.

View file

@ -52,6 +52,16 @@ 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,10 +177,27 @@ struct SourceAccessor : std::enable_shared_from_this<SourceAccessor>
SymlinkResolution mode = SymlinkResolution::Full); SymlinkResolution mode = SymlinkResolution::Full);
/** /**
* A string that uniquely represents the contents of this * Return a string that uniquely represents the contents of this
* accessor. This is used for caching lookups (see `fetchToStore()`). * accessor. This is used for caching lookups (see
* `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`.
*/ */
std::optional<std::string> fingerprint; virtual std::optional<std::string> getFingerprint(const CanonPath & path)
{
return _fingerprint;
}
virtual void setFingerprint(std::string fingerprint)
{
_fingerprint = std::move(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

View file

@ -90,6 +90,15 @@ struct MountedSourceAccessorImpl : MountedSourceAccessor
else else
return nullptr; return nullptr;
} }
std::optional<std::string> getFingerprint(const CanonPath & path) override
{
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);
}
}; };
ref<MountedSourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts) ref<MountedSourceAccessor> makeMountedSourceAccessor(std::map<CanonPath, ref<SourceAccessor>> mounts)