From 90caba8489d32ca0fcd77150deebf1d3e9a06570 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Tue, 4 Mar 2025 23:08:35 +0100 Subject: [PATCH] libstore: asyncify Store::isValidPath Change-Id: I2b98781c04944282fd1219cbec0804fd1ceb6765 --- lix/legacy/build-remote.cc | 2 +- lix/legacy/nix-env.cc | 2 +- lix/legacy/nix-store.cc | 6 ++--- lix/libcmd/repl.cc | 2 +- lix/libexpr/eval-cache.cc | 7 +++--- lix/libexpr/primops.cc | 28 +++++++++++++-------- lix/libexpr/primops/fetchClosure.cc | 7 +++--- lix/libexpr/primops/fetchTree.cc | 2 +- lix/libfetchers/cache.cc | 2 +- lix/libfetchers/path.cc | 4 ++- lix/libstore/binary-cache-store.cc | 4 +-- lix/libstore/build/derivation-goal.cc | 22 ++++++++-------- lix/libstore/build/entry-points.cc | 4 +-- lix/libstore/build/local-derivation-goal.cc | 4 +-- lix/libstore/build/substitution-goal.cc | 14 ++++++----- lix/libstore/daemon.cc | 2 +- lix/libstore/gc.cc | 23 ++++++++++------- lix/libstore/local-fs-store.cc | 4 +-- lix/libstore/local-store.cc | 24 ++++++++++-------- lix/libstore/misc.cc | 14 +++++------ lix/libstore/optimise-store.cc | 3 ++- lix/libstore/remote-fs-accessor.cc | 2 +- lix/libstore/store-api.cc | 22 ++++++++-------- lix/libstore/store-api.hh | 2 +- lix/nix/develop.cc | 2 +- lix/nix/prefetch.cc | 2 +- lix/nix/upgrade-nix.cc | 2 +- perl/lib/Nix/Store.xs | 2 +- 28 files changed, 120 insertions(+), 94 deletions(-) diff --git a/lix/legacy/build-remote.cc b/lix/legacy/build-remote.cc index d0140d66f..85ff12976 100644 --- a/lix/legacy/build-remote.cc +++ b/lix/legacy/build-remote.cc @@ -368,7 +368,7 @@ connected: auto outputPaths = drv.outputsAndOptPaths(*store); for (auto & [outputName, hopefullyOutputPath] : outputPaths) { assert(hopefullyOutputPath.second); - if (!store->isValidPath(*hopefullyOutputPath.second)) + if (!aio.blockOn(store->isValidPath(*hopefullyOutputPath.second))) missingPaths.insert(*hopefullyOutputPath.second); } } diff --git a/lix/legacy/nix-env.cc b/lix/legacy/nix-env.cc index de9ed16c8..74fb44fbf 100644 --- a/lix/legacy/nix-env.cc +++ b/lix/legacy/nix-env.cc @@ -230,7 +230,7 @@ static std::strong_ordering comparePriorities(EvalState & state, DrvInfo & drv1, static bool isPrebuilt(EvalState & state, DrvInfo & elem) { auto path = elem.queryOutPath(state); - if (state.ctx.store->isValidPath(path)) return true; + if (state.aio.blockOn(state.ctx.store->isValidPath(path))) return true; return state.aio.blockOn(state.ctx.store->querySubstitutablePaths({path})).count(path); } diff --git a/lix/legacy/nix-store.cc b/lix/legacy/nix-store.cc index 917cd3e2b..9eb29611e 100644 --- a/lix/legacy/nix-store.cc +++ b/lix/legacy/nix-store.cc @@ -103,7 +103,7 @@ try { else { if (build) TRY_AWAIT(store->ensurePath(path.path)); - else if (!store->isValidPath(path.path)) + else if (!TRY_AWAIT(store->isValidPath(path.path))) throw Error("path '%s' does not exist and cannot be created", store->printStorePath(path.path)); if (store2) { if (gcRoot == "") @@ -563,7 +563,7 @@ static void registerValidity(AsyncIoRoot & aio, bool reregister, bool hashGiven, auto hashResultOpt = !hashGiven ? std::optional { {Hash::dummy, -1} } : std::nullopt; auto info = decodeValidPathInfo(*store, cin, hashResultOpt); if (!info) break; - if (!store->isValidPath(info->path) || reregister) { + if (!aio.blockOn(store->isValidPath(info->path)) || reregister) { /* !!! races */ if (canonicalise) canonicalisePathMetaData(store->printStorePath(info->path), {}); @@ -615,7 +615,7 @@ static void opCheckValidity(AsyncIoRoot & aio, Strings opFlags, Strings opArgs) for (auto & i : opArgs) { auto path = store->followLinksToStorePath(i); - if (!store->isValidPath(path)) { + if (!aio.blockOn(store->isValidPath(path))) { if (printInvalid) cout << fmt("%s\n", store->printStorePath(path)); else diff --git a/lix/libcmd/repl.cc b/lix/libcmd/repl.cc index 5353bb16e..203f9414d 100644 --- a/lix/libcmd/repl.cc +++ b/lix/libcmd/repl.cc @@ -495,7 +495,7 @@ StorePath NixRepl::getDerivationPath(Value & v) { auto drvPath = drvInfo->queryDrvPath(state); if (!drvPath) throw Error("expression did not evaluate to a valid derivation (no 'drvPath' attribute)"); - if (!evaluator.store->isValidPath(*drvPath)) + if (!state.aio.blockOn(evaluator.store->isValidPath(*drvPath))) throw Error("expression evaluated to invalid derivation '%s'", evaluator.store->printStorePath(*drvPath)); return *drvPath; } diff --git a/lix/libexpr/eval-cache.cc b/lix/libexpr/eval-cache.cc index 10040c1cc..03d11ebdb 100644 --- a/lix/libexpr/eval-cache.cc +++ b/lix/libexpr/eval-cache.cc @@ -2,6 +2,7 @@ #include "lix/libstore/sqlite.hh" #include "lix/libexpr/eval.hh" #include "lix/libstore/store-api.hh" +#include "lix/libutil/async.hh" #include "lix/libutil/users.hh" namespace nix::eval_cache { @@ -585,7 +586,7 @@ string_t AttrCursor::getStringWithContext(EvalState & state) return o.path; }, }, c.raw); - if (!state.ctx.store->isValidPath(path)) { + if (!state.aio.blockOn(state.ctx.store->isValidPath(path))) { valid = false; break; } @@ -729,11 +730,11 @@ StorePath AttrCursor::forceDerivation(EvalState & state) { auto aDrvPath = getAttr(state, "drvPath"); auto drvPath = state.ctx.store->parseStorePath(aDrvPath->getString(state)); - if (!state.ctx.store->isValidPath(drvPath) && !settings.readOnlyMode) { + if (!state.aio.blockOn(state.ctx.store->isValidPath(drvPath)) && !settings.readOnlyMode) { /* The eval cache contains 'drvPath', but the actual path has been garbage-collected. So force it to be regenerated. */ aDrvPath->forceValue(state); - if (!state.ctx.store->isValidPath(drvPath)) + if (!state.aio.blockOn(state.ctx.store->isValidPath(drvPath))) throw Error("don't know how to recreate store derivation '%s'!", state.ctx.store->printStorePath(drvPath)); } diff --git a/lix/libexpr/primops.cc b/lix/libexpr/primops.cc index 9121d27fd..e1a9be9ce 100644 --- a/lix/libexpr/primops.cc +++ b/lix/libexpr/primops.cc @@ -17,8 +17,10 @@ #include "lix/libexpr/value-to-xml.hh" #include "lix/libexpr/primops.hh" #include "lix/libfetchers/fetch-to-store.hh" +#include "lix/libutil/result.hh" #include +#include #include #include @@ -46,30 +48,36 @@ try { StringMap res; for (auto & c : context) { - auto ensureValid = [&](const StorePath & p) { - if (!store->isValidPath(p)) - errors.make(store->printStorePath(p)).debugThrow(); + // NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines) + auto ensureValid = [&](const StorePath & p) -> kj::Promise> { + try { + if (!TRY_AWAIT(store->isValidPath(p))) + errors.make(store->printStorePath(p)).debugThrow(); + co_return result::success(); + } catch (...) { + co_return result::current_exception(); + } }; - std::visit(overloaded { + TRY_AWAIT(std::visit(overloaded { [&](const NixStringContextElem::Built & b) { drvs.push_back(DerivedPath::Built { .drvPath = b.drvPath, .outputs = OutputsSpec::Names { b.output }, }); - ensureValid(b.drvPath->getBaseStorePath()); + return ensureValid(b.drvPath->getBaseStorePath()); }, [&](const NixStringContextElem::Opaque & o) { auto ctxS = store->printStorePath(o.path); res.insert_or_assign(ctxS, ctxS); - ensureValid(o.path); + return ensureValid(o.path); }, [&](const NixStringContextElem::DrvDeep & d) { /* Treat same as Opaque */ auto ctxS = store->printStorePath(d.drvPath); res.insert_or_assign(ctxS, ctxS); - ensureValid(d.drvPath); + return ensureValid(d.drvPath); }, - }, c.raw); + }, c.raw)); } if (drvs.empty()) co_return StringMap{}; @@ -184,7 +192,7 @@ static void import(EvalState & state, const PosIdx pos, Value & vPath, Value * v if (!state.ctx.store->isStorePath(path2)) return std::nullopt; auto storePath = state.ctx.store->parseStorePath(path2); - if (!(state.ctx.store->isValidPath(storePath) && isDerivation(path2))) + if (!(state.aio.blockOn(state.ctx.store->isValidPath(storePath)) && isDerivation(path2))) return std::nullopt; return storePath; }; @@ -1565,7 +1573,7 @@ static void addPath( .references = {}, }); - if (!expectedHash || !state.ctx.store->isValidPath(*expectedStorePath)) { + if (!expectedHash || !state.aio.blockOn(state.ctx.store->isValidPath(*expectedStorePath))) { auto checkedPath = state.ctx.paths.checkSourcePath(CanonPath(realPath)); auto dstPath = state.aio.blockOn( method == FileIngestionMethod::Flat diff --git a/lix/libexpr/primops/fetchClosure.cc b/lix/libexpr/primops/fetchClosure.cc index eea0e5d65..9912f8bc7 100644 --- a/lix/libexpr/primops/fetchClosure.cc +++ b/lix/libexpr/primops/fetchClosure.cc @@ -2,6 +2,7 @@ #include "lix/libexpr/extra-primops.hh" #include "lix/libstore/store-api.hh" #include "lix/libstore/make-content-addressed.hh" +#include "lix/libutil/async.hh" #include "lix/libutil/url.hh" namespace nix { @@ -19,7 +20,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor // establish toPath or throw - if (!toPathMaybe || !state.ctx.store->isValidPath(*toPathMaybe)) { + if (!toPathMaybe || !state.aio.blockOn(state.ctx.store->isValidPath(*toPathMaybe))) { auto rewrittenPath = state.aio.blockOn(makeContentAddressed(fromStore, *state.ctx.store, fromPath)); if (toPathMaybe && *toPathMaybe != rewrittenPath) @@ -67,7 +68,7 @@ static void runFetchClosureWithRewrite(EvalState & state, const PosIdx pos, Stor */ static void runFetchClosureWithContentAddressedPath(EvalState & state, const PosIdx pos, Store & fromStore, const StorePath & fromPath, Value & v) { - if (!state.ctx.store->isValidPath(fromPath)) + if (!state.aio.blockOn(state.ctx.store->isValidPath(fromPath))) state.aio.blockOn(copyClosure(fromStore, *state.ctx.store, RealisedPath::Set { fromPath })); auto info = state.ctx.store->queryPathInfo(fromPath); @@ -93,7 +94,7 @@ static void runFetchClosureWithContentAddressedPath(EvalState & state, const Pos */ static void runFetchClosureWithInputAddressedPath(EvalState & state, const PosIdx pos, Store & fromStore, const StorePath & fromPath, Value & v) { - if (!state.ctx.store->isValidPath(fromPath)) + if (!state.aio.blockOn(state.ctx.store->isValidPath(fromPath))) state.aio.blockOn(copyClosure(fromStore, *state.ctx.store, RealisedPath::Set { fromPath })); auto info = state.ctx.store->queryPathInfo(fromPath); diff --git a/lix/libexpr/primops/fetchTree.cc b/lix/libexpr/primops/fetchTree.cc index b3fdcddb4..037137dbe 100644 --- a/lix/libexpr/primops/fetchTree.cc +++ b/lix/libexpr/primops/fetchTree.cc @@ -262,7 +262,7 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v .references = {} }); - if (state.ctx.store->isValidPath(expectedPath)) { + if (state.aio.blockOn(state.ctx.store->isValidPath(expectedPath))) { state.ctx.paths.allowAndSetStorePathString(expectedPath, v); return; } diff --git a/lix/libfetchers/cache.cc b/lix/libfetchers/cache.cc index 0d9cc9e50..c69b257a8 100644 --- a/lix/libfetchers/cache.cc +++ b/lix/libfetchers/cache.cc @@ -110,7 +110,7 @@ struct CacheImpl : Cache auto timestamp = stmt.getInt(3); TRY_AWAIT(store->addTempRoot(storePath)); - if (!store->isValidPath(storePath)) { + if (!TRY_AWAIT(store->isValidPath(storePath))) { // FIXME: we could try to substitute 'storePath'. debug("ignoring disappeared cache entry '%s'", inAttrsJSON); co_return std::nullopt; diff --git a/lix/libfetchers/path.cc b/lix/libfetchers/path.cc index b6ccf723c..94938edce 100644 --- a/lix/libfetchers/path.cc +++ b/lix/libfetchers/path.cc @@ -131,7 +131,9 @@ struct PathInputScheme : InputScheme TRY_AWAIT(store->addTempRoot(*storePath)); time_t mtime = 0; - if (!storePath || storePath->name() != "source" || !store->isValidPath(*storePath)) { + if (!storePath || storePath->name() != "source" + || !TRY_AWAIT(store->isValidPath(*storePath))) + { // FIXME: try to substitute storePath. auto src = AsyncGeneratorInputStream{dumpPathAndGetMtime(absPath, mtime)}; storePath = TRY_AWAIT(store->addToStoreFromDump(src, "source")); diff --git a/lix/libstore/binary-cache-store.cc b/lix/libstore/binary-cache-store.cc index 526a635a7..8e802a1d8 100644 --- a/lix/libstore/binary-cache-store.cc +++ b/lix/libstore/binary-cache-store.cc @@ -277,7 +277,7 @@ kj::Promise> BinaryCacheStore::addToStore( CheckSigsFlag checkSigs ) try { - if (!repair && isValidPath(info.path)) { + if (!repair && TRY_AWAIT(isValidPath(info.path))) { // FIXME: copyNAR -> null sink TRY_AWAIT(narSource.drain()); co_return result::success(); @@ -477,7 +477,7 @@ try { auto textHash = hashString(HashType::SHA256, s); auto path = makeTextPath(name, TextInfo { { textHash }, references }); - if (!repair && isValidPath(path)) + if (!repair && TRY_AWAIT(isValidPath(path))) co_return path; StringSink sink; diff --git a/lix/libstore/build/derivation-goal.cc b/lix/libstore/build/derivation-goal.cc index 4c7b210ea..105e4f4ad 100644 --- a/lix/libstore/build/derivation-goal.cc +++ b/lix/libstore/build/derivation-goal.cc @@ -170,7 +170,7 @@ try { /* The first thing to do is to make sure that the derivation exists. If it doesn't, it may be created through a substitute. */ - if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) { + if (buildMode == bmNormal && TRY_AWAIT(worker.evalStore.isValidPath(drvPath))) { co_return co_await loadDerivation(); } @@ -205,7 +205,7 @@ try { - Dynamic derivations are built, and so are found in the main store. */ for (auto * drvStore : { &worker.evalStore, &worker.store }) { - if (drvStore->isValidPath(drvPath)) { + if (TRY_AWAIT(drvStore->isValidPath(drvPath))) { drv = std::make_unique(TRY_AWAIT(drvStore->readDerivation(drvPath))); break; } @@ -232,7 +232,7 @@ try { for (auto & [outputName, output] : drv->outputs) { auto randomPath = StorePath::random(outputPathName(drv->name, outputName)); - assert(!worker.store.isValidPath(randomPath)); + assert(!TRY_AWAIT(worker.store.isValidPath(randomPath))); initialOutputs.insert({ outputName, InitialOutput { @@ -431,13 +431,13 @@ try { if (&worker.evalStore != &worker.store) { RealisedPath::Set inputSrcs; for (auto & i : drv->inputSrcs) - if (worker.evalStore.isValidPath(i)) + if (TRY_AWAIT(worker.evalStore.isValidPath(i))) inputSrcs.insert(i); TRY_AWAIT(copyClosure(worker.evalStore, worker.store, inputSrcs)); } for (auto & i : drv->inputSrcs) { - if (worker.store.isValidPath(i)) continue; + if (TRY_AWAIT(worker.store.isValidPath(i))) continue; if (!settings.useSubstitutes) throw Error("dependency '%s' of '%s' does not exist, and substitution is disabled", worker.store.printStorePath(i), worker.store.printStorePath(drvPath)); @@ -648,9 +648,9 @@ try { co_return *outPath; } else { - auto outMap = worker.evalStore.isValidPath(depDrvPath) + auto outMap = TRY_AWAIT(worker.evalStore.isValidPath(depDrvPath)) ? TRY_AWAIT(worker.store.queryDerivationOutputMap(depDrvPath, &worker.evalStore)) - : worker.store.isValidPath(depDrvPath) + : TRY_AWAIT(worker.store.isValidPath(depDrvPath)) ? TRY_AWAIT(worker.store.queryDerivationOutputMap(depDrvPath, &worker.store)) : (assert(false), OutputPathMap{}); @@ -1191,7 +1191,7 @@ try { newRealisation.id = DrvOutput { initialOutput->outputHash, outputName }; newRealisation.signatures.clear(); if (!drv->type().isFixed()) { - auto & drvStore = worker.evalStore.isValidPath(drvPath) + auto & drvStore = TRY_AWAIT(worker.evalStore.isValidPath(drvPath)) ? worker.evalStore : worker.store; newRealisation.dependentRealisations = TRY_AWAIT( @@ -1619,7 +1619,7 @@ try { co_return res; } else { for (auto * drvStore : {&worker.evalStore, &worker.store}) { - if (drvStore->isValidPath(drvPath)) { + if (TRY_AWAIT(drvStore->isValidPath(drvPath))) { co_return TRY_AWAIT(worker.store.queryPartialDerivationOutputMap(drvPath, drvStore) ); } @@ -1640,7 +1640,7 @@ try { co_return res; } else { for (auto * drvStore : {&worker.evalStore, &worker.store}) { - if (drvStore->isValidPath(drvPath)) { + if (TRY_AWAIT(drvStore->isValidPath(drvPath))) { co_return TRY_AWAIT(worker.store.queryDerivationOutputMap(drvPath, drvStore)); } } @@ -1679,7 +1679,7 @@ try { auto outputPath = *i.second; info.known = { .path = outputPath, - .status = !worker.store.isValidPath(outputPath) + .status = !TRY_AWAIT(worker.store.isValidPath(outputPath)) ? PathStatus::Absent : !checkHash || TRY_AWAIT(worker.pathContentsGood(outputPath)) ? PathStatus::Valid diff --git a/lix/libstore/build/entry-points.cc b/lix/libstore/build/entry-points.cc index 065a23d59..b2a29c0cb 100644 --- a/lix/libstore/build/entry-points.cc +++ b/lix/libstore/build/entry-points.cc @@ -110,7 +110,7 @@ try { kj::Promise> Store::ensurePath(const StorePath & path) try { /* If the path is already valid, we're done. */ - if (isValidPath(path)) co_return result::success(); + if (TRY_AWAIT(isValidPath(path))) co_return result::success(); auto results = TRY_AWAIT(processGoals(*this, *this, [&](GoalFactory & gf) { Worker::Targets goals; @@ -146,7 +146,7 @@ try { /* Since substituting the path didn't work, if we have a valid deriver, then rebuild the deriver. */ auto info = queryPathInfo(path); - if (info->deriver && isValidPath(*info->deriver)) { + if (info->deriver && TRY_AWAIT(isValidPath(*info->deriver))) { TRY_AWAIT(processGoals(*this, *this, [&](GoalFactory & gf) { Worker::Targets goals; goals.emplace_back(gf.makeGoal( diff --git a/lix/libstore/build/local-derivation-goal.cc b/lix/libstore/build/local-derivation-goal.cc index 76ed4300c..c19287c23 100644 --- a/lix/libstore/build/local-derivation-goal.cc +++ b/lix/libstore/build/local-derivation-goal.cc @@ -2386,7 +2386,7 @@ try { } else if (buildMode == bmCheck) { /* Path already exists, and we want to compare, so we leave out new path in place. */ - } else if (worker.store.isValidPath(newInfo.path)) { + } else if (TRY_AWAIT(worker.store.isValidPath(newInfo.path))) { /* Path already exists because CA path produced by something else. No moving needed. */ assert(newInfo.ca); @@ -2402,7 +2402,7 @@ try { if (buildMode == bmCheck) { - if (!worker.store.isValidPath(newInfo.path)) continue; + if (!TRY_AWAIT(worker.store.isValidPath(newInfo.path))) continue; ValidPathInfo oldInfo(*worker.store.queryPathInfo(newInfo.path)); if (newInfo.narHash != oldInfo.narHash) { anyCheckMismatchSeen = true; diff --git a/lix/libstore/build/substitution-goal.cc b/lix/libstore/build/substitution-goal.cc index 8b90acae9..d4c4acfef 100644 --- a/lix/libstore/build/substitution-goal.cc +++ b/lix/libstore/build/substitution-goal.cc @@ -55,7 +55,7 @@ try { TRY_AWAIT(worker.store.addTempRoot(storePath)); /* If the path already exists we're done. */ - if (!repair && worker.store.isValidPath(storePath)) { + if (!repair && TRY_AWAIT(worker.store.isValidPath(storePath))) { co_return done(ecSuccess, BuildResult::AlreadyValid); } @@ -180,19 +180,21 @@ try { trace("all references realised"); if (nrFailed > 0) { - return {done( + co_return done( nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed, BuildResult::DependencyFailed, - fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)))}; + fmt("some references of path '%s' could not be realised", + worker.store.printStorePath(storePath)) + ); } for (auto & i : info->references) if (i != storePath) /* ignore self-references */ - assert(worker.store.isValidPath(i)); + assert(TRY_AWAIT(worker.store.isValidPath(i))); - return tryToRun(); + co_return TRY_AWAIT(tryToRun()); } catch (...) { - return {result::current_exception()}; + co_return result::current_exception(); } diff --git a/lix/libstore/daemon.cc b/lix/libstore/daemon.cc index fe053c233..055feeb0b 100644 --- a/lix/libstore/daemon.cc +++ b/lix/libstore/daemon.cc @@ -275,7 +275,7 @@ static void performOp(AsyncIoRoot & aio, TunnelLogger * logger, ref store case WorkerProto::Op::IsValidPath: { auto path = store->parseStorePath(readString(from)); logger->startWork(); - bool result = store->isValidPath(path); + bool result = aio.blockOn(store->isValidPath(path)); logger->stopWork(); to << result; break; diff --git a/lix/libstore/gc.cc b/lix/libstore/gc.cc index c454b654c..de9542aac 100644 --- a/lix/libstore/gc.cc +++ b/lix/libstore/gc.cc @@ -257,14 +257,19 @@ void LocalStore::findTempRoots(Roots & tempRoots, bool censor) kj::Promise> LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) try { - auto foundRoot = [&](const Path & path, const Path & target) { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-capturing-lambda-coroutines) + auto foundRoot = [&](const Path & path, const Path & target) -> kj::Promise> { try { auto storePath = toStorePath(target).first; - if (isValidPath(storePath)) + if (TRY_AWAIT(isValidPath(storePath))) roots[std::move(storePath)].emplace(path); else printInfo("skipping invalid root from '%1%' to '%2%'", path, target); - } catch (BadStorePath &) { } + } catch (BadStorePath &) { + } catch (...) { + co_return result::current_exception(); + } + co_return result::success(); }; try { @@ -280,7 +285,7 @@ try { else if (type == DT_LNK) { Path target = readLink(path); if (isInStore(target)) - foundRoot(path, target); + TRY_AWAIT(foundRoot(path, target)); /* Handle indirect roots. */ else { @@ -294,7 +299,7 @@ try { struct stat st2 = lstat(target); if (!S_ISLNK(st2.st_mode)) co_return result::success(); Path target2 = readLink(target); - if (isInStore(target2)) foundRoot(target, target2); + if (isInStore(target2)) TRY_AWAIT(foundRoot(target, target2)); } } } @@ -302,7 +307,7 @@ try { else if (type == DT_REG) { auto storePath = maybeParseStorePath(config().storeDir + "/" + std::string(baseNameOf(path))); - if (storePath && isValidPath(*storePath)) + if (storePath && TRY_AWAIT(isValidPath(*storePath))) roots[std::move(*storePath)].emplace(path); } @@ -380,7 +385,7 @@ try { if (!isInStore(target)) continue; try { auto path = toStorePath(target).first; - if (!isValidPath(path)) continue; + if (!TRY_AWAIT(isValidPath(path))) continue; debug("got additional root '%1%'", printStorePath(path)); if (censor) roots[path].insert(censored); @@ -754,7 +759,7 @@ try { co_return result::success(); } - if (isValidPath(*path)) { + if (TRY_AWAIT(isValidPath(*path))) { /* Visit the referrers of this path. */ auto i = referrersCache.find(*path); @@ -774,7 +779,7 @@ try { TRY_AWAIT(queryPartialDerivationOutputMap(*path))) { if (maybeOutPath && - isValidPath(*maybeOutPath) && + TRY_AWAIT(isValidPath(*maybeOutPath)) && queryPathInfo(*maybeOutPath)->deriver == *path) enqueue(*maybeOutPath); } diff --git a/lix/libstore/local-fs-store.cc b/lix/libstore/local-fs-store.cc index 2c824f159..62c3035ca 100644 --- a/lix/libstore/local-fs-store.cc +++ b/lix/libstore/local-fs-store.cc @@ -17,7 +17,7 @@ struct LocalStoreAccessor : public FSAccessor kj::Promise> toRealPath(const Path & path, bool requireValidPath = true) try { auto storePath = store->toStorePath(path).first; - if (requireValidPath && !store->isValidPath(storePath)) + if (requireValidPath && !TRY_AWAIT(store->isValidPath(storePath))) throw InvalidPath("path '%1%' does not exist in the store", store->printStorePath(storePath)); co_return store->getRealStoreDir() + std::string(path, store->config().storeDir.size()); } catch (...) { @@ -86,7 +86,7 @@ ref LocalFSStore::getFSAccessor() kj::Promise>> LocalFSStore::narFromPath(const StorePath & path) try { - if (!isValidPath(path)) + if (!TRY_AWAIT(isValidPath(path))) throw Error("path '%s' does not exist in store", printStorePath(path)); co_return make_box_ptr( dumpPath(getRealStoreDir() + std::string(printStorePath(path), config().storeDir.size())) diff --git a/lix/libstore/local-store.cc b/lix/libstore/local-store.cc index 8f52b51de..16913f67b 100644 --- a/lix/libstore/local-store.cc +++ b/lix/libstore/local-store.cc @@ -1018,7 +1018,7 @@ LocalStore::queryValidPaths(const StorePathSet & paths, SubstituteFlag maybeSubs try { StorePathSet res; for (auto & i : paths) - if (isValidPath(i)) res.insert(i); + if (TRY_AWAIT(isValidPath(i))) res.insert(i); co_return res; } catch (...) { co_return result::current_exception(); @@ -1310,7 +1310,7 @@ try { TRY_AWAIT(addTempRoot(info.path)); - if (repair || !isValidPath(info.path)) { + if (repair || !TRY_AWAIT(isValidPath(info.path))) { std::optional outputLock; @@ -1322,7 +1322,7 @@ try { if (!locksHeld.count(printStorePath(info.path))) outputLock = TRY_AWAIT(lockPathAsync(realPath)); - if (repair || !isValidPath(info.path)) { + if (repair || !TRY_AWAIT(isValidPath(info.path))) { deletePath(realPath); @@ -1495,7 +1495,7 @@ try { TRY_AWAIT(addTempRoot(dstPath)); - if (repair || !isValidPath(dstPath)) { + if (repair || !TRY_AWAIT(isValidPath(dstPath))) { /* The first check above is an optimisation to prevent unnecessary lock acquisition. */ @@ -1504,7 +1504,7 @@ try { PathLock outputLock = TRY_AWAIT(lockPathAsync(realPath)); - if (repair || !isValidPath(dstPath)) { + if (repair || !TRY_AWAIT(isValidPath(dstPath))) { deletePath(realPath); @@ -1565,13 +1565,13 @@ try { TRY_AWAIT(addTempRoot(dstPath)); - if (repair || !isValidPath(dstPath)) { + if (repair || !TRY_AWAIT(isValidPath(dstPath))) { auto realPath = Store::toRealPath(dstPath); PathLock outputLock = TRY_AWAIT(lockPathAsync(realPath)); - if (repair || !isValidPath(dstPath)) { + if (repair || !TRY_AWAIT(isValidPath(dstPath))) { deletePath(realPath); @@ -1725,6 +1725,7 @@ try { Hash nullHash(HashType::SHA256); for (auto & i : validPaths) { + std::optional caught; try { auto info = std::const_pointer_cast(std::shared_ptr(queryPathInfo(i))); @@ -1766,12 +1767,15 @@ try { } } catch (Error & e) { + caught = std::move(e); + } + if (caught) { /* It's possible that the path got GC'ed, so ignore errors on invalid paths. */ - if (isValidPath(i)) - logError(e.info()); + if (TRY_AWAIT(isValidPath(i))) + logError(caught->info()); else - warn(e.msg()); + warn(caught->msg()); errors = true; } } diff --git a/lix/libstore/misc.cc b/lix/libstore/misc.cc index acd2d79ea..ddb558b72 100644 --- a/lix/libstore/misc.cc +++ b/lix/libstore/misc.cc @@ -37,7 +37,7 @@ try { if (includeDerivers && path.isDerivation()) for (auto& [_, maybeOutPath] : TRY_AWAIT(queryPartialDerivationOutputMap(path))) - if (maybeOutPath && isValidPath(*maybeOutPath)) + if (maybeOutPath && TRY_AWAIT(isValidPath(*maybeOutPath))) res.insert(*maybeOutPath); co_return res; } catch (...) { @@ -56,10 +56,10 @@ try { if (includeOutputs && path.isDerivation()) for (auto& [_, maybeOutPath] : TRY_AWAIT(queryPartialDerivationOutputMap(path))) - if (maybeOutPath && isValidPath(*maybeOutPath)) + if (maybeOutPath && TRY_AWAIT(isValidPath(*maybeOutPath))) res.insert(*maybeOutPath); - if (includeDerivers && info->deriver && isValidPath(*info->deriver)) + if (includeDerivers && info->deriver && TRY_AWAIT(isValidPath(*info->deriver))) res.insert(*info->deriver); co_return res; } catch (...) { @@ -236,7 +236,7 @@ struct QueryMissingContext } auto & drvPath = drvPathP->path; - if (!store.isValidPath(drvPath)) { + if (!aio.blockOn(store.isValidPath(drvPath))) { // FIXME: we could try to substitute the derivation. auto state(state_.lock()); state->unknown.insert(drvPath); @@ -254,7 +254,7 @@ struct QueryMissingContext knownOutputPaths = false; break; } - if (bfd.outputs.contains(outputName) && !store.isValidPath(*pathOpt)) + if (bfd.outputs.contains(outputName) && !aio.blockOn(store.isValidPath(*pathOpt))) invalid.insert(*pathOpt); } if (knownOutputPaths && invalid.empty()) return; @@ -280,7 +280,7 @@ struct QueryMissingContext if (!realisation) continue; found = true; - if (!store.isValidPath(realisation->outPath)) + if (!aio.blockOn(store.isValidPath(realisation->outPath))) invalid.insert(realisation->outPath); break; } @@ -306,7 +306,7 @@ struct QueryMissingContext void doPathOpaque(AsyncIoRoot & aio, const DerivedPath::Opaque & bo) { - if (store.isValidPath(bo.path)) return; + if (aio.blockOn(store.isValidPath(bo.path))) return; SubstitutablePathInfos infos; aio.blockOn(store.querySubstitutablePathInfos({{bo.path, std::nullopt}}, infos)); diff --git a/lix/libstore/optimise-store.cc b/lix/libstore/optimise-store.cc index 21a9f1858..3e04ce3dd 100644 --- a/lix/libstore/optimise-store.cc +++ b/lix/libstore/optimise-store.cc @@ -1,5 +1,6 @@ #include "lix/libstore/local-store.hh" #include "lix/libstore/globals.hh" +#include "lix/libutil/async.hh" #include "lix/libutil/result.hh" #include "lix/libutil/signals.hh" #include "lix/libutil/strings.hh" @@ -270,7 +271,7 @@ try { for (auto & i : paths) { TRY_AWAIT(addTempRoot(i)); - if (!isValidPath(i)) continue; /* path was GC'ed, probably */ + if (!TRY_AWAIT(isValidPath(i))) continue; /* path was GC'ed, probably */ { Activity act(*logger, lvlTalkative, actUnknown, fmt("optimising path '%s'", printStorePath(i))); optimisePath_( diff --git a/lix/libstore/remote-fs-accessor.cc b/lix/libstore/remote-fs-accessor.cc index 24450ad7b..78b7f58fd 100644 --- a/lix/libstore/remote-fs-accessor.cc +++ b/lix/libstore/remote-fs-accessor.cc @@ -58,7 +58,7 @@ try { auto [storePath, restPath] = store->toStorePath(path); - if (requireValidPath && !store->isValidPath(storePath)) + if (requireValidPath && !TRY_AWAIT(store->isValidPath(storePath))) throw InvalidPath("path '%1%' does not exist in remote store", store->printStorePath(storePath)); auto i = nars.find(std::string(storePath.hashPart())); diff --git a/lix/libstore/store-api.cc b/lix/libstore/store-api.cc index e9364f63d..f4ebb3b30 100644 --- a/lix/libstore/store-api.cc +++ b/lix/libstore/store-api.cc @@ -339,7 +339,7 @@ try { auto & [info, _] = *infosMap.at(path); - if (isValidPath(info.path)) { + if (aio.blockOn(isValidPath(info.path))) { nrDone++; showProgress(); return StorePathSet(); @@ -365,7 +365,7 @@ try { LegacySSHStore::narFromPath()'s connection lock. */ auto source = std::move(source_); - if (!isValidPath(info.path)) { + if (!aio.blockOn(isValidPath(info.path))) { MaintainCount mc(nrRunning); showProgress(); try { @@ -463,7 +463,7 @@ try { }; info.narSize = narSize; - if (!isValidPath(info.path)) { + if (!TRY_AWAIT(isValidPath(info.path))) { auto source = AsyncGeneratorInputStream{dumpPath(srcPath)}; TRY_AWAIT(addToStore(info, source)); } @@ -633,14 +633,14 @@ try { } -bool Store::isValidPath(const StorePath & storePath) -{ +kj::Promise> Store::isValidPath(const StorePath & storePath) +try { { auto state_(state.lock()); auto res = state_->pathInfoCache.get(std::string(storePath.to_string())); if (res && res->isKnownNow()) { stats.narInfoReadAverted++; - return res->didExist(); + co_return res->didExist(); } } @@ -651,7 +651,7 @@ bool Store::isValidPath(const StorePath & storePath) auto state_(state.lock()); state_->pathInfoCache.upsert(std::string(storePath.to_string()), res.first == NarInfoDiskCache::oInvalid ? PathInfoCacheValue{} : PathInfoCacheValue { .value = res.second }); - return res.first == NarInfoDiskCache::oValid; + co_return res.first == NarInfoDiskCache::oValid; } } @@ -661,7 +661,9 @@ bool Store::isValidPath(const StorePath & storePath) // FIXME: handle valid = true case. diskCache->upsertNarInfo(getUri(), std::string(storePath.hashPart()), 0); - return valid; + co_return valid; +} catch (...) { + co_return result::current_exception(); } @@ -1093,7 +1095,7 @@ kj::Promise> copyStorePath( try { /* Bail out early (before starting a download from srcStore) if dstStore already has this path. */ - if (!repair && dstStore.isValidPath(storePath)) + if (!repair && TRY_AWAIT(dstStore.isValidPath(storePath))) co_return result::success(); auto srcUri = srcStore.getUri(); @@ -1416,7 +1418,7 @@ try { } } - if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations) || !isValidPath(path)) + if (!experimentalFeatureSettings.isEnabled(Xp::CaDerivations) || !TRY_AWAIT(isValidPath(path))) co_return path; auto drv = TRY_AWAIT(readDerivation(path)); diff --git a/lix/libstore/store-api.hh b/lix/libstore/store-api.hh index 164716151..829070067 100644 --- a/lix/libstore/store-api.hh +++ b/lix/libstore/store-api.hh @@ -346,7 +346,7 @@ public: * Check whether a path is valid. * A path is valid when it exists in the store *now*. */ - bool isValidPath(const StorePath & path); + kj::Promise> isValidPath(const StorePath & path); protected: diff --git a/lix/nix/develop.cc b/lix/nix/develop.cc index d4519937f..dcf261ad9 100644 --- a/lix/nix/develop.cc +++ b/lix/nix/develop.cc @@ -270,7 +270,7 @@ try { { assert(optPath); auto & outPath = *optPath; - assert(store->isValidPath(outPath)); + assert(TRY_AWAIT(store->isValidPath(outPath))); auto outPathS = store->toRealPath(outPath); if (lstat(outPathS).st_size) co_return outPath; diff --git a/lix/nix/prefetch.cc b/lix/nix/prefetch.cc index 10fdadb94..9d23c1d67 100644 --- a/lix/nix/prefetch.cc +++ b/lix/nix/prefetch.cc @@ -79,7 +79,7 @@ std::tuple prefetchFile( .hash = *expectedHash, .references = {}, }); - if (store->isValidPath(*storePath)) + if (aio.blockOn(store->isValidPath(*storePath))) hash = expectedHash; else storePath.reset(); diff --git a/lix/nix/upgrade-nix.cc b/lix/nix/upgrade-nix.cc index 15de76255..bcafa9e96 100644 --- a/lix/nix/upgrade-nix.cc +++ b/lix/nix/upgrade-nix.cc @@ -195,7 +195,7 @@ struct CmdUpgradeNix : MixDryRun, EvalCommand ); } - if (!store->isValidPath(store->parseStorePath(userEnv))) { + if (!aio().blockOn(store->isValidPath(store->parseStorePath(userEnv)))) { throw Error("directory '%s' is not in the Nix store", userEnv); } diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index aafe838d4..033852c74 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -68,7 +68,7 @@ void setVerbosity(int level) int isValidPath(char * path) CODE: try { - RETVAL = store()->isValidPath(store()->parseStorePath(path)); + RETVAL = aio().blockOn(store()->isValidPath(store()->parseStorePath(path))); } catch (Error & e) { croak("%s", e.what()); }