libstore: add explicit in-build-slot-ness to goals

we don't need to expose information about how busy a Worker is if the
worker can instead tell its work items whether they are in a slot. in
the future we might use this to not start items waiting for a slot if
no slots are currently available, but that requires more preparation.

Change-Id: Ibe01ac536da7e6d6f80520164117c43e772f9bd9
This commit is contained in:
eldritch horrors 2024-08-11 01:37:40 +02:00
parent 176e1058f1
commit 38f550708d
11 changed files with 90 additions and 115 deletions

View file

@ -129,9 +129,9 @@ Goal::Finished DerivationGoal::timedOut(Error && ex)
} }
Goal::WorkResult DerivationGoal::work() Goal::WorkResult DerivationGoal::work(bool inBuildSlot)
{ {
return (this->*state)(); return (this->*state)(inBuildSlot);
} }
void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs) void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
@ -155,7 +155,7 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
} }
Goal::WorkResult DerivationGoal::getDerivation() Goal::WorkResult DerivationGoal::getDerivation(bool inBuildSlot)
{ {
trace("init"); trace("init");
@ -163,7 +163,7 @@ Goal::WorkResult DerivationGoal::getDerivation()
exists. If it doesn't, it may be created through a exists. If it doesn't, it may be created through a
substitute. */ substitute. */
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) { if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
return loadDerivation(); return loadDerivation(inBuildSlot);
} }
@ -172,7 +172,7 @@ Goal::WorkResult DerivationGoal::getDerivation()
} }
Goal::WorkResult DerivationGoal::loadDerivation() Goal::WorkResult DerivationGoal::loadDerivation(bool inBuildSlot)
{ {
trace("loading derivation"); trace("loading derivation");
@ -199,11 +199,11 @@ Goal::WorkResult DerivationGoal::loadDerivation()
} }
assert(drv); assert(drv);
return haveDerivation(); return haveDerivation(inBuildSlot);
} }
Goal::WorkResult DerivationGoal::haveDerivation() Goal::WorkResult DerivationGoal::haveDerivation(bool inBuildSlot)
{ {
trace("have derivation"); trace("have derivation");
@ -231,7 +231,7 @@ Goal::WorkResult DerivationGoal::haveDerivation()
}); });
} }
return gaveUpOnSubstitution(); return gaveUpOnSubstitution(inBuildSlot);
} }
for (auto & i : drv->outputsAndOptPaths(worker.store)) for (auto & i : drv->outputsAndOptPaths(worker.store))
@ -280,14 +280,14 @@ Goal::WorkResult DerivationGoal::haveDerivation()
} }
if (result.goals.empty()) { /* to prevent hang (no wake-up event) */ if (result.goals.empty()) { /* to prevent hang (no wake-up event) */
return outputsSubstitutionTried(); return outputsSubstitutionTried(inBuildSlot);
} else { } else {
state = &DerivationGoal::outputsSubstitutionTried; state = &DerivationGoal::outputsSubstitutionTried;
return result; return result;
} }
} }
Goal::WorkResult DerivationGoal::outputsSubstitutionTried() Goal::WorkResult DerivationGoal::outputsSubstitutionTried(bool inBuildSlot)
{ {
trace("all outputs substituted (maybe)"); trace("all outputs substituted (maybe)");
@ -330,7 +330,7 @@ Goal::WorkResult DerivationGoal::outputsSubstitutionTried()
if (needRestart == NeedRestartForMoreOutputs::OutputsAddedDoNeed) { if (needRestart == NeedRestartForMoreOutputs::OutputsAddedDoNeed) {
needRestart = NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed; needRestart = NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed;
return haveDerivation(); return haveDerivation(inBuildSlot);
} }
auto [allValid, validOutputs] = checkPathValidity(); auto [allValid, validOutputs] = checkPathValidity();
@ -346,13 +346,13 @@ Goal::WorkResult DerivationGoal::outputsSubstitutionTried()
worker.store.printStorePath(drvPath)); worker.store.printStorePath(drvPath));
/* Nothing to wait for; tail call */ /* Nothing to wait for; tail call */
return gaveUpOnSubstitution(); return gaveUpOnSubstitution(inBuildSlot);
} }
/* At least one of the output paths could not be /* At least one of the output paths could not be
produced using a substitute. So we have to build instead. */ produced using a substitute. So we have to build instead. */
Goal::WorkResult DerivationGoal::gaveUpOnSubstitution() Goal::WorkResult DerivationGoal::gaveUpOnSubstitution(bool inBuildSlot)
{ {
WaitForGoals result; WaitForGoals result;
@ -416,7 +416,7 @@ Goal::WorkResult DerivationGoal::gaveUpOnSubstitution()
} }
if (result.goals.empty()) {/* to prevent hang (no wake-up event) */ if (result.goals.empty()) {/* to prevent hang (no wake-up event) */
return inputsRealised(); return inputsRealised(inBuildSlot);
} else { } else {
state = &DerivationGoal::inputsRealised; state = &DerivationGoal::inputsRealised;
return result; return result;
@ -487,7 +487,7 @@ Goal::WorkResult DerivationGoal::repairClosure()
} }
Goal::WorkResult DerivationGoal::closureRepaired() Goal::WorkResult DerivationGoal::closureRepaired(bool inBuildSlot)
{ {
trace("closure repaired"); trace("closure repaired");
if (nrFailed > 0) if (nrFailed > 0)
@ -497,7 +497,7 @@ Goal::WorkResult DerivationGoal::closureRepaired()
} }
Goal::WorkResult DerivationGoal::inputsRealised() Goal::WorkResult DerivationGoal::inputsRealised(bool inBuildSlot)
{ {
trace("all inputs realised"); trace("all inputs realised");
@ -511,7 +511,7 @@ Goal::WorkResult DerivationGoal::inputsRealised()
if (retrySubstitution == RetrySubstitution::YesNeed) { if (retrySubstitution == RetrySubstitution::YesNeed) {
retrySubstitution = RetrySubstitution::AlreadyRetried; retrySubstitution = RetrySubstitution::AlreadyRetried;
return haveDerivation(); return haveDerivation(inBuildSlot);
} }
/* Gather information necessary for computing the closure and/or /* Gather information necessary for computing the closure and/or
@ -659,7 +659,7 @@ Goal::WorkResult DerivationGoal::started()
return StillAlive{}; return StillAlive{};
} }
Goal::WorkResult DerivationGoal::tryToBuild() Goal::WorkResult DerivationGoal::tryToBuild(bool inBuildSlot)
{ {
trace("trying to build"); trace("trying to build");
@ -731,7 +731,7 @@ Goal::WorkResult DerivationGoal::tryToBuild()
&& settings.maxBuildJobs.get() != 0; && settings.maxBuildJobs.get() != 0;
if (!buildLocally) { if (!buildLocally) {
switch (tryBuildHook()) { switch (tryBuildHook(inBuildSlot)) {
case rpAccept: case rpAccept:
/* Yes, it has started doing so. Wait until we get /* Yes, it has started doing so. Wait until we get
EOF from the hook. */ EOF from the hook. */
@ -759,7 +759,7 @@ Goal::WorkResult DerivationGoal::tryToBuild()
return ContinueImmediately{}; return ContinueImmediately{};
} }
Goal::WorkResult DerivationGoal::tryLocalBuild() { Goal::WorkResult DerivationGoal::tryLocalBuild(bool inBuildSlot) {
throw Error( throw Error(
"unable to build with a primary store that isn't a local store; " "unable to build with a primary store that isn't a local store; "
"either pass a different '--store' or enable remote builds." "either pass a different '--store' or enable remote builds."
@ -917,7 +917,7 @@ void runPostBuildHook(
proc.getStdout()->drainInto(sink); proc.getStdout()->drainInto(sink);
} }
Goal::WorkResult DerivationGoal::buildDone() Goal::WorkResult DerivationGoal::buildDone(bool inBuildSlot)
{ {
trace("build done"); trace("build done");
@ -1037,7 +1037,7 @@ Goal::WorkResult DerivationGoal::buildDone()
} }
} }
Goal::WorkResult DerivationGoal::resolvedFinished() Goal::WorkResult DerivationGoal::resolvedFinished(bool inBuildSlot)
{ {
trace("resolved derivation finished"); trace("resolved derivation finished");
@ -1108,7 +1108,7 @@ Goal::WorkResult DerivationGoal::resolvedFinished()
return done(status, std::move(builtOutputs)); return done(status, std::move(builtOutputs));
} }
HookReply DerivationGoal::tryBuildHook() HookReply DerivationGoal::tryBuildHook(bool inBuildSlot)
{ {
if (!worker.hook.available || !useDerivation) return rpDecline; if (!worker.hook.available || !useDerivation) return rpDecline;
@ -1120,7 +1120,7 @@ HookReply DerivationGoal::tryBuildHook()
/* Send the request to the hook. */ /* Send the request to the hook. */
worker.hook.instance->sink worker.hook.instance->sink
<< "try" << "try"
<< (worker.getNrLocalBuilds() < settings.maxBuildJobs ? 1 : 0) << (inBuildSlot ? 1 : 0)
<< drv->platform << drv->platform
<< worker.store.printStorePath(drvPath) << worker.store.printStorePath(drvPath)
<< parsedDrv->getRequiredSystemFeatures(); << parsedDrv->getRequiredSystemFeatures();

View file

@ -191,7 +191,7 @@ struct DerivationGoal : public Goal
*/ */
std::optional<DerivationType> derivationType; std::optional<DerivationType> derivationType;
typedef WorkResult (DerivationGoal::*GoalState)(); typedef WorkResult (DerivationGoal::*GoalState)(bool inBuildSlot);
GoalState state; GoalState state;
BuildMode buildMode; BuildMode buildMode;
@ -224,7 +224,7 @@ struct DerivationGoal : public Goal
std::string key() override; std::string key() override;
WorkResult work() override; WorkResult work(bool inBuildSlot) override;
/** /**
* Add wanted outputs to an already existing derivation goal. * Add wanted outputs to an already existing derivation goal.
@ -234,23 +234,23 @@ struct DerivationGoal : public Goal
/** /**
* The states. * The states.
*/ */
WorkResult getDerivation(); WorkResult getDerivation(bool inBuildSlot);
WorkResult loadDerivation(); WorkResult loadDerivation(bool inBuildSlot);
WorkResult haveDerivation(); WorkResult haveDerivation(bool inBuildSlot);
WorkResult outputsSubstitutionTried(); WorkResult outputsSubstitutionTried(bool inBuildSlot);
WorkResult gaveUpOnSubstitution(); WorkResult gaveUpOnSubstitution(bool inBuildSlot);
WorkResult closureRepaired(); WorkResult closureRepaired(bool inBuildSlot);
WorkResult inputsRealised(); WorkResult inputsRealised(bool inBuildSlot);
WorkResult tryToBuild(); WorkResult tryToBuild(bool inBuildSlot);
virtual WorkResult tryLocalBuild(); virtual WorkResult tryLocalBuild(bool inBuildSlot);
WorkResult buildDone(); WorkResult buildDone(bool inBuildSlot);
WorkResult resolvedFinished(); WorkResult resolvedFinished(bool inBuildSlot);
/** /**
* Is the build hook willing to perform the build? * Is the build hook willing to perform the build?
*/ */
HookReply tryBuildHook(); HookReply tryBuildHook(bool inBuildSlot);
virtual int getChildStatus(); virtual int getChildStatus();

View file

@ -20,7 +20,7 @@ DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(
} }
Goal::WorkResult DrvOutputSubstitutionGoal::init() Goal::WorkResult DrvOutputSubstitutionGoal::init(bool inBuildSlot)
{ {
trace("init"); trace("init");
@ -30,17 +30,14 @@ Goal::WorkResult DrvOutputSubstitutionGoal::init()
} }
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>(); subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
return tryNext(); return tryNext(inBuildSlot);
} }
Goal::WorkResult DrvOutputSubstitutionGoal::tryNext() Goal::WorkResult DrvOutputSubstitutionGoal::tryNext(bool inBuildSlot)
{ {
trace("trying next substituter"); trace("trying next substituter");
/* Make sure that we are allowed to start a substitution. Note that even if (!inBuildSlot) {
if maxSubstitutionJobs == 0, we still allow a substituter to run. This
prevents infinite waiting. */
if (worker.runningSubstitutions >= std::max(1U, settings.maxSubstitutionJobs.get())) {
return WaitForSlot{}; return WaitForSlot{};
} }
@ -84,7 +81,7 @@ Goal::WorkResult DrvOutputSubstitutionGoal::tryNext()
return StillAlive{}; return StillAlive{};
} }
Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched() Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched(bool inBuildSlot)
{ {
worker.childTerminated(this); worker.childTerminated(this);
maintainRunningSubstitutions.reset(); maintainRunningSubstitutions.reset();
@ -97,7 +94,7 @@ Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched()
} }
if (!outputInfo) { if (!outputInfo) {
return tryNext(); return tryNext(inBuildSlot);
} }
WaitForGoals result; WaitForGoals result;
@ -114,7 +111,7 @@ Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched()
worker.store.printStorePath(localOutputInfo->outPath), worker.store.printStorePath(localOutputInfo->outPath),
worker.store.printStorePath(depPath) worker.store.printStorePath(depPath)
); );
return tryNext(); return tryNext(inBuildSlot);
} }
result.goals.insert(worker.makeDrvOutputSubstitutionGoal(depId)); result.goals.insert(worker.makeDrvOutputSubstitutionGoal(depId));
} }
@ -123,14 +120,14 @@ Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched()
result.goals.insert(worker.makePathSubstitutionGoal(outputInfo->outPath)); result.goals.insert(worker.makePathSubstitutionGoal(outputInfo->outPath));
if (result.goals.empty()) { if (result.goals.empty()) {
return outPathValid(); return outPathValid(inBuildSlot);
} else { } else {
state = &DrvOutputSubstitutionGoal::outPathValid; state = &DrvOutputSubstitutionGoal::outPathValid;
return result; return result;
} }
} }
Goal::WorkResult DrvOutputSubstitutionGoal::outPathValid() Goal::WorkResult DrvOutputSubstitutionGoal::outPathValid(bool inBuildSlot)
{ {
assert(outputInfo); assert(outputInfo);
trace("output path substituted"); trace("output path substituted");
@ -159,9 +156,9 @@ std::string DrvOutputSubstitutionGoal::key()
return "a$" + std::string(id.to_string()); return "a$" + std::string(id.to_string());
} }
Goal::WorkResult DrvOutputSubstitutionGoal::work() Goal::WorkResult DrvOutputSubstitutionGoal::work(bool inBuildSlot)
{ {
return (this->*state)(); return (this->*state)(inBuildSlot);
} }

View file

@ -58,20 +58,20 @@ class DrvOutputSubstitutionGoal : public Goal {
public: public:
DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt); DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
typedef WorkResult (DrvOutputSubstitutionGoal::*GoalState)(); typedef WorkResult (DrvOutputSubstitutionGoal::*GoalState)(bool inBuildSlot);
GoalState state; GoalState state;
WorkResult init(); WorkResult init(bool inBuildSlot);
WorkResult tryNext(); WorkResult tryNext(bool inBuildSlot);
WorkResult realisationFetched(); WorkResult realisationFetched(bool inBuildSlot);
WorkResult outPathValid(); WorkResult outPathValid(bool inBuildSlot);
WorkResult finished(); WorkResult finished();
Finished timedOut(Error && ex) override { abort(); }; Finished timedOut(Error && ex) override { abort(); };
std::string key() override; std::string key() override;
WorkResult work() override; WorkResult work(bool inBuildSlot) override;
JobCategory jobCategory() const override { JobCategory jobCategory() const override {
return JobCategory::Substitution; return JobCategory::Substitution;

View file

@ -147,7 +147,7 @@ public:
trace("goal destroyed"); trace("goal destroyed");
} }
virtual WorkResult work() = 0; virtual WorkResult work(bool inBuildSlot) = 0;
virtual void waiteeDone(GoalPtr waitee) { } virtual void waiteeDone(GoalPtr waitee) { }

View file

@ -150,14 +150,13 @@ void LocalDerivationGoal::killSandbox(bool getStats)
} }
Goal::WorkResult LocalDerivationGoal::tryLocalBuild() Goal::WorkResult LocalDerivationGoal::tryLocalBuild(bool inBuildSlot)
{ {
#if __APPLE__ #if __APPLE__
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or(""); additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
#endif #endif
unsigned int curBuilds = worker.getNrLocalBuilds(); if (!inBuildSlot) {
if (curBuilds >= settings.maxBuildJobs) {
state = &DerivationGoal::tryToBuild; state = &DerivationGoal::tryToBuild;
outputLocks.unlock(); outputLocks.unlock();
return WaitForSlot{}; return WaitForSlot{};

View file

@ -211,7 +211,7 @@ struct LocalDerivationGoal : public DerivationGoal
/** /**
* The additional states. * The additional states.
*/ */
WorkResult tryLocalBuild() override; WorkResult tryLocalBuild(bool inBuildSlot) override;
/** /**
* Start building a derivation. * Start building a derivation.

View file

@ -39,13 +39,13 @@ Goal::Finished PathSubstitutionGoal::done(
} }
Goal::WorkResult PathSubstitutionGoal::work() Goal::WorkResult PathSubstitutionGoal::work(bool inBuildSlot)
{ {
return (this->*state)(); return (this->*state)(inBuildSlot);
} }
Goal::WorkResult PathSubstitutionGoal::init() Goal::WorkResult PathSubstitutionGoal::init(bool inBuildSlot)
{ {
trace("init"); trace("init");
@ -61,11 +61,11 @@ Goal::WorkResult PathSubstitutionGoal::init()
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>(); subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
return tryNext(); return tryNext(inBuildSlot);
} }
Goal::WorkResult PathSubstitutionGoal::tryNext() Goal::WorkResult PathSubstitutionGoal::tryNext(bool inBuildSlot)
{ {
trace("trying next substituter"); trace("trying next substituter");
@ -97,23 +97,23 @@ Goal::WorkResult PathSubstitutionGoal::tryNext()
if (sub->storeDir == worker.store.storeDir) if (sub->storeDir == worker.store.storeDir)
assert(subPath == storePath); assert(subPath == storePath);
} else if (sub->storeDir != worker.store.storeDir) { } else if (sub->storeDir != worker.store.storeDir) {
return tryNext(); return tryNext(inBuildSlot);
} }
try { try {
// FIXME: make async // FIXME: make async
info = sub->queryPathInfo(subPath ? *subPath : storePath); info = sub->queryPathInfo(subPath ? *subPath : storePath);
} catch (InvalidPath &) { } catch (InvalidPath &) {
return tryNext(); return tryNext(inBuildSlot);
} catch (SubstituterDisabled &) { } catch (SubstituterDisabled &) {
if (settings.tryFallback) { if (settings.tryFallback) {
return tryNext(); return tryNext(inBuildSlot);
} }
throw; throw;
} catch (Error & e) { } catch (Error & e) {
if (settings.tryFallback) { if (settings.tryFallback) {
logError(e.info()); logError(e.info());
return tryNext(); return tryNext(inBuildSlot);
} }
throw; throw;
} }
@ -126,7 +126,7 @@ Goal::WorkResult PathSubstitutionGoal::tryNext()
} else { } else {
printError("asked '%s' for '%s' but got '%s'", printError("asked '%s' for '%s' but got '%s'",
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path)); sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
return tryNext(); return tryNext(inBuildSlot);
} }
} }
@ -147,7 +147,7 @@ Goal::WorkResult PathSubstitutionGoal::tryNext()
{ {
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'", warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
worker.store.printStorePath(storePath), sub->getUri()); worker.store.printStorePath(storePath), sub->getUri());
return tryNext(); return tryNext(inBuildSlot);
} }
/* To maintain the closure invariant, we first have to realise the /* To maintain the closure invariant, we first have to realise the
@ -158,7 +158,7 @@ Goal::WorkResult PathSubstitutionGoal::tryNext()
result.goals.insert(worker.makePathSubstitutionGoal(i)); result.goals.insert(worker.makePathSubstitutionGoal(i));
if (result.goals.empty()) {/* to prevent hang (no wake-up event) */ if (result.goals.empty()) {/* to prevent hang (no wake-up event) */
return referencesValid(); return referencesValid(inBuildSlot);
} else { } else {
state = &PathSubstitutionGoal::referencesValid; state = &PathSubstitutionGoal::referencesValid;
return result; return result;
@ -166,7 +166,7 @@ Goal::WorkResult PathSubstitutionGoal::tryNext()
} }
Goal::WorkResult PathSubstitutionGoal::referencesValid() Goal::WorkResult PathSubstitutionGoal::referencesValid(bool inBuildSlot)
{ {
trace("all references realised"); trace("all references realised");
@ -186,14 +186,11 @@ Goal::WorkResult PathSubstitutionGoal::referencesValid()
} }
Goal::WorkResult PathSubstitutionGoal::tryToRun() Goal::WorkResult PathSubstitutionGoal::tryToRun(bool inBuildSlot)
{ {
trace("trying to run"); trace("trying to run");
/* Make sure that we are allowed to start a substitution. Note that even if (!inBuildSlot) {
if maxSubstitutionJobs == 0, we still allow a substituter to run. This
prevents infinite waiting. */
if (worker.getNrSubstitutions() >= std::max(1U, (unsigned int) settings.maxSubstitutionJobs)) {
return WaitForSlot{}; return WaitForSlot{};
} }
@ -231,7 +228,7 @@ Goal::WorkResult PathSubstitutionGoal::tryToRun()
} }
Goal::WorkResult PathSubstitutionGoal::finished() Goal::WorkResult PathSubstitutionGoal::finished(bool inBuildSlot)
{ {
trace("substitute finished"); trace("substitute finished");

View file

@ -66,7 +66,7 @@ struct PathSubstitutionGoal : public Goal
std::unique_ptr<MaintainCount<uint64_t>> maintainExpectedSubstitutions, std::unique_ptr<MaintainCount<uint64_t>> maintainExpectedSubstitutions,
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload; maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
typedef WorkResult (PathSubstitutionGoal::*GoalState)(); typedef WorkResult (PathSubstitutionGoal::*GoalState)(bool inBuildSlot);
GoalState state; GoalState state;
/** /**
@ -94,16 +94,16 @@ public:
return "a$" + std::string(storePath.name()) + "$" + worker.store.printStorePath(storePath); return "a$" + std::string(storePath.name()) + "$" + worker.store.printStorePath(storePath);
} }
WorkResult work() override; WorkResult work(bool inBuildSlot) override;
/** /**
* The states. * The states.
*/ */
WorkResult init(); WorkResult init(bool inBuildSlot);
WorkResult tryNext(); WorkResult tryNext(bool inBuildSlot);
WorkResult referencesValid(); WorkResult referencesValid(bool inBuildSlot);
WorkResult tryToRun(); WorkResult tryToRun(bool inBuildSlot);
WorkResult finished(); WorkResult finished(bool inBuildSlot);
/** /**
* Callback used by the worker to write to the log. * Callback used by the worker to write to the log.

View file

@ -232,18 +232,6 @@ void Worker::wakeUp(GoalPtr goal)
} }
unsigned Worker::getNrLocalBuilds()
{
return nrLocalBuilds;
}
unsigned Worker::getNrSubstitutions()
{
return nrSubstitutions;
}
void Worker::childStarted(GoalPtr goal, const std::set<int> & fds, void Worker::childStarted(GoalPtr goal, const std::set<int> & fds,
bool inBuildSlot, bool respectTimeouts) bool inBuildSlot, bool respectTimeouts)
{ {
@ -307,8 +295,8 @@ void Worker::waitForBuildSlot(GoalPtr goal)
{ {
goal->trace("wait for build slot"); goal->trace("wait for build slot");
bool isSubstitutionGoal = goal->jobCategory() == JobCategory::Substitution; bool isSubstitutionGoal = goal->jobCategory() == JobCategory::Substitution;
if ((!isSubstitutionGoal && getNrLocalBuilds() < settings.maxBuildJobs) || if ((!isSubstitutionGoal && nrLocalBuilds < settings.maxBuildJobs) ||
(isSubstitutionGoal && getNrSubstitutions() < settings.maxSubstitutionJobs)) (isSubstitutionGoal && nrSubstitutions < settings.maxSubstitutionJobs))
wakeUp(goal); /* we can do it right away */ wakeUp(goal); /* we can do it right away */
else else
wantingToBuild.insert(goal); wantingToBuild.insert(goal);
@ -364,7 +352,12 @@ void Worker::run(const Goals & _topGoals)
awake.clear(); awake.clear();
for (auto & goal : awake2) { for (auto & goal : awake2) {
checkInterrupt(); checkInterrupt();
handleWorkResult(goal, goal->work()); /* Make sure that we are always allowed to run at least one substitution.
This prevents infinite waiting. */
const bool inSlot = goal->jobCategory() == JobCategory::Substitution
? nrSubstitutions < std::max(1U, (unsigned int) settings.maxSubstitutionJobs)
: nrLocalBuilds < settings.maxBuildJobs;
handleWorkResult(goal, goal->work(inSlot));
actDerivations.progress( actDerivations.progress(
doneBuilds, expectedBuilds + doneBuilds, runningBuilds, failedBuilds doneBuilds, expectedBuilds + doneBuilds, runningBuilds, failedBuilds

View file

@ -229,17 +229,6 @@ public:
*/ */
GoalPtr makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal); GoalPtr makeGoal(const DerivedPath & req, BuildMode buildMode = bmNormal);
/**
* Return the number of local build processes currently running (but not
* remote builds via the build hook).
*/
unsigned int getNrLocalBuilds();
/**
* Return the number of substitution processes currently running.
*/
unsigned int getNrSubstitutions();
/** /**
* Registers a running child process. `inBuildSlot` means that * Registers a running child process. `inBuildSlot` means that
* the process counts towards the jobs limit. * the process counts towards the jobs limit.