mirror of
https://github.com/NixOS/nix.git
synced 2025-11-09 03:56:01 +01:00
Avoid isValidPath(), use queryPathInfo() instead
Since recently we call isValidPath() a lot from the evaluator, specifically from LocalStoreAccessor::requireStoreObject(). Unfortunately, isValidPath() uses but does not populate the in-memory path info cache; only queryPathInfo() does that. So isValidPath() is fast *if* we happened to call queryPathInfo() on the same path previously. This is not the case when lazy-trees is enabled, so we got a lot of superfluous, high-latency calls to the daemon (which show up in verbose output as `performing daemon worker op: 1`). Similarly, `fetchToStore()` called `isValidPath()` as well. The fix is to use `queryPathInfo()`, which for one particular eval reduced the number of daemon calls from 15246 to 2324. This may cause Nix to fetch some unnecessary information from the daemon, but that probably doesn't matter much given the high latency.
This commit is contained in:
parent
47281531ec
commit
19f89eb684
4 changed files with 32 additions and 4 deletions
|
|
@ -52,7 +52,7 @@ std::pair<StorePath, Hash> fetchToStore2(
|
||||||
auto hash = Hash::parseSRI(fetchers::getStrAttr(*res, "hash"));
|
auto hash = Hash::parseSRI(fetchers::getStrAttr(*res, "hash"));
|
||||||
auto storePath = store.makeFixedOutputPathFromCA(name,
|
auto storePath = store.makeFixedOutputPathFromCA(name,
|
||||||
ContentAddressWithReferences::fromParts(method, hash, {}));
|
ContentAddressWithReferences::fromParts(method, hash, {}));
|
||||||
if (mode == FetchMode::DryRun || store.isValidPath(storePath)) {
|
if (mode == FetchMode::DryRun || store.maybeQueryPathInfo(storePath)) {
|
||||||
debug("source path '%s' cache hit in '%s' (hash '%s')", path, store.printStorePath(storePath), hash.to_string(HashFormat::SRI, true));
|
debug("source path '%s' cache hit in '%s' (hash '%s')", path, store.printStorePath(storePath), hash.to_string(HashFormat::SRI, true));
|
||||||
return {storePath, hash};
|
return {storePath, hash};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,9 @@ public:
|
||||||
StorePath followLinksToStorePath(std::string_view path) const;
|
StorePath followLinksToStorePath(std::string_view path) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether a path is valid.
|
* Check whether a path is valid. NOTE: this function does not
|
||||||
|
* generally cache whether a path is valid. You may want to use
|
||||||
|
* `maybeQueryPathInfo()`, which does cache.
|
||||||
*/
|
*/
|
||||||
bool isValidPath(const StorePath & path);
|
bool isValidPath(const StorePath & path);
|
||||||
|
|
||||||
|
|
@ -308,10 +310,17 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query information about a valid path. It is permitted to omit
|
* Query information about a valid path. It is permitted to omit
|
||||||
* the name part of the store path.
|
* the name part of the store path. Throws an exception if the
|
||||||
|
* path is not valid.
|
||||||
*/
|
*/
|
||||||
ref<const ValidPathInfo> queryPathInfo(const StorePath & path);
|
ref<const ValidPathInfo> queryPathInfo(const StorePath & path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Like `queryPathInfo()`, but returns `nullptr` if the path is
|
||||||
|
* not valid.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<const ValidPathInfo> maybeQueryPathInfo(const StorePath & path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asynchronous version of queryPathInfo().
|
* Asynchronous version of queryPathInfo().
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ struct LocalStoreAccessor : PosixSourceAccessor
|
||||||
void requireStoreObject(const CanonPath & path)
|
void requireStoreObject(const CanonPath & path)
|
||||||
{
|
{
|
||||||
auto [storePath, rest] = store->toStorePath(store->storeDir + path.abs());
|
auto [storePath, rest] = store->toStorePath(store->storeDir + path.abs());
|
||||||
if (requireValidPath && !store->isValidPath(storePath))
|
if (requireValidPath && !store->maybeQueryPathInfo(storePath))
|
||||||
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
|
throw InvalidPath("path '%1%' is not a valid store path", store->printStorePath(storePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -633,6 +633,25 @@ ref<const ValidPathInfo> Store::queryPathInfo(const StorePath & storePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<const ValidPathInfo> Store::maybeQueryPathInfo(const StorePath & storePath)
|
||||||
|
{
|
||||||
|
std::promise<std::shared_ptr<const ValidPathInfo>> promise;
|
||||||
|
|
||||||
|
queryPathInfo(storePath,
|
||||||
|
{[&](std::future<ref<const ValidPathInfo>> result) {
|
||||||
|
try {
|
||||||
|
promise.set_value(result.get());
|
||||||
|
} catch (InvalidPath &) {
|
||||||
|
promise.set_value(nullptr);
|
||||||
|
} catch (...) {
|
||||||
|
promise.set_exception(std::current_exception());
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
|
return promise.get_future().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool goodStorePath(const StorePath & expected, const StorePath & actual)
|
static bool goodStorePath(const StorePath & expected, const StorePath & actual)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue