libstore: have goals promise WorkResults, not void

Change-Id: Idd218ec1572eda84dc47accc0dcd8a954d36f098
This commit is contained in:
eldritch horrors 2024-10-05 00:38:35 +02:00
parent a9f2aab226
commit 7ef4466018
7 changed files with 43 additions and 36 deletions

View file

@ -267,7 +267,7 @@ try {
/* We are first going to try to create the invalid output paths /* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build through substitutes. If that doesn't work, we'll build
them. */ them. */
kj::Vector<std::pair<GoalPtr, kj::Promise<void>>> dependencies; kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
if (settings.useSubstitutes) { if (settings.useSubstitutes) {
if (parsedDrv->substitutesAllowed()) { if (parsedDrv->substitutesAllowed()) {
for (auto & [outputName, status] : initialOutputs) { for (auto & [outputName, status] : initialOutputs) {
@ -376,7 +376,7 @@ try {
produced using a substitute. So we have to build instead. */ produced using a substitute. So we have to build instead. */
kj::Promise<Result<Goal::WorkResult>> DerivationGoal::gaveUpOnSubstitution() noexcept kj::Promise<Result<Goal::WorkResult>> DerivationGoal::gaveUpOnSubstitution() noexcept
try { try {
kj::Vector<std::pair<GoalPtr, kj::Promise<void>>> dependencies; kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
/* At this point we are building all outputs, so if more are wanted there /* At this point we are building all outputs, so if more are wanted there
is no need to restart. */ is no need to restart. */
@ -482,7 +482,7 @@ try {
} }
/* Check each path (slow!). */ /* Check each path (slow!). */
kj::Vector<std::pair<GoalPtr, kj::Promise<void>>> dependencies; kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
for (auto & i : outputClosure) { for (auto & i : outputClosure) {
if (worker.pathContentsGood(i)) continue; if (worker.pathContentsGood(i)) continue;
printError( printError(

View file

@ -103,7 +103,7 @@ try {
co_return co_await tryNext(); co_return co_await tryNext();
} }
kj::Vector<std::pair<GoalPtr, kj::Promise<void>>> dependencies; kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
for (const auto & [depId, depPath] : outputInfo->dependentRealisations) { for (const auto & [depId, depPath] : outputInfo->dependentRealisations) {
if (depId != id) { if (depId != id) {
if (auto localOutputInfo = worker.store.queryRealisation(depId); if (auto localOutputInfo = worker.store.queryRealisation(depId);

View file

@ -29,7 +29,7 @@ try {
exitCode = result.exitCode; exitCode = result.exitCode;
ex = result.ex; ex = result.ex;
notify->fulfill(); notify->fulfill(result);
cleanup(); cleanup();
co_return std::move(result); co_return std::move(result);
@ -38,24 +38,25 @@ try {
} }
kj::Promise<Result<void>> kj::Promise<Result<void>>
Goal::waitForGoals(kj::Array<std::pair<GoalPtr, kj::Promise<void>>> dependencies) noexcept Goal::waitForGoals(kj::Array<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies) noexcept
try { try {
auto left = dependencies.size(); auto left = dependencies.size();
for (auto & [dep, p] : dependencies) { for (auto & [dep, p] : dependencies) {
p = p.then([this, dep, &left] { p = p.then([this, dep, &left](auto _result) {
left--; left--;
trace(fmt("waitee '%s' done; %d left", dep->name, left)); trace(fmt("waitee '%s' done; %d left", dep->name, left));
if (dep->exitCode != Goal::ecSuccess) ++nrFailed; if (dep->exitCode != Goal::ecSuccess) ++nrFailed;
if (dep->exitCode == Goal::ecNoSubstituters) ++nrNoSubstituters; if (dep->exitCode == Goal::ecNoSubstituters) ++nrNoSubstituters;
if (dep->exitCode == Goal::ecIncompleteClosure) ++nrIncompleteClosure; if (dep->exitCode == Goal::ecIncompleteClosure) ++nrIncompleteClosure;
return _result;
}).eagerlyEvaluate(nullptr); }).eagerlyEvaluate(nullptr);
} }
auto collectDeps = asyncCollect(std::move(dependencies)); auto collectDeps = asyncCollect(std::move(dependencies));
while (auto item = co_await collectDeps.next()) { while (auto item = co_await collectDeps.next()) {
auto & dep = *item; auto & [dep, _result] = *item;
waiteeDone(dep); waiteeDone(dep);

View file

@ -92,8 +92,10 @@ struct Goal
*/ */
BuildResult buildResult; BuildResult buildResult;
struct WorkResult;
// for use by Worker and Goal only. will go away once work() is a promise. // for use by Worker and Goal only. will go away once work() is a promise.
kj::Own<kj::PromiseFulfiller<void>> notify; kj::Own<kj::PromiseFulfiller<Result<WorkResult>>> notify;
protected: protected:
AsyncSemaphore::Token slotToken; AsyncSemaphore::Token slotToken;
@ -112,13 +114,15 @@ public:
protected: protected:
kj::Promise<void> waitForAWhile(); kj::Promise<void> waitForAWhile();
kj::Promise<Result<void>> kj::Promise<Result<void>>
waitForGoals(kj::Array<std::pair<GoalPtr, kj::Promise<void>>> dependencies) noexcept; waitForGoals(kj::Array<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies) noexcept;
template<std::derived_from<Goal>... G> template<std::derived_from<Goal>... G>
kj::Promise<Result<void>> kj::Promise<Result<void>>
waitForGoals(std::pair<std::shared_ptr<G>, kj::Promise<void>>... goals) noexcept waitForGoals(std::pair<std::shared_ptr<G>, kj::Promise<Result<WorkResult>>>... goals) noexcept
{ {
return waitForGoals(kj::arrOf<std::pair<GoalPtr, kj::Promise<void>>>(std::move(goals)...)); return waitForGoals(
kj::arrOf<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>>(std::move(goals)...)
);
} }
virtual kj::Promise<Result<WorkResult>> workImpl() noexcept = 0; virtual kj::Promise<Result<WorkResult>> workImpl() noexcept = 0;

View file

@ -157,7 +157,7 @@ try {
/* To maintain the closure invariant, we first have to realise the /* To maintain the closure invariant, we first have to realise the
paths referenced by this one. */ paths referenced by this one. */
kj::Vector<std::pair<GoalPtr, kj::Promise<void>>> dependencies; kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
for (auto & i : info->references) for (auto & i : info->references)
if (i != storePath) /* ignore self-references */ if (i != storePath) /* ignore self-references */
dependencies.add(worker.goalFactory().makePathSubstitutionGoal(i)); dependencies.add(worker.goalFactory().makePathSubstitutionGoal(i));

View file

@ -53,7 +53,7 @@ Worker::~Worker()
template<typename ID, std::derived_from<Goal> G> template<typename ID, std::derived_from<Goal> G>
std::pair<std::shared_ptr<G>, kj::Promise<void>> Worker::makeGoalCommon( std::pair<std::shared_ptr<G>, kj::Promise<Result<Goal::WorkResult>>> Worker::makeGoalCommon(
std::map<ID, CachedGoal<G>> & map, std::map<ID, CachedGoal<G>> & map,
const ID & key, const ID & key,
InvocableR<std::unique_ptr<G>> auto create, InvocableR<std::unique_ptr<G>> auto create,
@ -89,7 +89,7 @@ std::pair<std::shared_ptr<G>, kj::Promise<void>> Worker::makeGoalCommon(
} }
std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> Worker::makeDerivationGoal( std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<Result<Goal::WorkResult>>> Worker::makeDerivationGoal(
const StorePath & drvPath, const OutputsSpec & wantedOutputs, BuildMode buildMode const StorePath & drvPath, const OutputsSpec & wantedOutputs, BuildMode buildMode
) )
{ {
@ -110,7 +110,7 @@ std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> Worker::makeDeriva
} }
std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> Worker::makeBasicDerivationGoal( std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<Result<Goal::WorkResult>>> Worker::makeBasicDerivationGoal(
const StorePath & drvPath, const StorePath & drvPath,
const BasicDerivation & drv, const BasicDerivation & drv,
const OutputsSpec & wantedOutputs, const OutputsSpec & wantedOutputs,
@ -134,7 +134,7 @@ std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> Worker::makeBasicD
} }
std::pair<std::shared_ptr<PathSubstitutionGoal>, kj::Promise<void>> std::pair<std::shared_ptr<PathSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
Worker::makePathSubstitutionGoal( Worker::makePathSubstitutionGoal(
const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca const StorePath & path, RepairFlag repair, std::optional<ContentAddress> ca
) )
@ -148,7 +148,7 @@ Worker::makePathSubstitutionGoal(
} }
std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<void>> std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
Worker::makeDrvOutputSubstitutionGoal( Worker::makeDrvOutputSubstitutionGoal(
const DrvOutput & id, RepairFlag repair, std::optional<ContentAddress> ca const DrvOutput & id, RepairFlag repair, std::optional<ContentAddress> ca
) )
@ -162,16 +162,16 @@ Worker::makeDrvOutputSubstitutionGoal(
} }
std::pair<GoalPtr, kj::Promise<void>> Worker::makeGoal(const DerivedPath & req, BuildMode buildMode) std::pair<GoalPtr, kj::Promise<Result<Goal::WorkResult>>> Worker::makeGoal(const DerivedPath & req, BuildMode buildMode)
{ {
return std::visit(overloaded { return std::visit(overloaded {
[&](const DerivedPath::Built & bfd) -> std::pair<GoalPtr, kj::Promise<void>> { [&](const DerivedPath::Built & bfd) -> std::pair<GoalPtr, kj::Promise<Result<Goal::WorkResult>>> {
if (auto bop = std::get_if<DerivedPath::Opaque>(&*bfd.drvPath)) if (auto bop = std::get_if<DerivedPath::Opaque>(&*bfd.drvPath))
return makeDerivationGoal(bop->path, bfd.outputs, buildMode); return makeDerivationGoal(bop->path, bfd.outputs, buildMode);
else else
throw UnimplementedError("Building dynamic derivations in one shot is not yet implemented."); throw UnimplementedError("Building dynamic derivations in one shot is not yet implemented.");
}, },
[&](const DerivedPath::Opaque & bo) -> std::pair<GoalPtr, kj::Promise<void>> { [&](const DerivedPath::Opaque & bo) -> std::pair<GoalPtr, kj::Promise<Result<Goal::WorkResult>>> {
return makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair); return makePathSubstitutionGoal(bo.path, buildMode == bmRepair ? Repair : NoRepair);
}, },
}, req.raw()); }, req.raw());

View file

@ -30,10 +30,12 @@ struct HookInstance;
class GoalFactory class GoalFactory
{ {
public: public:
virtual std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> makeDerivationGoal( virtual std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<Result<Goal::WorkResult>>>
makeDerivationGoal(
const StorePath & drvPath, const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal const StorePath & drvPath, const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal
) = 0; ) = 0;
virtual std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> makeBasicDerivationGoal( virtual std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<Result<Goal::WorkResult>>>
makeBasicDerivationGoal(
const StorePath & drvPath, const StorePath & drvPath,
const BasicDerivation & drv, const BasicDerivation & drv,
const OutputsSpec & wantedOutputs, const OutputsSpec & wantedOutputs,
@ -43,13 +45,13 @@ public:
/** /**
* @ref SubstitutionGoal "substitution goal" * @ref SubstitutionGoal "substitution goal"
*/ */
virtual std::pair<std::shared_ptr<PathSubstitutionGoal>, kj::Promise<void>> virtual std::pair<std::shared_ptr<PathSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
makePathSubstitutionGoal( makePathSubstitutionGoal(
const StorePath & storePath, const StorePath & storePath,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair,
std::optional<ContentAddress> ca = std::nullopt std::optional<ContentAddress> ca = std::nullopt
) = 0; ) = 0;
virtual std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<void>> virtual std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
makeDrvOutputSubstitutionGoal( makeDrvOutputSubstitutionGoal(
const DrvOutput & id, const DrvOutput & id,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair,
@ -62,7 +64,7 @@ public:
* It will be a `DerivationGoal` for a `DerivedPath::Built` or * It will be a `DerivationGoal` for a `DerivedPath::Built` or
* a `SubstitutionGoal` for a `DerivedPath::Opaque`. * a `SubstitutionGoal` for a `DerivedPath::Opaque`.
*/ */
virtual std::pair<GoalPtr, kj::Promise<void>> virtual std::pair<GoalPtr, kj::Promise<Result<Goal::WorkResult>>>
makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal) = 0; makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal) = 0;
}; };
@ -95,12 +97,12 @@ private:
struct CachedGoal struct CachedGoal
{ {
std::weak_ptr<G> goal; std::weak_ptr<G> goal;
kj::Own<kj::ForkedPromise<void>> promise; kj::Own<kj::ForkedPromise<Result<Goal::WorkResult>>> promise;
kj::Own<kj::PromiseFulfiller<void>> fulfiller; kj::Own<kj::PromiseFulfiller<Result<Goal::WorkResult>>> fulfiller;
CachedGoal() CachedGoal()
{ {
auto pf = kj::newPromiseAndFulfiller<void>(); auto pf = kj::newPromiseAndFulfiller<Result<Goal::WorkResult>>();
promise = kj::heap(pf.promise.fork()); promise = kj::heap(pf.promise.fork());
fulfiller = std::move(pf.fulfiller); fulfiller = std::move(pf.fulfiller);
} }
@ -236,29 +238,29 @@ public:
*/ */
private: private:
template<typename ID, std::derived_from<Goal> G> template<typename ID, std::derived_from<Goal> G>
std::pair<std::shared_ptr<G>, kj::Promise<void>> makeGoalCommon( std::pair<std::shared_ptr<G>, kj::Promise<Result<Goal::WorkResult>>> makeGoalCommon(
std::map<ID, CachedGoal<G>> & map, std::map<ID, CachedGoal<G>> & map,
const ID & key, const ID & key,
InvocableR<std::unique_ptr<G>> auto create, InvocableR<std::unique_ptr<G>> auto create,
InvocableR<bool, G &> auto modify InvocableR<bool, G &> auto modify
); );
std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> makeDerivationGoal( std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<Result<Goal::WorkResult>>> makeDerivationGoal(
const StorePath & drvPath, const StorePath & drvPath,
const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal) override; const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal) override;
std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<void>> makeBasicDerivationGoal( std::pair<std::shared_ptr<DerivationGoal>, kj::Promise<Result<Goal::WorkResult>>> makeBasicDerivationGoal(
const StorePath & drvPath, const BasicDerivation & drv, const StorePath & drvPath, const BasicDerivation & drv,
const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal) override; const OutputsSpec & wantedOutputs, BuildMode buildMode = bmNormal) override;
/** /**
* @ref SubstitutionGoal "substitution goal" * @ref SubstitutionGoal "substitution goal"
*/ */
std::pair<std::shared_ptr<PathSubstitutionGoal>, kj::Promise<void>> std::pair<std::shared_ptr<PathSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
makePathSubstitutionGoal( makePathSubstitutionGoal(
const StorePath & storePath, const StorePath & storePath,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair,
std::optional<ContentAddress> ca = std::nullopt std::optional<ContentAddress> ca = std::nullopt
) override; ) override;
std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<void>> std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
makeDrvOutputSubstitutionGoal( makeDrvOutputSubstitutionGoal(
const DrvOutput & id, const DrvOutput & id,
RepairFlag repair = NoRepair, RepairFlag repair = NoRepair,
@ -271,11 +273,11 @@ private:
* It will be a `DerivationGoal` for a `DerivedPath::Built` or * It will be a `DerivationGoal` for a `DerivedPath::Built` or
* a `SubstitutionGoal` for a `DerivedPath::Opaque`. * a `SubstitutionGoal` for a `DerivedPath::Opaque`.
*/ */
std::pair<GoalPtr, kj::Promise<void>> std::pair<GoalPtr, kj::Promise<Result<Goal::WorkResult>>>
makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal) override; makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal) override;
public: public:
using Targets = std::map<GoalPtr, kj::Promise<void>>; using Targets = std::map<GoalPtr, kj::Promise<Result<Goal::WorkResult>>>;
/** /**
* Loop until the specified top-level goals have finished. * Loop until the specified top-level goals have finished.