libstore: asyncify Store::computeFSClosure

Change-Id: I79d3e9c60886a9eb58051a28cdda25dadcead9f1
This commit is contained in:
eldritch horrors
2025-02-23 17:18:48 +00:00
parent f06040f5d8
commit 91387bbb13
17 changed files with 263 additions and 206 deletions
+1 -1
View File
@@ -459,7 +459,7 @@ static void main_nix_build(AsyncIoRoot & aio, std::string programName, Strings a
auto outputs = store->queryPartialDerivationOutputMap(inputDrv, &*evalStore);
for (auto & i : inputNode.value) {
auto o = outputs.at(i);
store->computeFSClosure(*o, inputs);
aio.blockOn(store->computeFSClosure(*o, inputs));
}
for (const auto & [outputName, childNode] : inputNode.childMap)
accumInputClosure(*outputs.at(outputName), childNode);
+13 -6
View File
@@ -358,7 +358,9 @@ static void opQuery(AsyncIoRoot & aio, Strings opFlags, Strings opArgs)
for (auto & i : opArgs) {
auto ps = aio.blockOn(maybeUseOutputs(store->followLinksToStorePath(i), useOutput, forceRealise));
for (auto & j : ps) {
if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs);
if (query == qRequisites) {
aio.blockOn(store->computeFSClosure(j, paths, false, includeOutputs));
}
else if (query == qReferences) {
for (auto & p : store->queryPathInfo(j)->references)
paths.insert(p);
@@ -369,7 +371,8 @@ static void opQuery(AsyncIoRoot & aio, Strings opFlags, Strings opArgs)
for (auto & i : tmp)
paths.insert(i);
}
else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true);
else if (query == qReferrersClosure)
aio.blockOn(store->computeFSClosure(j, paths, true));
}
}
auto sorted = store->topoSortPaths(paths);
@@ -465,8 +468,8 @@ static void opQuery(AsyncIoRoot & aio, Strings opFlags, Strings opArgs)
args.insert(p);
StorePathSet referrers;
store->computeFSClosure(
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations);
aio.blockOn(store->computeFSClosure(
args, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations));
auto & gcStore = require<GcStore>(*store);
Roots roots = aio.blockOn(gcStore.findRoots(false));
@@ -974,8 +977,12 @@ static void opServe(AsyncIoRoot & aio, Strings opFlags, Strings opArgs)
case ServeProto::Command::QueryClosure: {
bool includeOutputs = readInt(in);
StorePathSet closure;
store->computeFSClosure(ServeProto::Serialise<StorePathSet>::read(*store, rconn),
closure, false, includeOutputs);
aio.blockOn(store->computeFSClosure(
ServeProto::Serialise<StorePathSet>::read(*store, rconn),
closure,
false,
includeOutputs
));
out << ServeProto::write(*store, wconn, closure);
break;
}
+1 -1
View File
@@ -178,7 +178,7 @@ void BuiltPathsCommand::run(ref<Store> store, Installables && installables)
auto rootFromThis = root.outPaths();
pathsRoots.insert(rootFromThis.begin(), rootFromThis.end());
}
store->computeFSClosure(pathsRoots, pathsClosure);
aio().blockOn(store->computeFSClosure(pathsRoots, pathsClosure));
for (auto & path : pathsClosure)
paths.emplace_back(BuiltPath::Opaque{path});
}
+1 -1
View File
@@ -295,7 +295,7 @@ EvalPaths::EvalPaths(
if (store->isInStore(path)) {
try {
StorePathSet closure;
store->computeFSClosure(store->toStorePath(path).first, closure);
aio.blockOn(store->computeFSClosure(store->toStorePath(path).first, closure));
for (auto & path : closure)
allowPath(path);
} catch (InvalidPath &) {
+1 -1
View File
@@ -978,7 +978,7 @@ drvName, Bindings * attrs, Value & v)
[&](const NixStringContextElem::DrvDeep & d) {
/* !!! This doesn't work if readOnlyMode is set. */
StorePathSet refs;
state.ctx.store->computeFSClosure(d.drvPath, refs);
state.aio.blockOn(state.ctx.store->computeFSClosure(d.drvPath, refs));
for (auto & j : refs) {
drv.inputSrcs.insert(j);
if (j.isDerivation()) {
+51 -44
View File
@@ -11,6 +11,7 @@
#include "lix/libutil/logging-json.hh"
#include "lix/libstore/build/substitution-goal.hh"
#include "lix/libstore/build/drv-output-substitution-goal.hh"
#include "lix/libutil/result.hh"
#include "lix/libutil/strings.hh"
#include <boost/outcome/try.hpp>
@@ -466,7 +467,7 @@ try {
StorePathSet outputClosure;
for (auto & i : outputs) {
if (!wantedOutputs.contains(i.first)) continue;
worker.store.computeFSClosure(i.second, outputClosure);
TRY_AWAIT(worker.store.computeFSClosure(i.second, outputClosure));
}
/* Filter out our own outputs (which we have already checked). */
@@ -477,7 +478,7 @@ try {
derivation is responsible for which path in the output
closure. */
StorePathSet inputClosure;
if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure);
if (useDerivation) TRY_AWAIT(worker.store.computeFSClosure(drvPath, inputClosure));
std::map<StorePath, StorePath> outputsToDrv;
for (auto & i : inputClosure)
if (i.isDerivation()) {
@@ -619,58 +620,64 @@ try {
co_return co_await resolvedFinished();
}
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
std::function<kj::Promise<Result<void>>(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
accumInputPaths = [&](const StorePath & depDrvPath, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
/* Add the relevant output closures of the input derivation
`i' as input paths. Only add the closures of output paths
that are specified as inputs. */
auto getOutput = [&](const std::string & outputName) {
/* TODO (impure derivations-induced tech debt):
Tracking input derivation outputs statefully through the
goals is error prone and has led to bugs.
For a robust nix, we need to move towards the `else` branch,
which does not rely on goal state to match up with the
reality of the store, which is our real source of truth.
However, the impure derivations feature still relies on this
fragile way of doing things, because its builds do not have
a representation in the store, which is a usability problem
in itself. When implementing this logic entirely with lookups
make sure that they're cached. */
if (auto outPath = get(inputDrvOutputs, { depDrvPath, outputName })) {
return *outPath;
}
else {
auto outMap = [&]{
for (auto * drvStore : { &worker.evalStore, &worker.store })
if (drvStore->isValidPath(depDrvPath))
return worker.store.queryDerivationOutputMap(depDrvPath, drvStore);
assert(false);
}();
auto outMapPath = outMap.find(outputName);
if (outMapPath == outMap.end()) {
throw Error(
"derivation '%s' requires non-existent output '%s' from input derivation '%s'",
worker.store.printStorePath(drvPath), outputName, worker.store.printStorePath(depDrvPath));
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
accumInputPaths = [&](const StorePath & depDrvPath, const DerivedPathMap<StringSet>::ChildNode & inputNode) -> kj::Promise<Result<void>> {
try {
/* Add the relevant output closures of the input derivation
`i' as input paths. Only add the closures of output paths
that are specified as inputs. */
auto getOutput = [&](const std::string & outputName) {
/* TODO (impure derivations-induced tech debt):
Tracking input derivation outputs statefully through the
goals is error prone and has led to bugs.
For a robust nix, we need to move towards the `else` branch,
which does not rely on goal state to match up with the
reality of the store, which is our real source of truth.
However, the impure derivations feature still relies on this
fragile way of doing things, because its builds do not have
a representation in the store, which is a usability problem
in itself. When implementing this logic entirely with lookups
make sure that they're cached. */
if (auto outPath = get(inputDrvOutputs, { depDrvPath, outputName })) {
return *outPath;
}
return outMapPath->second;
}
};
else {
auto outMap = [&]{
for (auto * drvStore : { &worker.evalStore, &worker.store })
if (drvStore->isValidPath(depDrvPath))
return worker.store.queryDerivationOutputMap(depDrvPath, drvStore);
assert(false);
}();
for (auto & outputName : inputNode.value)
worker.store.computeFSClosure(getOutput(outputName), inputPaths);
auto outMapPath = outMap.find(outputName);
if (outMapPath == outMap.end()) {
throw Error(
"derivation '%s' requires non-existent output '%s' from input derivation '%s'",
worker.store.printStorePath(drvPath), outputName, worker.store.printStorePath(depDrvPath));
}
return outMapPath->second;
}
};
for (auto & [outputName, childNode] : inputNode.childMap)
accumInputPaths(getOutput(outputName), childNode);
for (auto & outputName : inputNode.value)
TRY_AWAIT(worker.store.computeFSClosure(getOutput(outputName), inputPaths));
for (auto & [outputName, childNode] : inputNode.childMap)
TRY_AWAIT(accumInputPaths(getOutput(outputName), childNode));
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
};
for (auto & [depDrvPath, depNode] : fullDrv.inputDrvs.map)
accumInputPaths(depDrvPath, depNode);
TRY_AWAIT(accumInputPaths(depDrvPath, depNode));
}
/* Second, the input sources. */
worker.store.computeFSClosure(drv->inputSrcs, inputPaths);
TRY_AWAIT(worker.store.computeFSClosure(drv->inputSrcs, inputPaths));
debug("added input paths %s", worker.store.showPaths(inputPaths));
+6 -3
View File
@@ -610,8 +610,11 @@ try {
StorePathSet closure;
for (auto & i : pathsInChroot)
try {
if (worker.store.isInStore(i.second.source))
worker.store.computeFSClosure(worker.store.toStorePath(i.second.source).first, closure);
if (worker.store.isInStore(i.second.source)) {
TRY_AWAIT(worker.store.computeFSClosure(
worker.store.toStorePath(i.second.source).first, closure
));
}
} catch (InvalidPath & e) {
} catch (Error & e) {
e.addTrace({}, "while processing 'sandbox-paths'");
@@ -1191,7 +1194,7 @@ struct RestrictedStore : public virtual IndirectRootStore, public virtual GcStor
}
StorePathSet closure;
next->computeFSClosure(newPaths, closure);
TRY_AWAIT(next->computeFSClosure(newPaths, closure));
for (auto & path : closure)
goal.addDependency(path);
for (auto & real : Realisation::closure(*next, newRealisations))
+110 -96
View File
@@ -682,111 +682,125 @@ try {
via the referrers edges and optionally derivers and derivation
output edges. If none of those paths are roots, then all
visited paths are garbage and are deleted. */
auto deleteReferrersClosure = [&](const StorePath & start) {
StorePathSet visited;
std::queue<StorePath> todo;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
auto deleteReferrersClosure = [&](const StorePath & start) -> kj::Promise<Result<void>> {
try {
StorePathSet visited;
std::queue<StorePath> todo;
/* Wake up any GC client waiting for deletion of the paths in
'visited' to finish. */
Finally releasePending([&]() {
gcServer.releasePending();
});
/* Wake up any GC client waiting for deletion of the paths in
'visited' to finish. */
Finally releasePending([&]() {
gcServer.releasePending();
});
auto enqueue = [&](const StorePath & path) {
if (visited.insert(path).second)
todo.push(path);
};
enqueue(start);
while (auto path = pop(todo)) {
checkInterrupt();
/* Bail out if we've previously discovered that this path
is alive. */
if (alive.count(*path)) {
alive.insert(start);
return;
}
/* If we've previously deleted this path, we don't have to
handle it again. */
if (dead.count(*path)) continue;
auto markAlive = [&]()
{
alive.insert(*path);
alive.insert(start);
try {
StorePathSet closure;
computeFSClosure(*path, closure,
/* flipDirection */ false, gcKeepOutputs, gcKeepDerivations);
for (auto & p : closure)
alive.insert(p);
} catch (InvalidPath &) { }
auto enqueue = [&](const StorePath & path) {
if (visited.insert(path).second)
todo.push(path);
};
/* If this is a root, bail out. */
if (roots.count(*path)) {
debug("cannot delete '%s' because it's a root", printStorePath(*path));
return markAlive();
}
enqueue(start);
if (options.action == GCOptions::gcDeleteSpecific
&& !options.pathsToDelete.count(*path))
return;
while (auto path = pop(todo)) {
checkInterrupt();
if (!gcServer.markPendingIfPresent(std::string(path->hashPart()))) {
debug("cannot delete '%s' because it's a temporary root", printStorePath(*path));
return markAlive();
}
if (isValidPath(*path)) {
/* Visit the referrers of this path. */
auto i = referrersCache.find(*path);
if (i == referrersCache.end()) {
StorePathSet referrers;
queryReferrers(*path, referrers);
referrersCache.emplace(*path, std::move(referrers));
i = referrersCache.find(*path);
}
for (auto & p : i->second)
enqueue(p);
/* If keep-derivations is set and this is a
derivation, then visit the derivation outputs. */
if (gcKeepDerivations && path->isDerivation()) {
for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(*path))
if (maybeOutPath &&
isValidPath(*maybeOutPath) &&
queryPathInfo(*maybeOutPath)->deriver == *path)
enqueue(*maybeOutPath);
/* Bail out if we've previously discovered that this path
is alive. */
if (alive.count(*path)) {
alive.insert(start);
co_return result::success();
}
/* If keep-outputs is set, then visit the derivers. */
if (gcKeepOutputs) {
auto derivers = queryValidDerivers(*path);
for (auto & i : derivers)
enqueue(i);
}
}
}
/* If we've previously deleted this path, we don't have to
handle it again. */
if (dead.count(*path)) continue;
for (auto & path : topoSortPaths(visited)) {
if (!dead.insert(path).second) continue;
if (shouldDelete) {
try {
invalidatePathChecked(path);
deleteFromStore(path.to_string());
referrersCache.erase(path);
} catch (PathInUse &) {
// References to upstream "bugs":
// https://github.com/NixOS/nix/issues/11923
// https://git.lix.systems/lix-project/lix/issues/621
printInfo("Skipping deletion of path '%1%' because it is now in use, preventing its removal.", printStorePath(path));
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
auto markAlive = [&]() -> kj::Promise<Result<void>>
{
try {
alive.insert(*path);
alive.insert(start);
try {
StorePathSet closure;
TRY_AWAIT(computeFSClosure(*path, closure,
/* flipDirection */ false, gcKeepOutputs, gcKeepDerivations));
for (auto & p : closure)
alive.insert(p);
} catch (InvalidPath &) { }
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
};
/* If this is a root, bail out. */
if (roots.count(*path)) {
debug("cannot delete '%s' because it's a root", printStorePath(*path));
TRY_AWAIT(markAlive());
co_return result::success();
}
if (options.action == GCOptions::gcDeleteSpecific
&& !options.pathsToDelete.count(*path))
co_return result::success();
if (!gcServer.markPendingIfPresent(std::string(path->hashPart()))) {
debug("cannot delete '%s' because it's a temporary root", printStorePath(*path));
TRY_AWAIT(markAlive());
co_return result::success();
}
if (isValidPath(*path)) {
/* Visit the referrers of this path. */
auto i = referrersCache.find(*path);
if (i == referrersCache.end()) {
StorePathSet referrers;
queryReferrers(*path, referrers);
referrersCache.emplace(*path, std::move(referrers));
i = referrersCache.find(*path);
}
for (auto & p : i->second)
enqueue(p);
/* If keep-derivations is set and this is a
derivation, then visit the derivation outputs. */
if (gcKeepDerivations && path->isDerivation()) {
for (auto & [name, maybeOutPath] : queryPartialDerivationOutputMap(*path))
if (maybeOutPath &&
isValidPath(*maybeOutPath) &&
queryPathInfo(*maybeOutPath)->deriver == *path)
enqueue(*maybeOutPath);
}
/* If keep-outputs is set, then visit the derivers. */
if (gcKeepOutputs) {
auto derivers = queryValidDerivers(*path);
for (auto & i : derivers)
enqueue(i);
}
}
}
for (auto & path : topoSortPaths(visited)) {
if (!dead.insert(path).second) continue;
if (shouldDelete) {
try {
invalidatePathChecked(path);
deleteFromStore(path.to_string());
referrersCache.erase(path);
} catch (PathInUse &) {
// References to upstream "bugs":
// https://github.com/NixOS/nix/issues/11923
// https://git.lix.systems/lix-project/lix/issues/621
printInfo("Skipping deletion of path '%1%' because it is now in use, preventing its removal.", printStorePath(path));
}
}
}
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
};
@@ -795,7 +809,7 @@ try {
if (options.action == GCOptions::gcDeleteSpecific) {
for (auto & i : options.pathsToDelete) {
deleteReferrersClosure(i);
TRY_AWAIT(deleteReferrersClosure(i));
if (!dead.count(i))
throw Error(
"Cannot delete path '%1%' since it is still alive. "
@@ -827,7 +841,7 @@ try {
if (name == "." || name == ".." || name == linksName) continue;
if (auto storePath = maybeParseStorePath(config().storeDir + "/" + name))
deleteReferrersClosure(*storePath);
TRY_AWAIT(deleteReferrersClosure(*storePath));
else
deleteFromStore(name);
+9 -4
View File
@@ -384,13 +384,15 @@ public:
kj::Promise<Result<void>> repairPath(const StorePath & path) override
try { unsupported("repairPath"); } catch (...) { return {result::current_exception()}; }
void computeFSClosure(const StorePathSet & paths,
kj::Promise<Result<void>> computeFSClosure(const StorePathSet & paths,
StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false) override
{
try {
if (flipDirection || includeDerivers) {
Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers);
return;
TRY_AWAIT(
Store::computeFSClosure(paths, out, flipDirection, includeOutputs, includeDerivers)
);
co_return result::success();
}
auto conn(connections->get());
@@ -403,6 +405,9 @@ public:
for (auto & i : ServeProto::Serialise<StorePathSet>::read(*this, *conn))
out.insert(i);
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
StorePathSet queryValidPaths(const StorePathSet & paths,
+1 -1
View File
@@ -11,7 +11,7 @@ kj::Promise<Result<std::map<StorePath, StorePath>>> makeContentAddressed(
const StorePathSet & storePaths)
try {
StorePathSet closure;
srcStore.computeFSClosure(storePaths, closure);
TRY_AWAIT(srcStore.computeFSClosure(storePaths, closure));
auto paths = srcStore.topoSortPaths(closure);
+59 -38
View File
@@ -12,59 +12,80 @@
namespace nix {
void Store::computeFSClosure(const StorePathSet & startPaths,
kj::Promise<Result<void>> Store::computeFSClosure(const StorePathSet & startPaths,
StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers)
{
std::function<std::set<StorePath>(const StorePath & path, ref<const ValidPathInfo>)> queryDeps;
if (flipDirection)
queryDeps = [&](const StorePath& path, ref<const ValidPathInfo>) {
StorePathSet res;
StorePathSet referrers;
queryReferrers(path, referrers);
for (auto& ref : referrers)
if (ref != path)
res.insert(ref);
try {
std::function<
kj::Promise<Result<std::set<StorePath>>>(const StorePath & path, ref<const ValidPathInfo>)>
queryDeps;
if (flipDirection) {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
queryDeps = [&](const StorePath & path,
ref<const ValidPathInfo>) -> kj::Promise<Result<std::set<StorePath>>> {
try {
StorePathSet res;
StorePathSet referrers;
queryReferrers(path, referrers);
for (auto& ref : referrers)
if (ref != path)
res.insert(ref);
if (includeOutputs)
for (auto& i : queryValidDerivers(path))
res.insert(i);
if (includeOutputs)
for (auto& i : queryValidDerivers(path))
res.insert(i);
if (includeDerivers && path.isDerivation())
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath && isValidPath(*maybeOutPath))
res.insert(*maybeOutPath);
return res;
if (includeDerivers && path.isDerivation())
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath && isValidPath(*maybeOutPath))
res.insert(*maybeOutPath);
co_return res;
} catch (...) {
co_return result::current_exception();
}
};
else
queryDeps = [&](const StorePath& path, ref<const ValidPathInfo> info) {
StorePathSet res;
for (auto& ref : info->references)
if (ref != path)
res.insert(ref);
} else {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines)
queryDeps = [&](const StorePath & path,
ref<const ValidPathInfo> info) -> kj::Promise<Result<std::set<StorePath>>> {
try {
StorePathSet res;
for (auto& ref : info->references)
if (ref != path)
res.insert(ref);
if (includeOutputs && path.isDerivation())
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath && isValidPath(*maybeOutPath))
res.insert(*maybeOutPath);
if (includeOutputs && path.isDerivation())
for (auto& [_, maybeOutPath] : queryPartialDerivationOutputMap(path))
if (maybeOutPath && isValidPath(*maybeOutPath))
res.insert(*maybeOutPath);
if (includeDerivers && info->deriver && isValidPath(*info->deriver))
res.insert(*info->deriver);
return res;
if (includeDerivers && info->deriver && isValidPath(*info->deriver))
res.insert(*info->deriver);
co_return res;
} catch (...) {
co_return result::current_exception();
}
};
}
paths_.merge(computeClosure<StorePath>(
paths_.merge(TRY_AWAIT(computeClosureAsync<StorePath>(
startPaths,
[&](const StorePath& path) -> std::set<StorePath> {
[&](const StorePath& path) -> kj::Promise<Result<std::set<StorePath>>> {
return queryDeps(path, queryPathInfo(path));
}));
})));
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
void Store::computeFSClosure(const StorePath & startPath,
kj::Promise<Result<void>> Store::computeFSClosure(const StorePath & startPath,
StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers)
{
try {
StorePathSet paths;
paths.insert(startPath);
computeFSClosure(paths, paths_, flipDirection, includeOutputs, includeDerivers);
TRY_AWAIT(computeFSClosure(paths, paths_, flipDirection, includeOutputs, includeDerivers));
co_return result::success();
} catch (...) {
co_return result::current_exception();
}
+1 -1
View File
@@ -169,7 +169,7 @@ try {
StorePathSet initialStorePaths, pathsClosure;
for (auto& path : startPaths)
initialStorePaths.insert(path.path());
store.computeFSClosure(initialStorePaths, pathsClosure);
TRY_AWAIT(store.computeFSClosure(initialStorePaths, pathsClosure));
ret.insert(startPaths.begin(), startPaths.end());
ret.insert(pathsClosure.begin(), pathsClosure.end());
co_return result::success();
+4 -4
View File
@@ -943,7 +943,7 @@ try {
if (!inputPaths.count(storePath))
throw BuildError("cannot export references of path '%s' because it is not in the input closure of the derivation", printStorePath(storePath));
computeFSClosure({storePath}, paths);
TRY_AWAIT(computeFSClosure({storePath}, paths));
}
/* If there are derivations in the graph, then include their
@@ -962,7 +962,7 @@ try {
derivation itself. That doesn't seem right to me, so I
won't try to implemented this for CA derivations. */
throw UnimplementedError("exportReferences on CA derivations is not yet implemented");
computeFSClosure(*k.second.second, paths);
TRY_AWAIT(computeFSClosure(*k.second.second, paths));
}
}
}
@@ -1053,7 +1053,7 @@ Store::getClosureSize(const StorePath & storePath)
try {
uint64_t totalNarSize = 0, totalDownloadSize = 0;
StorePathSet closure;
computeFSClosure(storePath, closure, false, false);
TRY_AWAIT(computeFSClosure(storePath, closure, false, false));
for (auto & p : closure) {
auto info = queryPathInfo(p);
totalNarSize += info->narSize;
@@ -1339,7 +1339,7 @@ try {
if (&srcStore == &dstStore) co_return result::success();
StorePathSet closure;
srcStore.computeFSClosure(storePaths, closure);
TRY_AWAIT(srcStore.computeFSClosure(storePaths, closure));
TRY_AWAIT(copyPaths(srcStore, dstStore, closure, repair, checkSigs, substitute));
co_return result::success();
} catch (...) {
+2 -2
View File
@@ -766,11 +766,11 @@ public:
* `referrers` relation instead of the `references` relation is
* returned.
*/
virtual void computeFSClosure(const StorePathSet & paths,
virtual kj::Promise<Result<void>> computeFSClosure(const StorePathSet & paths,
StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false);
void computeFSClosure(const StorePath & path,
kj::Promise<Result<void>> computeFSClosure(const StorePath & path,
StorePathSet & out, bool flipDirection = false,
bool includeOutputs = false, bool includeDerivers = false);
+1 -1
View File
@@ -46,7 +46,7 @@ struct CmdShowDerivation : InstallablesCommand
if (recursive) {
StorePathSet closure;
store->computeFSClosure(drvPaths, closure);
aio().blockOn(store->computeFSClosure(drvPaths, closure));
drvPaths = std::move(closure);
}
+1 -1
View File
@@ -22,7 +22,7 @@ static kj::Promise<Result<GroupedPaths>>
getClosureInfo(ref<Store> store, const StorePath & toplevel)
try {
StorePathSet closure;
store->computeFSClosure({toplevel}, closure);
TRY_AWAIT(store->computeFSClosure({toplevel}, closure));
GroupedPaths groupedPaths;
+1 -1
View File
@@ -100,7 +100,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
}();
StorePathSet closure;
store->computeFSClosure({packagePath}, closure, false, false);
aio().blockOn(store->computeFSClosure({packagePath}, closure, false, false));
if (!optDependencyPath.has_value() || !closure.count(*optDependencyPath)) {
printError("'%s' does not depend on '%s'", package->what(), dependency->what());