hydra-eval-jobs: Parallelize
[?]
Feb 19, 2020, 8:10 PM
XJISJGZLGWLCTN6EZWVVHKQFCDVCSXTNYL7YE2UB74AOA2XGYOCACDependencies
- [2]
GPZYBCJCaccidentally committed an = too little, which caused all unknown values to result in 'not building', which was not the intention - [3]
CYVWW32QRevert "Fix broken build.x86_64-linux job (#573)" - [4]
A6POFA3Hhydra-eval-jobs: Filter ANSI escape sequences - [5]
VMZDEQQ5Increase maxHeapSize more gradually - [6]
CXKN2W4Bhydra-eval-jobs: Reinitialize Boehm GC in the child - [7]
JSBIUNY6hydra-eval-jobs: fix maintainer resolution - [8]
YRXR3WDPhydra-eval-jobs: Warn and resets maxHeapSize on bad values - [9]
WV4SSAIYBuild against nix-master - [10]
HNGPGVBTFix build - [11]
ALU52WZJHandle attrsets in meta.license (i.e. lib.licenses) - [12]
MIC2O6ZFUse evalFile() instead of parseExprFromFile() - [13]
7YCFGMZB* Report evaluation errors per job, and don't bail out if a job fails - [14]
SM5M2J3APass inputs to release expressions using -I - [15]
L4GM4MA6Call initGC() - [16]
HVXL2XUZ - [17]
D6VR5FYG* Fix hydra_eval_jobs. - [18]
DPYJFBXUhydra-eval-jobs: Support meta.license being a list - [19]
KD5237CU* eval-jobs now efficiently evaluates all Hydra jobs from a - [20]
5DYPEBSIhydra-eval-jobs: Use function argument default values - [21]
RLXDJAG2hydra-eval-jobs: Add --dry-run option - [22]
AEFNBIIW* Merge the GC branch. - [23]
DKJFD6JNProcess Nix API changes - [24]
IMQRX4MPhydra-eval-jobs: Use JSON instead of XML - [25]
FHXU6346hydra-eval-jobs: Pass all inputs as 'inputs' arg. - [26]
4GTOWRFWhydra-eval-jobs: Fix build - [27]
STZE4KKRFix build against Nix master - [28]
VTNP5KDO* Don't catch all errors. Some errors mess up the connection with the - [29]
JTHWA6AMRename aggregate members to constituents - [30]
POPU2ATH* hydra_scheduler: use eval-jobs. - [31]
PMNWRTGJAdd multiple output support - [32]
VTMBJVIShydra-eval-jobs: Disable the build hook. - [33]
P45ANG5BFix build - [34]
YNGIYQRFhydra-eval-jobs: Don't keep track of used inputs - [35]
4XR2A7QD* Fix building hydra_eval_jobs against the sqlite branch. - [36]
5MP35ORVhydra-eval-jobs: Ugly hackery to reduce memory usage - [37]
AYMPPH7GDon't write one character at a time, it's inefficient - [38]
ZTQEU5QSHydra: Add support for maxSilent meta attribute (also already added timeout, but not implemented the actual timeout for the build yet) - [39]
HP5WJLQUhydra-eval-{jobs,jobset}: Pass file name as <...> - [40]
4N5APGRG* Start of a helper tool to evaluate job expressions efficiently. - [41]
FGUL3HAZhydra-eval-jobs: Don't go into an infinite recursion - [42]
IZ2AHLM3* Export all relevant info about the derivation. - [43]
YGRLM2SK* Export all relevant info about the derivation. - [44]
77VF5TC6* For ease of use during debugging, don't require --gc-roots-dir. - [45]
HJYRK37A* Revert r27114, it seems to break stuff. - [46]
BGMBEXS6Gradually increase maxHeapSize - [47]
WUMCRXFXDon't ignore assertion failures in getDerivation() - [48]
4LWGZL33 - [49]
EBG4P4SYDoh - clear $NIX_PATH properly - [50]
A63IHCMX* Register GC roots properly. - [51]
AEKIREIH* Updated hydra_eval_jobs for the new evaluator. - [52]
WJTP6VZIFix building against the latest Nix - [53]
7D6RFSAAFix build for new nixUnstable - [54]
5MNUNZWR* Store meta.maintainers. - [55]
5X6FHW3Shydra-eval-jobs: Fix building against the latest unstable Nix - [56]
SYN2GC3Oallow null values for jobs, meaning it should build - [57]
I2HYJBMLDebug tweak - [58]
52JSLNC6* Build fix. - [59]
3PNG7NIBRemove trailing whitespace - [60]
OC4Q4PXCSync with nixUnstable - [61]
JQ5VHWRBFix broken build.x86_64-linux job (#573) - [62]
L4LBF7UFHandle derivations without a system attribute - [63]
M5BEPXTETweak debug output - [64]
ZVSHXE3KAllow setting GC_INITIAL_HEAP_SIZE for hydra-eval-jobs - [65]
M3A5PZIHhydra: Clarify the dependency on BDW-GC. - [66]
FUB37KFUUse Nix's restricted evaluation mode - [67]
7GKAIP3VFix build and handling of string inputs starting with a dash - [68]
FTPCV25MStore aggregate members in the database - [69]
FGLKIVYSFix build against Nix master
Change contents
- edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 3[10.339]→[10.354:355](∅→∅),[10.355]→[6.0:27](∅→∅),[6.27]→[10.355:384](∅→∅),[10.355]→[10.355:384](∅→∅)
#define GC_LINUX_THREADS 1#include <gc/gc_allocator.h> - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 9
#include "json.hh" - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 12
#include "attr-path.hh"#include "derivations.hh" - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 19
#include <sys/resource.h> - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 21
using namespace nix;#include <nlohmann/json.hpp> - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 23
using namespace nix; - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 26
static size_t maxMemorySize; - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 28
struct MyArgs : MixEvalArgs, MixCommonArgs{Path releaseExpr;bool dryRun = false; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 33
static void findJobs(EvalState & state, JSONObject & top,Bindings & autoArgs, Value & v, const string & attrPath);MyArgs() : MixCommonArgs("hydra-eval-jobs"){mkFlag().longName("help").description("show usage information").handler([&]() {printHelp(programName, std::cout);throw Exit();}); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 43
mkFlag().longName("gc-roots-dir").description("garbage collector roots directory").labels({"path"}).dest(&gcRootsDir); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 49
static string queryMetaStrings(EvalState & state, DrvInfo & drv, const string & name, const string & subAttribute)mkFlag().longName("dry-run").description("don't create store derivations").set(&dryRun, true);expectArg("expr", &releaseExpr);}};static MyArgs myArgs;static std::string queryMetaStrings(EvalState & state, DrvInfo & drv, const string & name, const string & subAttribute) - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 84
static std::string lastAttrPath;static bool comma = false;static size_t maxHeapSize; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 85
struct BailOut { };static void worker(EvalState & state,Bindings & autoArgs,AutoCloseFD & to,AutoCloseFD & from){Value vTop;state.evalFile(lookupFileArg(state, myArgs.releaseExpr), vTop); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 94
auto vRoot = state.allocValue();state.autoCallFunction(autoArgs, vTop, *vRoot); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 97
bool lte(const std::string & s1, const std::string & s2){size_t p1 = 0, p2 = 0; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 98
if (p1 == s1.size()) return p2 == s2.size();if (p2 == s2.size()) return true;/* Wait for the master to send us a job name. */writeLine(to.get(), "next"); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 101
auto d1 = s1.find('.', p1);auto d2 = s2.find('.', p2);auto s = readLine(from.get());if (s == "exit") break;if (!hasPrefix(s, "do ")) abort();std::string attrPath(s, 3); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 106
auto c = s1.compare(p1, d1 - p1, s2, p2, d2 - p2);debug("worker process %d at '%s'", getpid(), attrPath); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 108
if (c < 0) return true;if (c > 0) return false;/* Evaluate it and send info back to the master. */nlohmann::json reply; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 111
p1 = d1 == std::string::npos ? s1.size() : d1 + 1;p2 = d2 == std::string::npos ? s2.size() : d2 + 1;}}try {auto v = findAlongAttrPath(state, attrPath, autoArgs, *vRoot).first; - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 114
state.forceValue(*v); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 116[10.688]→[10.369:434](∅→∅),[10.1574]→[10.369:434](∅→∅),[10.434]→[10.95:158](∅→∅),[10.158]→[10.255:257](∅→∅),[10.426]→[10.255:257](∅→∅),[10.1673]→[10.255:257](∅→∅),[10.255]→[10.255:257](∅→∅),[10.257]→[10.689:756](∅→∅)
static void findJobsWrapped(EvalState & state, JSONObject & top,Bindings & autoArgs, Value & vIn, const string & attrPath){if (lastAttrPath != "" && lte(attrPath, lastAttrPath)) return;if (auto drv = getDerivation(state, *v, false)) { - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 118
debug(format("at path `%1%'") % attrPath);DrvInfo::Outputs outputs = drv->queryOutputs(); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 120
checkInterrupt();if (drv->querySystem() == "unknown")throw EvalError("derivation must have a 'system' attribute"); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 123
Value v;state.autoCallFunction(autoArgs, vIn, v);auto drvPath = drv->queryDrvPath(); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 125
if (v.type == tAttrs) {nlohmann::json job; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 127
auto drv = getDerivation(state, v, false);job["nixName"] = drv->queryName();job["system"] =drv->querySystem();job["drvPath"] = drvPath;job["description"] = drv->queryMetaString("description");job["license"] = queryMetaStrings(state, *drv, "license", "shortName");job["homepage"] = drv->queryMetaString("homepage");job["maintainers"] = queryMetaStrings(state, *drv, "maintainers", "email");job["schedulingPriority"] = drv->queryMetaInt("schedulingPriority", 100);job["timeout"] = drv->queryMetaInt("timeout", 36000);job["maxSilent"] = drv->queryMetaInt("maxSilent", 7200);job["isChannel"] = drv->queryMetaBool("isHydraChannel", false); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 139
if (drv) {Path drvPath;/* If this is an aggregate, then get its constituents. */auto a = v->attrs->get(state.symbols.create("_hydraAggregate"));if (a && state.forceBool(*a->value, *a->pos)) {auto a = v->attrs->get(state.symbols.create("constituents"));if (!a)throw EvalError("derivation must have a ‘constituents’ attribute"); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 146
DrvInfo::Outputs outputs = drv->queryOutputs(); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 147[10.748]→[10.133:182](∅→∅),[10.182]→[10.41:123](∅→∅),[10.41]→[10.41:123](∅→∅),[10.123]→[10.758:819](∅→∅),[10.819]→[10.123:124](∅→∅),[10.123]→[10.123:124](∅→∅),[10.124]→[10.0:14](∅→∅),[10.14]→[10.20:65](∅→∅),[10.65]→[10.183:424](∅→∅),[10.424]→[7.189:277](∅→∅),[7.277]→[10.499:567](∅→∅),[10.499]→[10.499:567](∅→∅),[10.567]→[7.278:370](∅→∅),[7.370]→[10.650:963](∅→∅),[10.650]→[10.650:963](∅→∅)
if (drv->querySystem() == "unknown")throw EvalError("derivation must have a ‘system’ attribute");if (comma) { std::cout << ","; comma = false; }{auto res = top.object(attrPath);res.attr("nixName", drv->queryName());res.attr("system", drv->querySystem());res.attr("drvPath", drvPath = drv->queryDrvPath());res.attr("description", drv->queryMetaString("description"));res.attr("license", queryMetaStrings(state, *drv, "license", "shortName"));res.attr("homepage", drv->queryMetaString("homepage"));res.attr("maintainers", queryMetaStrings(state, *drv, "maintainers", "email"));res.attr("schedulingPriority", drv->queryMetaInt("schedulingPriority", 100));res.attr("timeout", drv->queryMetaInt("timeout", 36000));res.attr("maxSilent", drv->queryMetaInt("maxSilent", 7200));res.attr("isChannel", drv->queryMetaBool("isHydraChannel", false));PathSet context;state.coerceToString(*a->pos, *a->value, context, true, false);for (auto & i : context)if (i.at(0) == '!') {size_t index = i.find("!", 1);job["constituents"].push_back(string(i, index + 1));} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 155[10.1270]→[10.0:70](∅→∅),[10.70]→[10.65:156](∅→∅),[10.65]→[10.65:156](∅→∅),[10.156]→[10.66:144](∅→∅),[10.144]→[10.71:163](∅→∅),[10.225]→[10.71:163](∅→∅),[10.163]→[10.312:353](∅→∅),[10.312]→[10.312:353](∅→∅),[10.353]→[10.164:256](∅→∅),[10.256]→[10.440:473](∅→∅),[10.440]→[10.440:473](∅→∅),[10.473]→[10.26:106](∅→∅),[10.106]→[10.544:574](∅→∅),[10.544]→[10.544:574](∅→∅),[10.574]→[10.304:501](∅→∅)
/* If this is an aggregate, then get its constituents. */Bindings::iterator a = v.attrs->find(state.symbols.create("_hydraAggregate"));if (a != v.attrs->end() && state.forceBool(*a->value, *a->pos)) {Bindings::iterator a = v.attrs->find(state.symbols.create("constituents"));if (a == v.attrs->end())throw EvalError("derivation must have a ‘constituents’ attribute");PathSet context;state.coerceToString(*a->pos, *a->value, context, true, false);PathSet drvs;for (auto & i : context)if (i.at(0) == '!') {size_t index = i.find("!", 1);drvs.insert(string(i, index + 1));state.forceList(*a->value, *a->pos);for (unsigned int n = 0; n < a->value->listSize(); ++n) {auto v = a->value->listElems()[n];state.forceValue(*v);if (v->type == tString)job["namedConstituents"].push_back(state.forceStringNoCtx(*v)); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 162[10.811]→[10.1262:1333](∅→∅),[10.329]→[10.878:892](∅→∅),[10.1333]→[10.878:892](∅→∅),[10.878]→[10.878:892](∅→∅)
res.attr("constituents", concatStringsSep(" ", drvs));}} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 164[10.893]→[10.126:278](∅→∅),[10.1270]→[10.126:278](∅→∅),[10.953]→[10.126:278](∅→∅),[10.278]→[10.145:275](∅→∅),[10.275]→[9.47:262](∅→∅),[10.82]→[10.178:192](∅→∅),[10.87]→[10.178:192](∅→∅),[9.262]→[10.178:192](∅→∅),[10.362]→[10.178:192](∅→∅),[10.178]→[10.178:192](∅→∅),[10.192]→[10.804:805](∅→∅),[10.805]→[10.363:410](∅→∅),[10.410]→[10.1405:1488](∅→∅),[10.1405]→[10.1405:1488](∅→∅),[10.1488]→[10.15:16](∅→∅),[10.16]→[10.820:834](∅→∅)
/* Register the derivation as a GC root. !!! Thisregisters roots for jobs that we may have alreadydone. */auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>();if (gcRootsDir != "" && localStore) {Path root = gcRootsDir + "/" + std::string(baseNameOf(drvPath));if (!pathExists(root))localStore->addPermRoot(localStore->parseStorePath(drvPath), root, false);}auto res2 = res.object("outputs");for (auto & j : outputs)res2.attr(j.first, j.second);}/* Register the derivation as a GC root. !!! Thisregisters roots for jobs that we may have alreadydone. */auto localStore = state.store.dynamic_pointer_cast<LocalFSStore>();if (gcRootsDir != "" && localStore) {Path root = gcRootsDir + "/" + std::string(baseNameOf(drvPath));if (!pathExists(root))localStore->addPermRoot(localStore->parseStorePath(drvPath), root, false);} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 174
GC_prof_stats_s gc;GC_get_prof_stats(&gc, sizeof(gc));nlohmann::json out;for (auto & j : outputs)out[j.first] = j.second;job["outputs"] = std::move(out); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 179
if (gc.heapsize_full > maxHeapSize) {printInfo("restarting hydra-eval-jobs after job '%s' because heap size is at %d bytes", attrPath, gc.heapsize_full);lastAttrPath = attrPath;throw BailOut();reply["job"] = std::move(job); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 181[10.64]→[10.1148:1158](∅→∅),[10.419]→[10.1148:1158](∅→∅),[10.1488]→[10.1148:1158](∅→∅),[10.1863]→[10.1148:1158](∅→∅),[10.1148]→[10.1148:1158](∅→∅)
} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 182
else {if (!state.isDerivation(v)) {for (auto & i : v.attrs->lexicographicOrder()) {else if (v->type == tAttrs) {auto attrs = nlohmann::json::array();StringSet ss;for (auto & i : v->attrs->lexicographicOrder()) { - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 187
/* Skip jobs with dots in the name. */if (name.find('.') != std::string::npos) {if (name.find('.') != std::string::npos || name.find(' ') != std::string::npos) { - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 191
findJobs(state, top, autoArgs, *i->value,(attrPath.empty() ? "" : attrPath + ".") + name);attrs.push_back(name); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 193
reply["attrs"] = std::move(attrs); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 195
} catch (EvalError & e) {reply["error"] = filterANSIEscapes(e.msg(), true); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 199
} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 200
else if (v.type == tNull) {// allow null values, meaning 'do nothing'writeLine(to.get(), reply.dump());/* If our RSS exceeds the maximum, exit. The master willstart a new process. */struct rusage r;getrusage(RUSAGE_SELF, &r);if ((size_t) r.ru_maxrss > maxMemorySize * 1024) break; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 209
elsethrow TypeError(format("unsupported value: %1%") % v);writeLine(to.get(), "restart"); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 211[10.492]→[10.492:494](∅→∅),[10.494]→[10.1607:1665](∅→∅),[10.1665]→[10.281:342](∅→∅),[10.342]→[10.646:658](∅→∅),[10.612]→[10.646:658](∅→∅),[10.2402]→[10.646:658](∅→∅),[10.646]→[10.646:658](∅→∅),[10.658]→[10.343:403](∅→∅),[10.403]→[10.0:30](∅→∅),[10.673]→[10.0:30](∅→∅),[10.1726]→[10.0:30](∅→∅),[10.2473]→[10.0:30](∅→∅),[10.728]→[10.0:30](∅→∅),[10.30]→[10.1702:1758](∅→∅),[10.1758]→[10.411:452](∅→∅),[10.10]→[10.411:452](∅→∅),[10.452]→[4.0:61](∅→∅),[4.61]→[10.944:950](∅→∅),[10.95]→[10.944:950](∅→∅),[10.1849]→[10.944:950](∅→∅),[10.944]→[10.944:950](∅→∅),[10.950]→[10.541:544](∅→∅),[10.1571]→[10.541:544](∅→∅),[10.2102]→[10.541:544](∅→∅),[10.541]→[10.541:544](∅→∅)
static void findJobs(EvalState & state, JSONObject & top,Bindings & autoArgs, Value & v, const string & attrPath){try {findJobsWrapped(state, top, autoArgs, v, attrPath);} catch (EvalError & e) {if (comma) { std::cout << ","; comma = false; }auto res = top.object(attrPath);res.attr("error", filterANSIEscapes(e.msg(), true));}} - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 214
assert(lte("abc", "def"));assert(lte("abc", "def.foo"));assert(!lte("def", "abc"));assert(lte("nixpkgs.hello", "nixpkgs"));assert(lte("nixpkgs.hello", "nixpkgs.hellooo"));assert(lte("gitAndTools.git-annex.x86_64-darwin", "gitAndTools.git-annex.x86_64-linux"));assert(lte("gitAndTools.git-annex.x86_64-linux", "gitAndTools.git-annex-remote-b2.aarch64-linux")); - edit in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 221
auto initialHeapSize = config->getStrOption("evaluator_initial_heap_size", "");if (initialHeapSize != "")setenv("GC_INITIAL_HEAP_SIZE", initialHeapSize.c_str(), 1); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 222
maxHeapSize = config->getIntOption("evaluator_max_heap_size", 1UL << 30);auto nrWorkers = config->getIntOption("evaluator_workers", 1);maxMemorySize = config->getIntOption("evaluator_max_memory_size", 4096); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 228
/* Read the current heap size, which is the initial heap size. */GC_prof_stats_s gc;GC_get_prof_stats(&gc, sizeof(gc));auto initialHeapSizeInt = gc.heapsize_full;myArgs.parseCmdline(argvToStrings(argc, argv)); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 230
/* Then make sure the maximum heap size will be bigger than the initial heap size. */if (initialHeapSizeInt > maxHeapSize) {printInfo("warning: evaluator_initial_heap_size (%d) bigger than evaluator_max_heap_size (%d).", initialHeapSizeInt, maxHeapSize);maxHeapSize = initialHeapSizeInt * 1.1;printInfo(" evaluator_max_heap_size now set to %d.", maxHeapSize);}/* FIXME: The build hook in conjunction with import-from-derivation is causing "unexpected EOF" during eval */settings.builders = ""; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 233
Path releaseExpr;/* Prevent access to paths outside of the Nix search path andto the environment. */evalSettings.restrictEval = true; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 237
struct MyArgs : LegacyArgs, MixEvalArgsif (myArgs.dryRun) settings.readOnlyMode = true;if (myArgs.releaseExpr == "") throw UsageError("no expression specified");if (gcRootsDir == "") printMsg(lvlError, "warning: `--gc-roots-dir' not specified");struct State - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 245
using LegacyArgs::LegacyArgs;std::set<std::string> todo{""};std::set<std::string> active;nlohmann::json jobs;std::exception_ptr exc; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 251[10.516]→[10.516:663](∅→∅),[10.663]→[10.975:1028](∅→∅),[10.975]→[10.975:1028](∅→∅),[10.1028]→[10.23:111](∅→∅),[10.111]→[10.1028:1112](∅→∅),[10.1028]→[10.1028:1112](∅→∅),[10.80]→[10.2631:2648](∅→∅),[10.1112]→[10.2631:2648](∅→∅),[10.1258]→[10.2631:2648](∅→∅),[10.2631]→[10.2631:2648](∅→∅),[10.2648]→[10.0:36](∅→∅),[10.36]→[10.1158:1195](∅→∅),[10.1158]→[10.1158:1195](∅→∅)
MyArgs myArgs(baseNameOf(argv[0]), [&](Strings::iterator & arg, const Strings::iterator & end) {if (*arg == "--gc-roots-dir")gcRootsDir = getArg(*arg, arg, end);else if (*arg == "--dry-run")settings.readOnlyMode = true;else if (*arg != "" && arg->at(0) == '-')return false;elsereleaseExpr = *arg;return true;});std::condition_variable wakeup;Sync<State> state_;/* Start a handler thread per worker process. */auto handler = [&](){try {pid_t pid = -1;AutoCloseFD from, to;while (true) { - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 264
myArgs.parseCmdline(argvToStrings(argc, argv));/* Start a new worker process if necessary. */if (pid == -1) {Pipe toPipe, fromPipe;toPipe.create();fromPipe.create();pid = startProcess([&,to{std::make_shared<AutoCloseFD>(std::move(fromPipe.writeSide))},from{std::make_shared<AutoCloseFD>(std::move(toPipe.readSide))}](){try {EvalState state(myArgs.searchPath, openStore());Bindings & autoArgs = *myArgs.getAutoArgs(state);worker(state, autoArgs, *to, *from);} catch (std::exception & e) {nlohmann::json err;err["error"] = e.what();writeLine(to->get(), err.dump());}},ProcessOptions { .allowVfork = false });from = std::move(fromPipe.readSide);to = std::move(toPipe.writeSide);debug("created worker process %d", pid);} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 291
JSONObject json(std::cout, true);std::cout.flush();/* Check whether the existing worker process is still there. */auto s = readLine(from.get());if (s == "restart") {pid = -1;continue;} else if (s != "next") {auto json = nlohmann::json::parse(s);throw Error("worker error: %s", (std::string) json["error"]);} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 301
do {/* Wait for a job name to become available. */std::string attrPath; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 304
Pipe pipe;pipe.create();while (true) {checkInterrupt();auto state(state_.lock());if ((state->todo.empty() && state->active.empty()) || state->exc) {writeLine(to.get(), "exit");return;}if (!state->todo.empty()) {attrPath = *state->todo.begin();state->todo.erase(state->todo.begin());state->active.insert(attrPath);break;} elsestate.wait(wakeup);} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 320
ProcessOptions options;options.allowVfork = false;/* Tell the worker to evaluate it. */writeLine(to.get(), "do " + attrPath); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 323
GC_atfork_prepare();/* Wait for the response. */auto response = nlohmann::json::parse(readLine(from.get())); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 326
auto pid = startProcess([&]() {pipe.readSide = -1;/* Handle the response. */StringSet newAttrs; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 329
GC_atfork_child();GC_start_mark_threads();if (response.find("job") != response.end()) {auto state(state_.lock());state->jobs[attrPath] = response["job"];} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 334
if (lastAttrPath != "") debug("resuming from '%s'", lastAttrPath);if (response.find("attrs") != response.end()) {for (auto & i : response["attrs"]) {auto s = (attrPath.empty() ? "" : attrPath + ".") + (std::string) i;newAttrs.insert(s);}} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 341
/* FIXME: The build hook in conjunction with import-from-derivation is causing "unexpected EOF" during eval */settings.builders = "";if (response.find("error") != response.end()) {auto state(state_.lock());state->jobs[attrPath]["error"] = response["error"];} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 346
/* Prevent access to paths outside of the Nix search path andto the environment. */evalSettings.restrictEval = true;/* Add newly discovered job names to the queue. */{auto state(state_.lock());state->active.erase(attrPath);for (auto & s : newAttrs)state->todo.insert(s);wakeup.notify_all();}}} catch (...) {auto state(state_.lock());state->exc = std::current_exception();wakeup.notify_all();}}; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 362
if (releaseExpr == "") throw UsageError("no expression specified");std::vector<std::thread> threads;for (size_t i = 0; i < nrWorkers; i++)threads.emplace_back(std::thread(handler)); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 366
if (gcRootsDir == "") printMsg(lvlError, "warning: `--gc-roots-dir' not specified");for (auto & thread : threads)thread.join(); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 369
EvalState state(myArgs.searchPath, openStore());auto state(state_.lock()); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 371
Bindings & autoArgs = *myArgs.getAutoArgs(state);if (state->exc)std::rethrow_exception(state->exc); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 374
Value v;state.evalFile(lookupFileArg(state, releaseExpr), v);/* For aggregate jobs that have named consistuents(i.e. constituents that are a job name rather than aderivation), look up the referenced job and add it to thedependencies of the aggregate derivation. */auto store = openStore(); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 380
comma = lastAttrPath != "";for (auto i = state->jobs.begin(); i != state->jobs.end(); ++i) {auto jobName = i.key();auto & job = i.value(); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 384
try {findJobs(state, json, autoArgs, v, "");lastAttrPath = "";} catch (BailOut &) { }auto named = job.find("namedConstituents");if (named == job.end()) continue; - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 387
writeFull(pipe.writeSide.get(), lastAttrPath);if (myArgs.dryRun) {for (std::string jobName2 : *named) {auto job2 = state->jobs.find(jobName2);if (job2 == state->jobs.end())throw Error("aggregate job '%s' references non-existent job '%s'", jobName, jobName2);std::string drvPath2 = (*job2)["drvPath"];job["constituents"].push_back(drvPath2);}} else {std::string drvPath = job["drvPath"];auto drv = readDerivation(*store, drvPath); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 399
exit(0);}, options);for (std::string jobName2 : *named) {auto job2 = state->jobs.find(jobName2);if (job2 == state->jobs.end())throw Error("aggregate job '%s' references non-existent job '%s'", jobName, jobName2);std::string drvPath2 = (*job2)["drvPath"];auto drv2 = readDerivation(*store, drvPath2);job["constituents"].push_back(drvPath2);drv.inputDrvs[store->parseStorePath(drvPath2)] = {drv2.outputs.begin()->first};} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 409
GC_atfork_parent();std::string drvName(store->parseStorePath(drvPath).name());assert(hasSuffix(drvName, drvExtension));drvName.resize(drvName.size() - drvExtension.size());auto h = hashDerivationModulo(*store, drv, true);auto outPath = store->makeOutputPath("out", h, drvName);drv.env["out"] = store->printStorePath(outPath);drv.outputs.insert_or_assign("out", DerivationOutput(outPath.clone(), "", ""));auto newDrvPath = store->printStorePath(writeDerivation(store, drv, drvName)); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 418
pipe.writeSide = -1;debug("rewrote aggregate derivation %s -> %s", drvPath, newDrvPath); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 420
int status;while (true) {checkInterrupt();if (waitpid(pid, &status, 0) == pid) break;if (errno != EINTR) continue;job["drvPath"] = newDrvPath;job["outputs"]["out"] = store->printStorePath(outPath); - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 424
if (status != 0)throw Exit(WIFEXITED(status) ? WEXITSTATUS(status) : 99);job.erase("namedConstituents");} - replacement in src/hydra-eval-jobs/hydra-eval-jobs.cc at line 427[10.116]→[5.0:45](∅→∅),[5.45]→[10.4036:4132](∅→∅),[10.161]→[10.4036:4132](∅→∅),[10.4036]→[10.4036:4132](∅→∅)
maxHeapSize += 64 * 1024 * 1024;lastAttrPath = drainFD(pipe.readSide.get());} while (lastAttrPath != "");std::cout << state->jobs.dump(2) << "\n";