about summary refs log tree commit diff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/build.cc46
-rw-r--r--src/libstore/derivations.cc7
-rw-r--r--src/libstore/derivations.hh2
-rw-r--r--src/libstore/download.cc11
-rw-r--r--src/libstore/download.hh3
-rw-r--r--src/libstore/http-binary-cache-store.cc3
-rw-r--r--src/libstore/local-store.cc2
7 files changed, 45 insertions, 29 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index cfab0b0dc32c..e0eb702a4f82 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -193,6 +193,7 @@ bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) {
 struct Child
 {
     WeakGoalPtr goal;
+    Goal * goal2; // ugly hackery
     set<int> fds;
     bool respectTimeouts;
     bool inBuildSlot;
@@ -284,7 +285,7 @@ public:
        false if there is no sense in waking up goals that are sleeping
        because they can't run yet (e.g., there is no free build slot,
        or the hook would still say `postpone'). */
-    void childTerminated(GoalPtr goal, bool wakeSleepers = true);
+    void childTerminated(Goal * goal, bool wakeSleepers = true);
 
     /* Put `goal' to sleep until a build slot becomes available (which
        might be right away). */
@@ -652,18 +653,15 @@ HookInstance::~HookInstance()
 //////////////////////////////////////////////////////////////////////
 
 
-typedef map<string, string> HashRewrites;
+typedef map<std::string, std::string> StringRewrites;
 
 
-string rewriteHashes(string s, const HashRewrites & rewrites)
+std::string rewriteStrings(std::string s, const StringRewrites & rewrites)
 {
     for (auto & i : rewrites) {
-        assert(i.first.size() == i.second.size());
         size_t j = 0;
-        while ((j = s.find(i.first, j)) != string::npos) {
-            debug(format("rewriting @ %1%") % j);
-            s.replace(j, i.second.size(), i.second);
-        }
+        while ((j = s.find(i.first, j)) != string::npos)
+            s.replace(j, i.first.size(), i.second);
     }
     return s;
 }
@@ -782,7 +780,7 @@ private:
 #endif
 
     /* Hash rewriting. */
-    HashRewrites rewritesToTmp, rewritesFromTmp;
+    StringRewrites inputRewrites, outputRewrites;
     typedef map<Path, Path> RedirectedOutputs;
     RedirectedOutputs redirectedOutputs;
 
@@ -938,7 +936,7 @@ DerivationGoal::~DerivationGoal()
 void DerivationGoal::killChild()
 {
     if (pid != -1) {
-        worker.childTerminated(shared_from_this());
+        worker.childTerminated(this);
 
         if (buildUser.enabled()) {
             /* If we're using a build user, then there is a tricky
@@ -1412,7 +1410,7 @@ void DerivationGoal::buildDone()
     debug(format("builder process for ‘%1%’ finished") % drvPath);
 
     /* So the child is gone now. */
-    worker.childTerminated(shared_from_this());
+    worker.childTerminated(this);
 
     /* Close the read side of the logger pipe. */
     if (hook) {
@@ -1774,6 +1772,10 @@ void DerivationGoal::startBuilder()
         for (auto & i : varNames) env[i] = getEnv(i);
     }
 
+    /* Substitute output placeholders with the actual output paths. */
+    for (auto & output : drv->outputs)
+        inputRewrites[hashPlaceholder(output.first)] = output.second.path;
+
     /* The `exportReferencesGraph' feature allows the references graph
        to be passed to a builder.  This attribute should be a list of
        pairs [name1 path1 name2 path2 ...].  The references graph of
@@ -2418,7 +2420,7 @@ void DerivationGoal::runChild()
         /* Fill in the environment. */
         Strings envStrs;
         for (auto & i : env)
-            envStrs.push_back(rewriteHashes(i.first + "=" + i.second, rewritesToTmp));
+            envStrs.push_back(rewriteStrings(i.first + "=" + i.second, inputRewrites));
 
         /* If we are running in `build-users' mode, then switch to the
            user we allocated above.  Make sure that we drop all root
@@ -2560,7 +2562,7 @@ void DerivationGoal::runChild()
         }
 
         for (auto & i : drv->args)
-            args.push_back(rewriteHashes(i, rewritesToTmp));
+            args.push_back(rewriteStrings(i, inputRewrites));
 
         restoreSIGPIPE();
 
@@ -2682,7 +2684,7 @@ void DerivationGoal::registerOutputs()
 
         /* Apply hash rewriting if necessary. */
         bool rewritten = false;
-        if (!rewritesFromTmp.empty()) {
+        if (!outputRewrites.empty()) {
             printMsg(lvlError, format("warning: rewriting hashes in ‘%1%’; cross fingers") % path);
 
             /* Canonicalise first.  This ensures that the path we're
@@ -2694,7 +2696,7 @@ void DerivationGoal::registerOutputs()
             StringSink sink;
             dumpPath(actualPath, sink);
             deletePath(actualPath);
-            sink.s = make_ref<std::string>(rewriteHashes(*sink.s, rewritesFromTmp));
+            sink.s = make_ref<std::string>(rewriteStrings(*sink.s, outputRewrites));
             StringSource source(*sink.s);
             restorePath(actualPath, source);
 
@@ -3033,8 +3035,8 @@ Path DerivationGoal::addHashRewrite(const Path & path)
     Path p = worker.store.storeDir + "/" + h2 + string(path, worker.store.storeDir.size() + 33);
     deletePath(p);
     assert(path.size() == p.size());
-    rewritesToTmp[h1] = h2;
-    rewritesFromTmp[h2] = h1;
+    inputRewrites[h1] = h2;
+    outputRewrites[h2] = h1;
     redirectedOutputs[path] = p;
     return p;
 }
@@ -3140,8 +3142,9 @@ SubstitutionGoal::~SubstitutionGoal()
 {
     try {
         if (thr.joinable()) {
+            // FIXME: signal worker thread to quit.
             thr.join();
-            //worker.childTerminated(shared_from_this()); // FIXME
+            worker.childTerminated(this);
         }
     } catch (...) {
         ignoreException();
@@ -3296,7 +3299,7 @@ void SubstitutionGoal::finished()
     trace("substitute finished");
 
     thr.join();
-    worker.childTerminated(shared_from_this());
+    worker.childTerminated(this);
 
     try {
         promise.get_future().get();
@@ -3449,6 +3452,7 @@ void Worker::childStarted(GoalPtr goal, const set<int> & fds,
 {
     Child child;
     child.goal = goal;
+    child.goal2 = goal.get();
     child.fds = fds;
     child.timeStarted = child.lastOutput = time(0);
     child.inBuildSlot = inBuildSlot;
@@ -3458,10 +3462,10 @@ void Worker::childStarted(GoalPtr goal, const set<int> & fds,
 }
 
 
-void Worker::childTerminated(GoalPtr goal, bool wakeSleepers)
+void Worker::childTerminated(Goal * goal, bool wakeSleepers)
 {
     auto i = std::find_if(children.begin(), children.end(),
-        [&](const Child & child) { return child.goal.lock() == goal; });
+        [&](const Child & child) { return child.goal2 == goal; });
     assert(i != children.end());
 
     if (i->inBuildSlot) {
diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc
index 7dcf71d468df..f051f10bd018 100644
--- a/src/libstore/derivations.cc
+++ b/src/libstore/derivations.cc
@@ -390,4 +390,11 @@ Sink & operator << (Sink & out, const BasicDerivation & drv)
 }
 
 
+std::string hashPlaceholder(const std::string & outputName)
+{
+    // FIXME: memoize?
+    return "/" + printHash32(hashString(htSHA256, "nix-output:" + outputName));
+}
+
+
 }
diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh
index 974de78c58d5..9717a81e469c 100644
--- a/src/libstore/derivations.hh
+++ b/src/libstore/derivations.hh
@@ -117,4 +117,6 @@ struct Sink;
 Source & readDerivation(Source & in, Store & store, BasicDerivation & drv);
 Sink & operator << (Sink & out, const BasicDerivation & drv);
 
+std::string hashPlaceholder(const std::string & outputName);
+
 }
diff --git a/src/libstore/download.cc b/src/libstore/download.cc
index 95c7d2255afc..5305a48950c4 100644
--- a/src/libstore/download.cc
+++ b/src/libstore/download.cc
@@ -230,7 +230,7 @@ struct CurlDownloader : public Downloader
             } catch (DownloadError & e) {
                 attempt++;
                 if (e.error != Transient || attempt >= options.tries) throw;
-                auto ms = 25 * (1 << (attempt - 1));
+                auto ms = options.baseRetryTimeMs * (1 << (attempt - 1));
                 printMsg(lvlError, format("warning: %s; retrying in %d ms") % e.what() % ms);
                 std::this_thread::sleep_for(std::chrono::milliseconds(ms));
             }
@@ -243,13 +243,14 @@ ref<Downloader> makeDownloader()
     return make_ref<CurlDownloader>();
 }
 
-Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, const Hash & expectedHash)
+Path Downloader::downloadCached(ref<Store> store, const string & url_, bool unpack, string name, const Hash & expectedHash)
 {
     auto url = resolveUri(url_);
 
-    string name;
-    auto p = url.rfind('/');
-    if (p != string::npos) name = string(url, p + 1);
+    if (name == "") {
+        auto p = url.rfind('/');
+        if (p != string::npos) name = string(url, p + 1);
+    }
 
     Path expectedStorePath;
     if (expectedHash) {
diff --git a/src/libstore/download.hh b/src/libstore/download.hh
index 1f6098759a2d..f22e688645b0 100644
--- a/src/libstore/download.hh
+++ b/src/libstore/download.hh
@@ -14,6 +14,7 @@ struct DownloadOptions
     enum { yes, no, automatic } showProgress = yes;
     bool head = false;
     size_t tries = 1;
+    unsigned int baseRetryTimeMs = 100;
 };
 
 struct DownloadResult
@@ -29,7 +30,7 @@ struct Downloader
 {
     virtual DownloadResult download(string url, const DownloadOptions & options) = 0;
 
-    Path downloadCached(ref<Store> store, const string & url, bool unpack,
+    Path downloadCached(ref<Store> store, const string & url, bool unpack, string name = "",
         const Hash & expectedHash = Hash());
 
     enum Error { NotFound, Forbidden, Misc, Transient };
diff --git a/src/libstore/http-binary-cache-store.cc b/src/libstore/http-binary-cache-store.cc
index 42e9099b8e20..bdcd2fd3998b 100644
--- a/src/libstore/http-binary-cache-store.cc
+++ b/src/libstore/http-binary-cache-store.cc
@@ -80,7 +80,8 @@ protected:
         auto downloader(downloaders.get());
         DownloadOptions options;
         options.showProgress = DownloadOptions::no;
-        options.tries = 3;
+        options.tries = 5;
+        options.baseRetryTimeMs = 1000;
         try {
             return downloader->download(cacheUri + "/" + path, options).data;
         } catch (DownloadError & e) {
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index d3f0c4787e17..10056f2f1fd8 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -760,7 +760,7 @@ Path LocalStore::queryPathFromHashPart(const string & hashPart)
 
     Path prefix = storeDir + "/" + hashPart;
 
-    return retrySQLite<Path>([&]() {
+    return retrySQLite<Path>([&]() -> std::string {
         auto state(_state.lock());
 
         auto useQueryPathFromHashPart(state->stmtQueryPathFromHashPart.use()(prefix));