Skip to content

Commit 4c44a21

Browse files
committed
Get rid of a tryToBuild tail recursive call with loop
This will make it easier to convert somethings to RAII.
1 parent 95c5779 commit 4c44a21

File tree

1 file changed

+90
-86
lines changed

1 file changed

+90
-86
lines changed

src/libstore/build/derivation-building-goal.cc

Lines changed: 90 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -472,101 +472,105 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
472472
{
473473
bool useHook;
474474

475-
trace("trying to build");
476-
477-
/* Obtain locks on all output paths, if the paths are known a priori.
478-
479-
The locks are automatically released when we exit this function or Nix
480-
crashes. If we can't acquire the lock, then continue; hopefully some
481-
other goal can start a build, and if not, the main loop will sleep a few
482-
seconds and then retry this goal. */
483-
PathSet lockFiles;
484-
/* FIXME: Should lock something like the drv itself so we don't build same
485-
CA drv concurrently */
486-
if (dynamic_cast<LocalStore *>(&worker.store)) {
487-
/* If we aren't a local store, we might need to use the local store as
488-
a build remote, but that would cause a deadlock. */
489-
/* FIXME: Make it so we can use ourselves as a build remote even if we
490-
are the local store (separate locking for building vs scheduling? */
491-
/* FIXME: find some way to lock for scheduling for the other stores so
492-
a forking daemon with --store still won't farm out redundant builds.
493-
*/
494-
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
495-
if (i.second.second)
496-
lockFiles.insert(worker.store.Store::toRealPath(*i.second.second));
497-
else
498-
lockFiles.insert(worker.store.Store::toRealPath(drvPath) + "." + i.first);
475+
while (true) {
476+
trace("trying to build");
477+
478+
/* Obtain locks on all output paths, if the paths are known a priori.
479+
480+
The locks are automatically released when we exit this function or Nix
481+
crashes. If we can't acquire the lock, then continue; hopefully some
482+
other goal can start a build, and if not, the main loop will sleep a few
483+
seconds and then retry this goal. */
484+
PathSet lockFiles;
485+
/* FIXME: Should lock something like the drv itself so we don't build same
486+
CA drv concurrently */
487+
if (dynamic_cast<LocalStore *>(&worker.store)) {
488+
/* If we aren't a local store, we might need to use the local store as
489+
a build remote, but that would cause a deadlock. */
490+
/* FIXME: Make it so we can use ourselves as a build remote even if we
491+
are the local store (separate locking for building vs scheduling? */
492+
/* FIXME: find some way to lock for scheduling for the other stores so
493+
a forking daemon with --store still won't farm out redundant builds.
494+
*/
495+
for (auto & i : drv->outputsAndOptPaths(worker.store)) {
496+
if (i.second.second)
497+
lockFiles.insert(worker.store.Store::toRealPath(*i.second.second));
498+
else
499+
lockFiles.insert(worker.store.Store::toRealPath(drvPath) + "." + i.first);
500+
}
499501
}
500-
}
501502

502-
if (!outputLocks.lockPaths(lockFiles, "", false)) {
503-
Activity act(*logger, lvlWarn, actBuildWaiting, fmt("waiting for lock on %s", Magenta(showPaths(lockFiles))));
503+
if (!outputLocks.lockPaths(lockFiles, "", false)) {
504+
Activity act(
505+
*logger, lvlWarn, actBuildWaiting, fmt("waiting for lock on %s", Magenta(showPaths(lockFiles))));
504506

505-
/* Wait then try locking again, repeat until success (returned
506-
boolean is true). */
507-
do {
508-
co_await waitForAWhile();
509-
} while (!outputLocks.lockPaths(lockFiles, "", false));
510-
}
507+
/* Wait then try locking again, repeat until success (returned
508+
boolean is true). */
509+
do {
510+
co_await waitForAWhile();
511+
} while (!outputLocks.lockPaths(lockFiles, "", false));
512+
}
511513

512-
/* Now check again whether the outputs are valid. This is because
513-
another process may have started building in parallel. After
514-
it has finished and released the locks, we can (and should)
515-
reuse its results. (Strictly speaking the first check can be
516-
omitted, but that would be less efficient.) Note that since we
517-
now hold the locks on the output paths, no other process can
518-
build this derivation, so no further checks are necessary. */
519-
auto [allValid, validOutputs] = checkPathValidity();
514+
/* Now check again whether the outputs are valid. This is because
515+
another process may have started building in parallel. After
516+
it has finished and released the locks, we can (and should)
517+
reuse its results. (Strictly speaking the first check can be
518+
omitted, but that would be less efficient.) Note that since we
519+
now hold the locks on the output paths, no other process can
520+
build this derivation, so no further checks are necessary. */
521+
auto [allValid, validOutputs] = checkPathValidity();
522+
523+
if (buildMode != bmCheck && allValid) {
524+
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
525+
outputLocks.setDeletion(true);
526+
outputLocks.unlock();
527+
co_return doneSuccess(BuildResult::AlreadyValid, std::move(validOutputs));
528+
}
520529

521-
if (buildMode != bmCheck && allValid) {
522-
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
523-
outputLocks.setDeletion(true);
524-
outputLocks.unlock();
525-
co_return doneSuccess(BuildResult::AlreadyValid, std::move(validOutputs));
526-
}
530+
/* If any of the outputs already exist but are not valid, delete
531+
them. */
532+
for (auto & [_, status] : initialOutputs) {
533+
if (!status.known || status.known->isValid())
534+
continue;
535+
auto storePath = status.known->path;
536+
debug("removing invalid path '%s'", worker.store.printStorePath(status.known->path));
537+
deletePath(worker.store.Store::toRealPath(storePath));
538+
}
527539

528-
/* If any of the outputs already exist but are not valid, delete
529-
them. */
530-
for (auto & [_, status] : initialOutputs) {
531-
if (!status.known || status.known->isValid())
532-
continue;
533-
auto storePath = status.known->path;
534-
debug("removing invalid path '%s'", worker.store.printStorePath(status.known->path));
535-
deletePath(worker.store.Store::toRealPath(storePath));
536-
}
540+
/* Don't do a remote build if the derivation has the attribute
541+
`preferLocalBuild' set. Also, check and repair modes are only
542+
supported for local builds. */
543+
bool buildLocally = (buildMode != bmNormal || drvOptions->willBuildLocally(worker.store, *drv))
544+
&& settings.maxBuildJobs.get() != 0;
537545

538-
/* Don't do a remote build if the derivation has the attribute
539-
`preferLocalBuild' set. Also, check and repair modes are only
540-
supported for local builds. */
541-
bool buildLocally =
542-
(buildMode != bmNormal || drvOptions->willBuildLocally(worker.store, *drv)) && settings.maxBuildJobs.get() != 0;
543-
544-
if (buildLocally) {
545-
useHook = false;
546-
} else {
547-
switch (tryBuildHook()) {
548-
case rpAccept:
549-
/* Yes, it has started doing so. Wait until we get
550-
EOF from the hook. */
551-
useHook = true;
552-
break;
553-
case rpPostpone:
554-
/* Not now; wait until at least one child finishes or
555-
the wake-up timeout expires. */
556-
if (!actLock)
557-
actLock = std::make_unique<Activity>(
558-
*logger,
559-
lvlWarn,
560-
actBuildWaiting,
561-
fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath))));
562-
outputLocks.unlock();
563-
co_await waitForAWhile();
564-
co_return tryToBuild();
565-
case rpDecline:
566-
/* We should do it ourselves. */
546+
if (buildLocally) {
567547
useHook = false;
568-
break;
548+
} else {
549+
switch (tryBuildHook()) {
550+
case rpAccept:
551+
/* Yes, it has started doing so. Wait until we get
552+
EOF from the hook. */
553+
useHook = true;
554+
break;
555+
case rpPostpone:
556+
/* Not now; wait until at least one child finishes or
557+
the wake-up timeout expires. */
558+
if (!actLock)
559+
actLock = std::make_unique<Activity>(
560+
*logger,
561+
lvlWarn,
562+
actBuildWaiting,
563+
fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath))));
564+
outputLocks.unlock();
565+
co_await waitForAWhile();
566+
continue;
567+
case rpDecline:
568+
/* We should do it ourselves. */
569+
useHook = false;
570+
break;
571+
}
569572
}
573+
break;
570574
}
571575

572576
actLock.reset();

0 commit comments

Comments
 (0)