@@ -472,101 +472,105 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
472
472
{
473
473
bool useHook;
474
474
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
+ }
499
501
}
500
- }
501
502
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))));
504
506
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
+ }
511
513
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
+ }
520
529
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
+ }
527
539
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 ;
537
545
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) {
567
547
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
+ }
569
572
}
573
+ break ;
570
574
}
571
575
572
576
actLock.reset ();
0 commit comments