forked from lix-project/hydra
Handle concurrent finishing of the same build
There is a slight possibility that the queue monitor and a builder thread simultaneously decide to mark a build as finished. That's fine, as long as we ensure the DB update is idempotent (as ensured by doing "update Builds set finished = 1 ... where finished = 0").
This commit is contained in:
parent
948473c909
commit
9cdbff2fdf
|
@ -163,7 +163,7 @@ struct Step
|
||||||
|
|
||||||
~Step()
|
~Step()
|
||||||
{
|
{
|
||||||
printMsg(lvlError, format("destroying step %1%") % drvPath);
|
//printMsg(lvlError, format("destroying step %1%") % drvPath);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -520,17 +520,18 @@ void State::getQueuedBuilds(Connection & conn, std::shared_ptr<StoreAPI> store,
|
||||||
if (!store->isValidPath(build->drvPath)) {
|
if (!store->isValidPath(build->drvPath)) {
|
||||||
/* Derivation has been GC'ed prematurely. */
|
/* Derivation has been GC'ed prematurely. */
|
||||||
printMsg(lvlError, format("aborting GC'ed build %1%") % build->id);
|
printMsg(lvlError, format("aborting GC'ed build %1%") % build->id);
|
||||||
pqxx::work txn(conn);
|
if (!build->finishedInDB) {
|
||||||
assert(!build->finishedInDB);
|
pqxx::work txn(conn);
|
||||||
txn.parameterized
|
txn.parameterized
|
||||||
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $3, errorMsg = $4 where id = $1")
|
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $3, errorMsg = $4 where id = $1 and finished = 0")
|
||||||
(build->id)
|
(build->id)
|
||||||
((int) bsAborted)
|
((int) bsAborted)
|
||||||
(time(0))
|
(time(0))
|
||||||
("derivation was garbage-collected prior to build").exec();
|
("derivation was garbage-collected prior to build").exec();
|
||||||
txn.commit();
|
txn.commit();
|
||||||
build->finishedInDB = true;
|
build->finishedInDB = true;
|
||||||
nrBuildsDone++;
|
nrBuildsDone++;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -598,18 +599,19 @@ void State::getQueuedBuilds(Connection & conn, std::shared_ptr<StoreAPI> store,
|
||||||
|
|
||||||
if (buildStatus != bsSuccess) {
|
if (buildStatus != bsSuccess) {
|
||||||
time_t now = time(0);
|
time_t now = time(0);
|
||||||
pqxx::work txn(conn);
|
if (!build->finishedInDB) {
|
||||||
createBuildStep(txn, 0, build, r, "", buildStepStatus);
|
pqxx::work txn(conn);
|
||||||
assert(!build->finishedInDB);
|
createBuildStep(txn, 0, build, r, "", buildStepStatus);
|
||||||
txn.parameterized
|
txn.parameterized
|
||||||
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $3, isCachedBuild = $4 where id = $1")
|
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $3, isCachedBuild = $4 where id = $1 and finished = 0")
|
||||||
(build->id)
|
(build->id)
|
||||||
((int) buildStatus)
|
((int) buildStatus)
|
||||||
(now)
|
(now)
|
||||||
(buildStatus != bsUnsupported ? 1 : 0).exec();
|
(buildStatus != bsUnsupported ? 1 : 0).exec();
|
||||||
txn.commit();
|
txn.commit();
|
||||||
build->finishedInDB = true;
|
build->finishedInDB = true;
|
||||||
nrBuildsDone++;
|
nrBuildsDone++;
|
||||||
|
}
|
||||||
badStep = true;
|
badStep = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -622,7 +624,8 @@ void State::getQueuedBuilds(Connection & conn, std::shared_ptr<StoreAPI> store,
|
||||||
|
|
||||||
{
|
{
|
||||||
auto builds_(builds.lock());
|
auto builds_(builds.lock());
|
||||||
(*builds_)[build->id] = build;
|
if (!build->finishedInDB) // FIXME: can this happen?
|
||||||
|
(*builds_)[build->id] = build;
|
||||||
build->toplevel = step;
|
build->toplevel = step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1232,9 +1235,9 @@ bool State::doBuildStep(std::shared_ptr<StoreAPI> store, Step::ptr step,
|
||||||
/* Mark all builds that depend on this derivation as failed. */
|
/* Mark all builds that depend on this derivation as failed. */
|
||||||
for (auto & build2 : indirect) {
|
for (auto & build2 : indirect) {
|
||||||
printMsg(lvlError, format("marking build %1% as failed") % build2->id);
|
printMsg(lvlError, format("marking build %1% as failed") % build2->id);
|
||||||
assert(!build->finishedInDB);
|
if (build->finishedInDB) continue;
|
||||||
txn.parameterized
|
txn.parameterized
|
||||||
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $4, isCachedBuild = $5 where id = $1")
|
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $4, isCachedBuild = $5 where id = $1 and finished = 0")
|
||||||
(build2->id)
|
(build2->id)
|
||||||
((int) (build2->drvPath != step->drvPath && buildStatus == bsFailed ? bsDepFailed : buildStatus))
|
((int) (build2->drvPath != step->drvPath && buildStatus == bsFailed ? bsDepFailed : buildStatus))
|
||||||
(result.startTime)
|
(result.startTime)
|
||||||
|
@ -1272,10 +1275,10 @@ void State::markSucceededBuild(pqxx::work & txn, Build::ptr build,
|
||||||
{
|
{
|
||||||
printMsg(lvlInfo, format("marking build %1% as succeeded") % build->id);
|
printMsg(lvlInfo, format("marking build %1% as succeeded") % build->id);
|
||||||
|
|
||||||
assert(!build->finishedInDB);
|
if (build->finishedInDB) return;
|
||||||
|
|
||||||
txn.parameterized
|
txn.parameterized
|
||||||
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $4, size = $5, closureSize = $6, releaseName = $7, isCachedBuild = $8 where id = $1")
|
("update Builds set finished = 1, busy = 0, buildStatus = $2, startTime = $3, stopTime = $4, size = $5, closureSize = $6, releaseName = $7, isCachedBuild = $8 where id = $1 and finished = 0")
|
||||||
(build->id)
|
(build->id)
|
||||||
((int) (res.failed ? bsFailedWithOutput : bsSuccess))
|
((int) (res.failed ? bsFailedWithOutput : bsSuccess))
|
||||||
(startTime)
|
(startTime)
|
||||||
|
|
|
@ -28,6 +28,9 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Sync() { }
|
||||||
|
Sync(const T & data) : data(data) { }
|
||||||
|
|
||||||
class Lock
|
class Lock
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue