mirror of
https://github.com/NixOS/nix.git
synced 2025-11-30 14:10:59 +01:00
Persistently cache InputAccessor::fetchToStore()
This especially speeds up repeated evaluations that copy a large
source tree (e.g. 'nix.nixPath = [ "nixpkgs=${nixpkgs}" ];').
This commit is contained in:
parent
2e0d63caf6
commit
beac2e67cd
4 changed files with 34 additions and 6 deletions
|
|
@ -160,11 +160,14 @@ void Input::checkLocks(Input & input) const
|
||||||
|
|
||||||
std::pair<ref<InputAccessor>, Input> Input::getAccessor(ref<Store> store) const
|
std::pair<ref<InputAccessor>, Input> Input::getAccessor(ref<Store> store) const
|
||||||
{
|
{
|
||||||
|
// FIXME: cache the accessor
|
||||||
|
|
||||||
if (!scheme)
|
if (!scheme)
|
||||||
throw Error("cannot fetch unsupported input '%s'", attrsToJSON(toAttrs()));
|
throw Error("cannot fetch unsupported input '%s'", attrsToJSON(toAttrs()));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
auto [accessor, final] = scheme->getAccessor(store, *this);
|
auto [accessor, final] = scheme->getAccessor(store, *this);
|
||||||
|
accessor->fingerprint = scheme->getFingerprint(store, *this);
|
||||||
checkLocks(final);
|
checkLocks(final);
|
||||||
return {accessor, std::move(final)};
|
return {accessor, std::move(final)};
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
|
@ -256,10 +259,7 @@ std::optional<time_t> Input::getLastModified() const
|
||||||
|
|
||||||
std::optional<std::string> Input::getFingerprint(ref<Store> store) const
|
std::optional<std::string> Input::getFingerprint(ref<Store> store) const
|
||||||
{
|
{
|
||||||
if (auto rev = getRev())
|
return scheme ? scheme->getFingerprint(store, *this) : std::nullopt;
|
||||||
return rev->gitRev();
|
|
||||||
assert(scheme);
|
|
||||||
return scheme->getFingerprint(store, *this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ParsedURL InputScheme::toURL(const Input & input) const
|
ParsedURL InputScheme::toURL(const Input & input) const
|
||||||
|
|
@ -293,4 +293,12 @@ void InputScheme::clone(const Input & input, const Path & destDir) const
|
||||||
throw Error("do not know how to clone input '%s'", input.to_string());
|
throw Error("do not know how to clone input '%s'", input.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string> InputScheme::getFingerprint(ref<Store> store, const Input & input) const
|
||||||
|
{
|
||||||
|
if (auto rev = input.getRev())
|
||||||
|
return rev->gitRev();
|
||||||
|
else
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,7 @@ struct InputScheme
|
||||||
virtual std::optional<CanonPath> isRelative(const Input & input) const
|
virtual std::optional<CanonPath> isRelative(const Input & input) const
|
||||||
{ return std::nullopt; }
|
{ return std::nullopt; }
|
||||||
|
|
||||||
virtual std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const
|
virtual std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const;
|
||||||
{ return std::nullopt; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void registerInputScheme(std::shared_ptr<InputScheme> && fetcher);
|
void registerInputScheme(std::shared_ptr<InputScheme> && fetcher);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "input-accessor.hh"
|
#include "input-accessor.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
#include "cache.hh"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
|
@ -96,6 +97,21 @@ StorePath InputAccessor::fetchToStore(
|
||||||
// FIXME: add an optimisation for the case where the accessor is
|
// FIXME: add an optimisation for the case where the accessor is
|
||||||
// an FSInputAccessor pointing to a store path.
|
// an FSInputAccessor pointing to a store path.
|
||||||
|
|
||||||
|
std::optional<std::string> cacheKey;
|
||||||
|
|
||||||
|
if (!filter && fingerprint) {
|
||||||
|
cacheKey = *fingerprint + "|" + name + "|" + path.abs();
|
||||||
|
if (auto storePathS = fetchers::getCache()->queryFact(*cacheKey)) {
|
||||||
|
if (auto storePath = store->maybeParseStorePath(*storePathS)) {
|
||||||
|
if (store->isValidPath(*storePath)) {
|
||||||
|
debug("store path cache hit for '%s'", showPath(path));
|
||||||
|
return *storePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
debug("source path '%s' is uncacheable", showPath(path));
|
||||||
|
|
||||||
auto source = sinkToSource([&](Sink & sink) {
|
auto source = sinkToSource([&](Sink & sink) {
|
||||||
dumpPath(path, sink, filter ? *filter : defaultPathFilter);
|
dumpPath(path, sink, filter ? *filter : defaultPathFilter);
|
||||||
});
|
});
|
||||||
|
|
@ -105,6 +121,9 @@ StorePath InputAccessor::fetchToStore(
|
||||||
? store->computeStorePathFromDump(*source, name).first
|
? store->computeStorePathFromDump(*source, name).first
|
||||||
: store->addToStoreFromDump(*source, name, FileIngestionMethod::Recursive, htSHA256, repair);
|
: store->addToStoreFromDump(*source, name, FileIngestionMethod::Recursive, htSHA256, repair);
|
||||||
|
|
||||||
|
if (cacheKey)
|
||||||
|
fetchers::getCache()->upsertFact(*cacheKey, store->printStorePath(storePath));
|
||||||
|
|
||||||
return storePath;
|
return storePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ struct InputAccessor : public std::enable_shared_from_this<InputAccessor>
|
||||||
|
|
||||||
std::string displayPrefix, displaySuffix;
|
std::string displayPrefix, displaySuffix;
|
||||||
|
|
||||||
|
std::optional<std::string> fingerprint;
|
||||||
|
|
||||||
InputAccessor();
|
InputAccessor();
|
||||||
|
|
||||||
virtual ~InputAccessor()
|
virtual ~InputAccessor()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue