From 500c27e4d5304528f1479bc9da552d2692cb4dc3 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 3 Mar 2017 12:37:27 +0100 Subject: [PATCH] Add hydra.conf option "nar_buffer_size" to configure memoryTokens limit It defaults to half the physical RAM. --- src/hydra-queue-runner/hydra-queue-runner.cc | 88 +++++++++++++------- src/hydra-queue-runner/state.hh | 9 +- src/hydra-queue-runner/token-server.hh | 5 ++ 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/hydra-queue-runner/hydra-queue-runner.cc b/src/hydra-queue-runner/hydra-queue-runner.cc index 5dc840dd..945de98d 100644 --- a/src/hydra-queue-runner/hydra-queue-runner.cc +++ b/src/hydra-queue-runner/hydra-queue-runner.cc @@ -17,46 +17,79 @@ using namespace nix; -State::State() - : memoryTokens(12ULL << 30) // FIXME: make this configurable +struct Config { - hydraData = getEnv("HYDRA_DATA"); - if (hydraData == "") throw Error("$HYDRA_DATA must be set"); + std::map options; - /* Read hydra.conf. */ - auto hydraConfigFile = getEnv("HYDRA_CONFIG"); - if (pathExists(hydraConfigFile)) { + Config() + { + /* Read hydra.conf. */ + auto hydraConfigFile = getEnv("HYDRA_CONFIG"); + if (pathExists(hydraConfigFile)) { - for (auto line : tokenizeString(readFile(hydraConfigFile), "\n")) { - line = trim(string(line, 0, line.find('#'))); + for (auto line : tokenizeString(readFile(hydraConfigFile), "\n")) { + line = trim(string(line, 0, line.find('#'))); - auto eq = line.find('='); - if (eq == std::string::npos) continue; + auto eq = line.find('='); + if (eq == std::string::npos) continue; - auto key = trim(std::string(line, 0, eq)); - auto value = trim(std::string(line, eq + 1)); + auto key = trim(std::string(line, 0, eq)); + auto value = trim(std::string(line, eq + 1)); - if (key == "") continue; + if (key == "") continue; - hydraConfig[key] = value; + options[key] = value; + } } } + std::string getStrOption(const std::string & key, const std::string & def = "") { - std::string s = hydraConfig["max_output_size"]; - if (s != "") string2Int(s, maxOutputSize); + auto i = options.find(key); + return i == options.end() ? def : i->second; } + uint64_t getIntOption(const std::string & key, uint64_t def = 0) + { + auto i = options.find(key); + return i == options.end() ? def : std::stoi(i->second); + } + + bool getBoolOption(const std::string & key, bool def = false) + { + auto i = options.find(key); + return i == options.end() ? def : i->second == "true"; + } +}; + + +static uint64_t getMemSize() +{ + auto pages = sysconf(_SC_PHYS_PAGES); + return pages >= 0 ? pages * sysconf(_SC_PAGESIZE) : 4ULL << 30; +} + + +State::State() + : config(std::make_unique()) + , memoryTokens(config->getIntOption("nar_buffer_size", getMemSize() / 2)) + , maxOutputSize(config->getIntOption("max_output_size", 2ULL << 30)) +{ + printInfo("using %d bytes for the NAR buffer", memoryTokens.capacity()); + + hydraData = getEnv("HYDRA_DATA"); + if (hydraData == "") throw Error("$HYDRA_DATA must be set"); + logDir = canonPath(hydraData + "/build-logs"); /* handle deprecated store specification */ - if (hydraConfig["store_mode"] != "") + if (config->getStrOption("store_mode") != "") throw Error("store_mode in hydra.conf is deprecated, please use store_uri"); - if (hydraConfig["binary_cache_dir"] != "") + if (config->getStrOption("binary_cache_dir") != "") printMsg(lvlError, "hydra.conf: binary_cache_dir is deprecated and ignored. use store_uri=file:// instead"); - if (hydraConfig["binary_cache_s3_bucket"] != "") + if (config->getStrOption("binary_cache_s3_bucket") != "") printMsg(lvlError, "hydra.conf: binary_cache_s3_bucket is deprecated and ignored. use store_uri=s3:// instead"); - if (hydraConfig["binary_cache_secret_key_file"] != "") + if (config->getStrOption("binary_cache_secret_key_file") != "") printMsg(lvlError, "hydra.conf: binary_cache_secret_key_file is deprecated and ignored. use store_uri=...?secret-key= instead"); } @@ -800,18 +833,13 @@ void State::run(BuildID buildOne) localStore = openStore(); - _destStore = hydraConfig["store_uri"] == "" - ? localStore - : openStore(hydraConfig["store_uri"]); + auto storeUri = config->getStrOption("store_uri"); + _destStore = storeUri == "" ? localStore : openStore(storeUri); - auto isTrue = [](const std::string & s) { - return s == "1" || s == "true"; - }; - - useSubstitutes = isTrue(hydraConfig["use-substitutes"]); + useSubstitutes = config->getBoolOption("use-substitutes", false); // FIXME: hacky mechanism for configuring determinism checks. - for (auto & s : tokenizeString(hydraConfig["xxx-jobset-repeats"])) { + for (auto & s : tokenizeString(config->getStrOption("xxx-jobset-repeats"))) { auto s2 = tokenizeString>(s, ":"); if (s2.size() != 3) throw Error("bad value in xxx-jobset-repeats"); jobsetRepeats.emplace(std::make_pair(s2[0], s2[1]), std::stoi(s2[2])); diff --git a/src/hydra-queue-runner/state.hh b/src/hydra-queue-runner/state.hh index 4c23471b..d4cbbb5c 100644 --- a/src/hydra-queue-runner/state.hh +++ b/src/hydra-queue-runner/state.hh @@ -250,10 +250,15 @@ struct Machine }; +class Config; + + class State { private: + std::unique_ptr config; + // FIXME: Make configurable. const unsigned int maxTries = 5; const unsigned int retryInterval = 60; // seconds @@ -262,8 +267,6 @@ private: nix::Path hydraData, logDir; - std::map hydraConfig; - bool useSubstitutes = false; /* The queued builds. */ @@ -407,7 +410,7 @@ private: tokens are available. */ nix::TokenServer memoryTokens; - size_t maxOutputSize = 2ULL << 30; + size_t maxOutputSize; time_t lastStatusLogged = 0; const int statusLogInterval = 300; diff --git a/src/hydra-queue-runner/token-server.hh b/src/hydra-queue-runner/token-server.hh index 7c6310ef..e00004d0 100644 --- a/src/hydra-queue-runner/token-server.hh +++ b/src/hydra-queue-runner/token-server.hh @@ -99,6 +99,11 @@ public: auto inUse_(inUse.lock()); return *inUse_; } + + size_t capacity() + { + return maxTokens; + } }; }