* Subtle bug in the builder: if a subgoal that is instantiated

multiple times is also a top-level goal, then the second and later
  instantiations would never be created because there would be a
  stable pointer to the first one that would keep it alive in the
  WeakGoalMap.
* Some tracing code for debugging this kind of problem.
This commit is contained in:
Eelco Dolstra 2005-02-18 09:50:20 +00:00
parent 398463a72a
commit 3c1630131e

View file

@ -60,6 +60,9 @@ protected:
/* Whether amDone() has been called. */
bool done;
/* Name of this goal for debugging purposes. */
string name;
Goal(Worker & worker) : worker(worker)
{
done = false;
@ -68,14 +71,12 @@ protected:
virtual ~Goal()
{
printMsg(lvlVomit, "goal destroyed");
trace("goal destroyed");
}
public:
virtual void work() = 0;
virtual string name() = 0;
void addWaitee(GoalPtr waitee);
virtual void waiteeDone(GoalPtr waitee, bool success);
@ -87,6 +88,11 @@ public:
void trace(const format & f);
string getName()
{
return name;
}
protected:
void amDone(bool success = true);
};
@ -198,6 +204,9 @@ void Goal::waiteeDone(GoalPtr waitee, bool success)
assert(waitees.find(waitee) != waitees.end());
waitees.erase(waitee);
trace(format("waitee `%1%' done; %2% left") %
waitee->name % waitees.size());
if (!success) ++nrFailed;
if (waitees.empty() || (!success && !keepGoing)) {
@ -236,7 +245,7 @@ void Goal::amDone(bool success)
void Goal::trace(const format & f)
{
debug(format("%1%: %2%") % name() % f);
debug(format("%1%: %2%") % name % f);
}
@ -379,8 +388,6 @@ private:
/* Return the set of (in)valid paths. */
PathSet checkPathValidity(bool returnValid);
string name();
};
@ -389,6 +396,8 @@ DerivationGoal::DerivationGoal(const Path & drvPath, Worker & worker)
{
this->drvPath = drvPath;
state = &DerivationGoal::init;
name = (format("building of `%1%'") % drvPath).str();
trace("created");
}
@ -1232,12 +1241,6 @@ PathSet DerivationGoal::checkPathValidity(bool returnValid)
}
string DerivationGoal::name()
{
return (format("building of `%1%'") % drvPath).str();
}
//////////////////////////////////////////////////////////////////////
@ -1284,8 +1287,6 @@ public:
/* Callback used by the worker to write to the log. */
void writeLog(int fd, const unsigned char * buf, size_t count);
string name();
};
@ -1294,6 +1295,8 @@ SubstitutionGoal::SubstitutionGoal(const Path & storePath, Worker & worker)
{
this->storePath = storePath;
state = &SubstitutionGoal::init;
name = (format("substitution of `%1%'") % storePath).str();
trace("created");
}
@ -1524,12 +1527,6 @@ void SubstitutionGoal::writeLog(int fd,
}
string SubstitutionGoal::name()
{
return (format("substitution of `%1%'") % storePath).str();
}
//////////////////////////////////////////////////////////////////////
@ -1545,6 +1542,7 @@ public:
PseudoGoal(Worker & worker) : Goal(worker)
{
success = true;
name = "pseudo-goal";
}
void work()
@ -1561,11 +1559,6 @@ public:
{
return success;
}
string name()
{
return "pseudo-goal";
}
};
@ -1625,9 +1618,15 @@ GoalPtr Worker::makeSubstitutionGoal(const Path & storePath)
static void removeGoal(GoalPtr goal, WeakGoalMap & goalMap)
{
/* !!! For now we just let dead goals accumulate. We should
probably periodically sweep the goalMap to remove dead
goals. */
/* !!! inefficient */
for (WeakGoalMap::iterator i = goalMap.begin();
i != goalMap.end(); )
if (i->second.lock() == goal) {
WeakGoalMap::iterator j = i; ++j;
goalMap.erase(i);
i = j;
}
else ++i;
}
@ -1796,13 +1795,13 @@ void Worker::waitForInput()
if (rd == -1) {
if (errno != EINTR)
throw SysError(format("reading from %1%")
% goal->name());
% goal->getName());
} else if (rd == 0) {
debug(format("%1%: got EOF") % goal->name());
debug(format("%1%: got EOF") % goal->getName());
wakeUp(goal);
} else {
printMsg(lvlVomit, format("%1%: read %2% bytes")
% goal->name() % rd);
% goal->getName() % rd);
goal->writeLog(fd, buffer, (size_t) rd);
if (verbosity >= buildVerbosity)
writeFull(STDERR_FILENO, buffer, rd);