about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-09-14T16·10+0200
committerEelco Dolstra <edolstra@gmail.com>2017-09-14T16·10+0200
commit89dc62c1745950748084a763ea325bc427045e07 (patch)
treeb31517cd86f5da52cb34ce788d4b219a49fc35d7 /src
parent308ecf63611c858327f163a154a3216fd6195ed9 (diff)
RemoteStore: Add option to drop old connections from the pool
This is a hack to make hydra-queue-runner free its temproots
periodically, thereby ensuring that garbage collection of the
corresponding paths is not blocked until the queue runner is
restarted.

It would be better if temproots could be released earlier than at
process exit. I started working on a RAII object returned by functions
like addToStore() that releases temproots. However, this would be a
pretty massive change so I gave up on it for now.
Diffstat (limited to 'src')
-rw-r--r--src/libstore/remote-store.cc16
-rw-r--r--src/libstore/remote-store.hh6
-rw-r--r--src/libutil/pool.hh10
3 files changed, 31 insertions, 1 deletions
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 1af84cff5ba8..b9076c0474d6 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -45,7 +45,13 @@ RemoteStore::RemoteStore(const Params & params)
     , connections(make_ref<Pool<Connection>>(
             std::max(1, (int) maxConnections),
             [this]() { return openConnectionWrapper(); },
-            [](const ref<Connection> & r) { return r->to.good() && r->from.good(); }
+            [this](const ref<Connection> & r) {
+                return
+                    r->to.good()
+                    && r->from.good()
+                    && std::chrono::duration_cast<std::chrono::seconds>(
+                        std::chrono::steady_clock::now() - r->startTime).count() < maxConnectionAge;
+            }
             ))
 {
 }
@@ -106,6 +112,8 @@ ref<RemoteStore::Connection> UDSRemoteStore::openConnection()
     conn->from.fd = conn->fd.get();
     conn->to.fd = conn->fd.get();
 
+    conn->startTime = std::chrono::steady_clock::now();
+
     initConnection(*conn);
 
     return conn;
@@ -619,6 +627,12 @@ void RemoteStore::connect()
 }
 
 
+void RemoteStore::flushBadConnections()
+{
+    connections->flushBad();
+}
+
+
 RemoteStore::Connection::~Connection()
 {
     try {
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index e370e4797d24..30c6beae6ff2 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -25,6 +25,9 @@ public:
     const Setting<int> maxConnections{(Store*) this, 1,
             "max-connections", "maximum number of concurrent connections to the Nix daemon"};
 
+    const Setting<unsigned int> maxConnectionAge{(Store*) this, std::numeric_limits<unsigned int>::max(),
+            "max-connection-age", "number of seconds to reuse a connection"};
+
     RemoteStore(const Params & params);
 
     /* Implementations of abstract store API methods. */
@@ -95,6 +98,8 @@ public:
 
     void connect() override;
 
+    void flushBadConnections();
+
 protected:
 
     struct Connection
@@ -102,6 +107,7 @@ protected:
         FdSink to;
         FdSource from;
         unsigned int daemonVersion;
+        std::chrono::time_point<std::chrono::steady_clock> startTime;
 
         virtual ~Connection();
 
diff --git a/src/libutil/pool.hh b/src/libutil/pool.hh
index 7033090020ef..0b142b0597c7 100644
--- a/src/libutil/pool.hh
+++ b/src/libutil/pool.hh
@@ -168,6 +168,16 @@ public:
     {
         return state.lock()->max;
     }
+
+    void flushBad()
+    {
+        auto state_(state.lock());
+        std::vector<ref<R>> left;
+        for (auto & p : state_->idle)
+            if (validator(p))
+                left.push_back(p);
+        std::swap(state_->idle, left);
+    }
 };
 
 }