* When using build hooks, for any nix-store -r build operation, it is

necessary that at least one build hook doesn't return "postpone",
  otherwise nix-store will barf ("waiting for a build slot, yet there
  are no running children").  So inform the build hook when this is
  the case, so that it can start a build even when that would exceed
  the maximum load on a machine.
This commit is contained in:
Eelco Dolstra 2008-12-04 14:29:41 +00:00
parent 5dfba0b4db
commit 909fbb9de1
2 changed files with 18 additions and 7 deletions

View file

@ -23,10 +23,8 @@ use English '-no_match_vars';
my $loadIncreased = 0; my $loadIncreased = 0;
my $amWilling = shift @ARGV; my ($amWilling, $localSystem, $neededSystem, $drvPath, $mustRun) = @ARGV;
my $localSystem = shift @ARGV; $mustRun = 0 unless defined $mustRun;
my $neededSystem = shift @ARGV;
my $drvPath = shift @ARGV;
sub sendReply { sub sendReply {
my $reply = shift; my $reply = shift;
@ -91,10 +89,12 @@ LOOP: foreach my $cur (@machines) {
# We have a machine of the right type. Try to get a lock on # We have a machine of the right type. Try to get a lock on
# one of the machine's lock files. # one of the machine's lock files.
my $slot = 0; my $slot = 0;
while ($slot < $cur->{maxJobs}) { while ($slot < $cur->{maxJobs} || $mustRun) {
my $slotLock = "$currentLoad/" . $cur->{systemType} . "-" . $cur->{hostName} . "-$slot"; my $slotLock = "$currentLoad/" . $cur->{systemType} . "-" . $cur->{hostName} . "-$slot";
open SLOTLOCK, ">>$slotLock" or die; open SLOTLOCK, ">>$slotLock" or die;
if (flock(SLOTLOCK, LOCK_EX | LOCK_NB)) { if (flock(SLOTLOCK, LOCK_EX | LOCK_NB)) {
print STDERR "warning: exceeding maximum load on " . $cur->{systemType} . "\n"
if $slot >= $cur->{maxJobs};
$machine = $cur; $machine = $cur;
last LOOP; last LOOP;
} }

View file

@ -219,6 +219,9 @@ public:
/* Can we start another child process? */ /* Can we start another child process? */
bool canBuildMore(); bool canBuildMore();
/* Can we postpone a build right now? */
bool canPostpone();
/* 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. */
void childStarted(GoalPtr goal, pid_t pid, void childStarted(GoalPtr goal, pid_t pid,
@ -1296,7 +1299,9 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
(worker.canBuildMore() ? (string) "1" : "0").c_str(), (worker.canBuildMore() ? (string) "1" : "0").c_str(),
thisSystem.c_str(), thisSystem.c_str(),
drv.platform.c_str(), drv.platform.c_str(),
drvPath.c_str(), NULL); drvPath.c_str(),
(worker.canPostpone() ? (string) "0" : "1").c_str(),
NULL);
throw SysError(format("executing `%1%'") % buildHook); throw SysError(format("executing `%1%'") % buildHook);
@ -2602,6 +2607,12 @@ bool Worker::canBuildMore()
} }
bool Worker::canPostpone()
{
return children.size() != 0;
}
void Worker::childStarted(GoalPtr goal, void Worker::childStarted(GoalPtr goal,
pid_t pid, const set<int> & fds, bool inBuildSlot) pid_t pid, const set<int> & fds, bool inBuildSlot)
{ {