Currently, the hydra.nixos.org queue contains 1000s of Darwin builds that all depend on a stdenv-darwin that previously failed. However, before, first createStep() would construct a dependency graph for each build, then getQueuedBuilds() would discover that one of the steps had failed previously and discard all those steps. Since the graph construction involves a lot of uncached calls to isValidPath(), this took several seconds per build.
Now createStep() detects the previous failure right away and bails out.
YTAYNN7VNYZNLGUSGY3EF33MGQWMJW76FKV657SBKASQFQC7EB3AC BRAESISHTN4IIWUBVDMPDMY7QLMJDKX7GQ7K6NSJN66L5VPWSX3QC UNVMKJV5VX74A2MLS42AP3SY25HKQSH4S27Y44QFKRQRKPU2MV6QC MHVIT4JYWUYD4UCGB2AHLXWLX6B5SYE22BREERNGANT7RGGDUFOAC 73YR46NJNYZQKHA3QDJCAZYAKC2CGEF5LIS44NOIPDZU6FX6BDPQC 4CQWOODYIBUEMPSLWTXZPZZTQBYYRGCORKLY4SKG2WVCVXGT654QC BCDHO4OULIMAC2RNZM5LKDOD2CYENXU6JGEHQZEXZBUMXK3QC3AAC TPNHTE5VJ36IPKMFENDERDBFBHLYFXOVNDLV2QSC4G5STPPMBLMAC Step::ptr step = createStep(destStore, conn, build, build->drvPath,build, 0, finishedDrvs, newSteps, newRunnable);
Step::ptr step;/* Create steps for this derivation and its dependencies. */try {step = createStep(destStore, conn, build, build->drvPath,build, 0, finishedDrvs, newSteps, newRunnable);} catch (PreviousFailure & ex) {/* Some step previously failed, so mark the build asfailed right away. */printMsg(lvlError, format("marking build %d as cached failure due to ‘%s’") % build->id % ex.step->drvPath);if (!build->finishedInDB) {auto mc = startDbUpdate();pqxx::work txn(conn);/* Find the previous build step record, first byderivation path, then by output path. */BuildID propagatedFrom = 0;auto res = txn.parameterized("select max(build) from BuildSteps where drvPath = $1 and startTime != 0 and stopTime != 0 and status = 1")(ex.step->drvPath).exec();if (!res[0][0].is_null()) propagatedFrom = res[0][0].as<BuildID>();if (!propagatedFrom) {for (auto & output : ex.step->drv.outputs) {auto res = txn.parameterized("select max(s.build) from BuildSteps s join BuildStepOutputs o on s.build = o.build where path = $1 and startTime != 0 and stopTime != 0 and status = 1")(output.second.path).exec();if (!res[0][0].is_null()) {propagatedFrom = res[0][0].as<BuildID>();break;}}}createBuildStep(txn, 0, build, ex.step, "", bsCachedFailure, "", propagatedFrom);txn.parameterized("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $3, isCachedBuild = 1 where id = $1 and finished = 0")(build->id)((int) (ex.step->drvPath == build->drvPath ? bsFailed : bsDepFailed))(time(0)).exec();txn.commit();build->finishedInDB = true;nrBuildsDone++;}return;}
/* If any step has a previously failed output path, then failthe build right away. */bool badStep = false;for (auto & r : newSteps)if (checkCachedFailure(r, conn)) {printMsg(lvlError, format("marking build %1% as cached failure") % build->id);if (!build->finishedInDB) {auto mc = startDbUpdate();pqxx::work txn(conn);/* Find the previous build step record, first byderivation path, then by output path. */BuildID propagatedFrom = 0;
auto res = txn.parameterized("select max(build) from BuildSteps where drvPath = $1 and startTime != 0 and stopTime != 0 and status = 1")(r->drvPath).exec();if (!res[0][0].is_null()) propagatedFrom = res[0][0].as<BuildID>();if (!propagatedFrom) {for (auto & output : r->drv.outputs) {auto res = txn.parameterized("select max(s.build) from BuildSteps s join BuildStepOutputs o on s.build = o.build where path = $1 and startTime != 0 and stopTime != 0 and status = 1")(output.second.path).exec();if (!res[0][0].is_null()) {propagatedFrom = res[0][0].as<BuildID>();break;}}}createBuildStep(txn, 0, build, r, "", bsCachedFailure, "", propagatedFrom);txn.parameterized("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $3, isCachedBuild = 1 where id = $1 and finished = 0")(build->id)((int) (step == r ? bsFailed : bsDepFailed))(time(0)).exec();txn.commit();build->finishedInDB = true;nrBuildsDone++;}badStep = true;break;}if (badStep) return;