libstore: remove DrvOutputSubstitutionGoal
this goal is only involved for output paths that aren't known at initial build time, which in turn can only happen if they are ca paths. since we can no longer create ca derivations during eval *or* read them from disk we can now assume that we will never run this goal. there are still some vestiges like output known-ness we can't remove yet, so those must stay. Change-Id: I989e5ad4600c628bcbe8e17e1b082ce8d73a3bd9
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
#include "lix/libstore/common-protocol-impl.hh" // IWYU pragma: keep
|
||||
#include "lix/libstore/local-store.hh" // TODO remove, along with remaining downcasts
|
||||
#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"
|
||||
|
||||
@@ -253,14 +252,13 @@ try {
|
||||
if (parsedDrv->substitutesAllowed()) {
|
||||
for (auto & [outputName, status] : initialOutputs) {
|
||||
if (!status.wanted) continue;
|
||||
if (!status.known)
|
||||
dependencies.add(
|
||||
worker.goalFactory().makeDrvOutputSubstitutionGoal(
|
||||
DrvOutput{status.outputHash, outputName},
|
||||
buildMode == bmRepair ? Repair : NoRepair
|
||||
)
|
||||
if (!status.known) {
|
||||
// TODO remove somehow
|
||||
throw Error(
|
||||
"congrats, you hit vestigial CA code. sigh.\n"
|
||||
"please report a bug at https://git.lix.systems/lix-project/lix/issues"
|
||||
);
|
||||
else {
|
||||
} else {
|
||||
auto * cap = getDerivationCA(*drv);
|
||||
dependencies.add(worker.goalFactory().makePathSubstitutionGoal(
|
||||
status.known->path,
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
#include "lix/libstore/build/drv-output-substitution-goal.hh"
|
||||
#include "lix/libstore/build-result.hh"
|
||||
#include "lix/libutil/async.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libstore/build/worker.hh"
|
||||
#include "lix/libstore/build/substitution-goal.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include <kj/array.h>
|
||||
#include <kj/async.h>
|
||||
#include <kj/vector.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(
|
||||
const DrvOutput & id,
|
||||
Worker & worker,
|
||||
bool isDependency,
|
||||
RepairFlag repair,
|
||||
std::optional<ContentAddress> ca)
|
||||
: Goal(worker, isDependency)
|
||||
, id(id)
|
||||
{
|
||||
name = fmt("substitution of '%s'", id.to_string());
|
||||
trace("created");
|
||||
}
|
||||
|
||||
|
||||
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::workImpl() noexcept
|
||||
try {
|
||||
trace("init");
|
||||
|
||||
/* If the derivation already exists, we’re done */
|
||||
if (TRY_AWAIT(worker.store.queryRealisation(id))) {
|
||||
co_return WorkResult{ecSuccess};
|
||||
}
|
||||
|
||||
subs = settings.useSubstitutes ? TRY_AWAIT(getDefaultSubstituters()) : std::list<ref<Store>>();
|
||||
co_return co_await tryNext();
|
||||
} catch (...) {
|
||||
co_return result::current_exception();
|
||||
}
|
||||
|
||||
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::tryNext() noexcept
|
||||
try {
|
||||
trace("trying next substituter");
|
||||
|
||||
if (!slotToken.valid()) {
|
||||
slotToken = co_await worker.substitutions.acquire();
|
||||
}
|
||||
|
||||
maintainRunningSubstitutions = worker.runningSubstitutions.addTemporarily(1);
|
||||
|
||||
if (subs.size() == 0) {
|
||||
/* None left. Terminate this goal and let someone else deal
|
||||
with it. */
|
||||
debug("derivation output '%s' is required, but there is no substituter that can provide it", id.to_string());
|
||||
|
||||
if (substituterFailed) {
|
||||
worker.failedSubstitutions++;
|
||||
}
|
||||
|
||||
/* Hack: don't indicate failure if there were no substituters.
|
||||
In that case the calling derivation should just do a
|
||||
build. */
|
||||
co_return WorkResult{substituterFailed ? ecFailed : ecNoSubstituters};
|
||||
}
|
||||
|
||||
sub = subs.front();
|
||||
subs.pop_front();
|
||||
|
||||
/* The async call to a curl download below can outlive `this` (if
|
||||
some other error occurs), so it must not touch `this`. So put
|
||||
the shared state in a separate refcounted object. */
|
||||
downloadState = std::make_shared<DownloadState>();
|
||||
auto pipe = kj::newPromiseAndCrossThreadFulfiller<void>();
|
||||
downloadState->outPipe = kj::mv(pipe.fulfiller);
|
||||
|
||||
downloadState->result =
|
||||
std::async(std::launch::async, [downloadState{downloadState}, id{id}, sub{sub}] {
|
||||
Finally updateStats([&]() { downloadState->outPipe->fulfill(); });
|
||||
ReceiveInterrupts receiveInterrupts;
|
||||
AsyncIoRoot aio;
|
||||
return aio.blockOn(sub->queryRealisation(id));
|
||||
});
|
||||
|
||||
co_await pipe.promise;
|
||||
co_return co_await realisationFetched();
|
||||
} catch (...) {
|
||||
co_return result::current_exception();
|
||||
}
|
||||
|
||||
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::realisationFetched() noexcept
|
||||
try {
|
||||
maintainRunningSubstitutions.reset();
|
||||
slotToken = {};
|
||||
|
||||
try {
|
||||
outputInfo = downloadState->result.get();
|
||||
} catch (std::exception & e) { // NOLINT(lix-foreign-exceptions)
|
||||
printError(e.what());
|
||||
substituterFailed = true;
|
||||
}
|
||||
|
||||
if (!outputInfo) {
|
||||
co_return co_await tryNext();
|
||||
}
|
||||
|
||||
kj::Vector<std::pair<GoalPtr, kj::Promise<Result<WorkResult>>>> dependencies;
|
||||
for (const auto & [depId, depPath] : outputInfo->dependentRealisations) {
|
||||
if (depId != id) {
|
||||
if (auto localOutputInfo = TRY_AWAIT(worker.store.queryRealisation(depId));
|
||||
localOutputInfo && localOutputInfo->outPath != depPath) {
|
||||
warn(
|
||||
"substituter '%s' has an incompatible realisation for '%s', ignoring.\n"
|
||||
"Local: %s\n"
|
||||
"Remote: %s",
|
||||
sub->getUri(),
|
||||
depId.to_string(),
|
||||
worker.store.printStorePath(localOutputInfo->outPath),
|
||||
worker.store.printStorePath(depPath)
|
||||
);
|
||||
co_return co_await tryNext();
|
||||
}
|
||||
dependencies.add(worker.goalFactory().makeDrvOutputSubstitutionGoal(depId));
|
||||
}
|
||||
}
|
||||
|
||||
dependencies.add(worker.goalFactory().makePathSubstitutionGoal(outputInfo->outPath));
|
||||
|
||||
if (!dependencies.empty()) {
|
||||
TRY_AWAIT(waitForGoals(dependencies.releaseAsArray()));
|
||||
}
|
||||
co_return co_await outPathValid();
|
||||
} catch (...) {
|
||||
co_return result::current_exception();
|
||||
}
|
||||
|
||||
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::outPathValid() noexcept
|
||||
try {
|
||||
assert(outputInfo);
|
||||
trace("output path substituted");
|
||||
|
||||
if (nrFailed > 0) {
|
||||
debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
|
||||
co_return WorkResult{
|
||||
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
|
||||
};
|
||||
}
|
||||
|
||||
TRY_AWAIT(worker.store.registerDrvOutput(*outputInfo));
|
||||
co_return TRY_AWAIT(finished());
|
||||
} catch (...) {
|
||||
co_return result::current_exception();
|
||||
}
|
||||
|
||||
kj::Promise<Result<Goal::WorkResult>> DrvOutputSubstitutionGoal::finished() noexcept
|
||||
try {
|
||||
trace("finished");
|
||||
return {WorkResult{ecSuccess}};
|
||||
} catch (...) {
|
||||
return {result::current_exception()};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
///@file
|
||||
|
||||
#include "lix/libutil/notifying-counter.hh"
|
||||
#include "lix/libstore/store-api.hh"
|
||||
#include "lix/libstore/build/goal.hh"
|
||||
#include "lix/libstore/realisation.hh"
|
||||
#include <future>
|
||||
|
||||
namespace nix {
|
||||
|
||||
class Worker;
|
||||
|
||||
/**
|
||||
* Substitution of a derivation output.
|
||||
* This is done in three steps:
|
||||
* 1. Fetch the output info from a substituter
|
||||
* 2. Substitute the corresponding output path
|
||||
* 3. Register the output info
|
||||
*/
|
||||
class DrvOutputSubstitutionGoal : public Goal {
|
||||
|
||||
/**
|
||||
* The drv output we're trying to substitute
|
||||
*/
|
||||
DrvOutput id;
|
||||
|
||||
/**
|
||||
* The realisation corresponding to the given output id.
|
||||
* Will be filled once we can get it.
|
||||
*/
|
||||
std::shared_ptr<const Realisation> outputInfo;
|
||||
|
||||
/**
|
||||
* The remaining substituters.
|
||||
*/
|
||||
std::list<ref<Store>> subs;
|
||||
|
||||
/**
|
||||
* The current substituter.
|
||||
*/
|
||||
std::shared_ptr<Store> sub;
|
||||
|
||||
NotifyingCounter<uint64_t>::Bump maintainRunningSubstitutions;
|
||||
|
||||
struct DownloadState
|
||||
{
|
||||
kj::Own<kj::CrossThreadPromiseFulfiller<void>> outPipe;
|
||||
std::future<std::shared_ptr<const Realisation>> result;
|
||||
};
|
||||
|
||||
std::shared_ptr<DownloadState> downloadState;
|
||||
|
||||
/**
|
||||
* Whether a substituter failed.
|
||||
*/
|
||||
bool substituterFailed = false;
|
||||
|
||||
public:
|
||||
DrvOutputSubstitutionGoal(
|
||||
const DrvOutput & id,
|
||||
Worker & worker,
|
||||
bool isDependency,
|
||||
RepairFlag repair = NoRepair,
|
||||
std::optional<ContentAddress> ca = std::nullopt
|
||||
);
|
||||
|
||||
kj::Promise<Result<WorkResult>> tryNext() noexcept;
|
||||
kj::Promise<Result<WorkResult>> realisationFetched() noexcept;
|
||||
kj::Promise<Result<WorkResult>> outPathValid() noexcept;
|
||||
kj::Promise<Result<WorkResult>> finished() noexcept;
|
||||
|
||||
kj::Promise<Result<WorkResult>> workImpl() noexcept override;
|
||||
|
||||
JobCategory jobCategory() const override {
|
||||
return JobCategory::Substitution;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "lix/libstore/build/worker.hh"
|
||||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libstore/build/substitution-goal.hh"
|
||||
#include "lix/libstore/build/drv-output-substitution-goal.hh"
|
||||
#include "lix/libstore/build/local-derivation-goal.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libstore/build/hook-instance.hh" // IWYU pragma: keep
|
||||
@@ -50,7 +49,6 @@ Worker::~Worker()
|
||||
children.clear();
|
||||
|
||||
derivationGoals.clear();
|
||||
drvOutputSubstitutionGoals.clear();
|
||||
substitutionGoals.clear();
|
||||
|
||||
assert(expectedSubstitutions == 0);
|
||||
@@ -183,20 +181,6 @@ Worker::makePathSubstitutionGoal(
|
||||
}
|
||||
|
||||
|
||||
std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
|
||||
Worker::makeDrvOutputSubstitutionGoal(
|
||||
const DrvOutput & id, RepairFlag repair, std::optional<ContentAddress> ca
|
||||
)
|
||||
{
|
||||
return makeGoalCommon(
|
||||
drvOutputSubstitutionGoals,
|
||||
id,
|
||||
[&] { return std::make_unique<DrvOutputSubstitutionGoal>(id, *this, running, repair, ca); },
|
||||
[&](auto &) { return true; }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
std::pair<GoalPtr, kj::Promise<Result<Goal::WorkResult>>> Worker::makeGoal(const DerivedPath & req, BuildMode buildMode)
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
|
||||
@@ -21,7 +21,6 @@ namespace nix {
|
||||
/* Forward definition. */
|
||||
struct DerivationGoal;
|
||||
struct PathSubstitutionGoal;
|
||||
class DrvOutputSubstitutionGoal;
|
||||
class LocalStore;
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point;
|
||||
@@ -54,12 +53,6 @@ public:
|
||||
RepairFlag repair = NoRepair,
|
||||
std::optional<ContentAddress> ca = std::nullopt
|
||||
) = 0;
|
||||
virtual std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
|
||||
makeDrvOutputSubstitutionGoal(
|
||||
const DrvOutput & id,
|
||||
RepairFlag repair = NoRepair,
|
||||
std::optional<ContentAddress> ca = std::nullopt
|
||||
) = 0;
|
||||
|
||||
/**
|
||||
* Make a goal corresponding to the `DerivedPath`.
|
||||
@@ -76,7 +69,6 @@ class WorkerBase : protected GoalFactory
|
||||
{
|
||||
friend struct DerivationGoal;
|
||||
friend struct PathSubstitutionGoal;
|
||||
friend class DrvOutputSubstitutionGoal;
|
||||
|
||||
protected:
|
||||
GoalFactory & goalFactory() { return *this; }
|
||||
@@ -139,7 +131,6 @@ private:
|
||||
*/
|
||||
std::map<StorePath, CachedGoal<DerivationGoal>> derivationGoals;
|
||||
std::map<StorePath, CachedGoal<PathSubstitutionGoal>> substitutionGoals;
|
||||
std::map<DrvOutput, CachedGoal<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
|
||||
|
||||
/**
|
||||
* Cache for pathContentsGood().
|
||||
@@ -265,12 +256,6 @@ private:
|
||||
RepairFlag repair = NoRepair,
|
||||
std::optional<ContentAddress> ca = std::nullopt
|
||||
) override;
|
||||
std::pair<std::shared_ptr<DrvOutputSubstitutionGoal>, kj::Promise<Result<Goal::WorkResult>>>
|
||||
makeDrvOutputSubstitutionGoal(
|
||||
const DrvOutput & id,
|
||||
RepairFlag repair = NoRepair,
|
||||
std::optional<ContentAddress> ca = std::nullopt
|
||||
) override;
|
||||
|
||||
/**
|
||||
* Make a goal corresponding to the `DerivedPath`.
|
||||
|
||||
@@ -140,7 +140,6 @@ libstore_sources = files(
|
||||
'build-result.cc',
|
||||
'build/child.cc',
|
||||
'build/derivation-goal.cc',
|
||||
'build/drv-output-substitution-goal.cc',
|
||||
'build/entry-points.cc',
|
||||
'build/goal.cc',
|
||||
'build/hook-instance.cc',
|
||||
@@ -209,7 +208,6 @@ libstore_headers = files(
|
||||
'build-result.hh',
|
||||
'build/child.hh',
|
||||
'build/derivation-goal.hh',
|
||||
'build/drv-output-substitution-goal.hh',
|
||||
'build/goal.hh',
|
||||
'build/hook-instance.hh',
|
||||
'build/local-derivation-goal.hh',
|
||||
|
||||
Reference in New Issue
Block a user