summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-11-24 16:48:04 +0100
committerLudovic Courtès <ludo@gnu.org>2015-05-11 17:42:53 +0200
commit5241aec531e9c9a4b2dd5e5b6ee3f07ff049d9a5 (patch)
treefcd2cce0b3ecb71ad07b3806b0062cb30227270f
parent9f355738e106f4ca49bba7276e8d520a2fc2955d (diff)
downloadguix-5241aec531e9c9a4b2dd5e5b6ee3f07ff049d9a5.tar.gz
Build derivations in a more predictable order
Derivations are now built in order of derivation name, so a package
named "aardvark" is built before "baboon".

Fixes #399.
-rw-r--r--nix/libstore/build.cc48
1 files changed, 41 insertions, 7 deletions
diff --git a/nix/libstore/build.cc b/nix/libstore/build.cc
index 952dbd2325..009fcb2c0c 100644
--- a/nix/libstore/build.cc
+++ b/nix/libstore/build.cc
@@ -84,8 +84,12 @@ class Goal;
 typedef std::shared_ptr<Goal> GoalPtr;
 typedef std::weak_ptr<Goal> WeakGoalPtr;
 
+struct CompareGoalPtrs {
+    bool operator() (const GoalPtr & a, const GoalPtr & b);
+};
+
 /* Set of goals. */
-typedef set<GoalPtr> Goals;
+typedef set<GoalPtr, CompareGoalPtrs> Goals;
 typedef list<WeakGoalPtr> WeakGoals;
 
 /* A map of paths to goals (and the other way around). */
@@ -172,11 +176,20 @@ public:
        (important!), etc. */
     virtual void cancel(bool timeout) = 0;
 
+    virtual string key() = 0;
+
 protected:
     void amDone(ExitCode result);
 };
 
 
+bool CompareGoalPtrs::operator() (const GoalPtr & a, const GoalPtr & b) {
+    string s1 = a->key();
+    string s2 = b->key();
+    return s1 < s2;
+}
+
+
 /* A mapping used to remember for each child process to what goal it
    belongs, and file descriptors for receiving log data and output
    path creation commands. */
@@ -303,6 +316,7 @@ public:
 void addToWeakGoals(WeakGoals & goals, GoalPtr p)
 {
     // FIXME: necessary?
+    // FIXME: O(n)
     foreach (WeakGoals::iterator, i, goals)
         if (i->lock() == p) return;
     goals.push_back(p);
@@ -779,6 +793,15 @@ public:
 
     void cancel(bool timeout);
 
+    string key()
+    {
+        /* Ensure that derivations get built in order of their name,
+           i.e. a derivation named "aardvark" always comes before
+           "baboon". And substitution goals always happen before
+           derivation goals (due to "b$"). */
+        return "b$" + storePathToName(drvPath) + "$" + drvPath;
+    }
+
     void work();
 
     Path getDrvPath()
@@ -2614,6 +2637,13 @@ public:
 
     void cancel(bool timeout);
 
+    string key()
+    {
+        /* "a$" ensures substitution goals happen before derivation
+           goals. */
+        return "a$" + storePathToName(storePath) + "$" + storePath;
+    }
+
     void work();
 
     /* The states. */
@@ -3124,15 +3154,19 @@ void Worker::run(const Goals & _topGoals)
 
         checkInterrupt();
 
-        /* Call every wake goal. */
+        /* Call every wake goal (in the ordering established by
+           CompareGoalPtrs). */
         while (!awake.empty() && !topGoals.empty()) {
-            WeakGoals awake2(awake);
+            Goals awake2;
+            for (auto & i : awake) {
+                GoalPtr goal = i.lock();
+                if (goal) awake2.insert(goal);
+            }
             awake.clear();
-            foreach (WeakGoals::iterator, i, awake2) {
+            for (auto & goal : awake2) {
                 checkInterrupt();
-                GoalPtr goal = i->lock();
-                if (goal) goal->work();
-                if (topGoals.empty()) break;
+                goal->work();
+                if (topGoals.empty()) break; // stuff may have been cancelled
             }
         }