diff options
-rw-r--r-- | src/libstore/misc.cc | 32 | ||||
-rw-r--r-- | src/libstore/realisation.cc | 15 | ||||
-rw-r--r-- | src/libutil/closure.hh | 68 | ||||
-rw-r--r-- | tests/unit/libutil/closure.cc | 35 |
4 files changed, 27 insertions, 123 deletions
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index c8646083b..22f6b67ee 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -14,10 +14,9 @@ namespace nix { void Store::computeFSClosure(const StorePathSet & startPaths, StorePathSet & paths_, bool flipDirection, bool includeOutputs, bool includeDerivers) { - std::function<std::set<StorePath>(const StorePath & path, std::future<ref<const ValidPathInfo>> &)> queryDeps; + std::function<std::set<StorePath>(const StorePath & path, ref<const ValidPathInfo>)> queryDeps; if (flipDirection) - queryDeps = [&](const StorePath& path, - std::future<ref<const ValidPathInfo>> & fut) { + queryDeps = [&](const StorePath& path, ref<const ValidPathInfo>) { StorePathSet res; StorePathSet referrers; queryReferrers(path, referrers); @@ -36,10 +35,8 @@ void Store::computeFSClosure(const StorePathSet & startPaths, return res; }; else - queryDeps = [&](const StorePath& path, - std::future<ref<const ValidPathInfo>> & fut) { + queryDeps = [&](const StorePath& path, ref<const ValidPathInfo> info) { StorePathSet res; - auto info = fut.get(); for (auto& ref : info->references) if (ref != path) res.insert(ref); @@ -54,24 +51,11 @@ void Store::computeFSClosure(const StorePathSet & startPaths, return res; }; - computeClosure<StorePath>( - startPaths, paths_, - [&](const StorePath& path, - std::function<void(std::promise<std::set<StorePath>>&)> - processEdges) { - std::promise<std::set<StorePath>> promise; - std::function<void(std::future<ref<const ValidPathInfo>>)> - getDependencies = - [&](std::future<ref<const ValidPathInfo>> fut) { - try { - promise.set_value(queryDeps(path, fut)); - } catch (...) { - promise.set_exception(std::current_exception()); - } - }; - queryPathInfo(path, getDependencies); - processEdges(promise); - }); + paths_.merge(computeClosure<StorePath>( + startPaths, + [&](const StorePath& path) -> std::set<StorePath> { + return queryDeps(path, queryPathInfo(path)); + })); } void Store::computeFSClosure(const StorePath & startPath, diff --git a/src/libstore/realisation.cc b/src/libstore/realisation.cc index 93ddb5b20..50c911da0 100644 --- a/src/libstore/realisation.cc +++ b/src/libstore/realisation.cc @@ -43,20 +43,7 @@ void Realisation::closure(Store & store, const std::set<Realisation> & startOutp return res; }; - computeClosure<Realisation>( - startOutputs, res, - [&](const Realisation& current, - std::function<void(std::promise<std::set<Realisation>>&)> - processEdges) { - std::promise<std::set<Realisation>> promise; - try { - auto res = getDeps(current); - promise.set_value(res); - } catch (...) { - promise.set_exception(std::current_exception()); - } - return processEdges(promise); - }); + res.merge(computeClosure<Realisation>(startOutputs, getDeps)); } nlohmann::json Realisation::toJSON() const { diff --git a/src/libutil/closure.hh b/src/libutil/closure.hh index 16e3b93e4..146931fc8 100644 --- a/src/libutil/closure.hh +++ b/src/libutil/closure.hh @@ -1,72 +1,32 @@ #pragma once ///@file +#include <functional> #include <set> -#include <future> -#include "sync.hh" - -using std::set; namespace nix { template<typename T> -using GetEdgesAsync = std::function<void(const T &, std::function<void(std::promise<set<T>> &)>)>; - -template<typename T> -void computeClosure( - const set<T> startElts, - set<T> & res, - GetEdgesAsync<T> getEdgesAsync +std::set<T> computeClosure( + std::set<T> startElts, + std::function<std::set<T>(const T &)> getEdges ) { - struct State - { - size_t pending; - set<T> & res; - std::exception_ptr exc; - }; - - Sync<State> state_(State{0, res, 0}); + std::set<T> res, queue = std::move(startElts); - std::function<void(const T &)> enqueue; + while (!queue.empty()) { + std::set<T> next; - std::condition_variable done; - - enqueue = [&](const T & current) -> void { - { - auto state(state_.lock()); - if (state->exc) return; - if (!state->res.insert(current).second) return; - state->pending++; + for (auto & e : queue) { + if (res.insert(e).second) { + next.merge(getEdges(e)); + } } - getEdgesAsync(current, [&](std::promise<set<T>> & prom) { - try { - auto children = prom.get_future().get(); - for (auto & child : children) - enqueue(child); - { - auto state(state_.lock()); - assert(state->pending); - if (!--state->pending) done.notify_one(); - } - } catch (...) { - auto state(state_.lock()); - if (!state->exc) state->exc = std::current_exception(); - assert(state->pending); - if (!--state->pending) done.notify_one(); - }; - }); - }; - - for (auto & startElt : startElts) - enqueue(startElt); - - { - auto state(state_.lock()); - while (state->pending) state.wait(done); - if (state->exc) std::rethrow_exception(state->exc); + queue = std::move(next); } + + return res; } } diff --git a/tests/unit/libutil/closure.cc b/tests/unit/libutil/closure.cc index 7597e7807..b4eaad6f9 100644 --- a/tests/unit/libutil/closure.cc +++ b/tests/unit/libutil/closure.cc @@ -16,15 +16,11 @@ map<string, set<string>> testGraph = { }; TEST(closure, correctClosure) { - set<string> aClosure; set<string> expectedClosure = {"A", "B", "C", "F", "G"}; - computeClosure<string>( + set<string> aClosure = computeClosure<string>( {"A"}, - aClosure, - [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { - promise<set<string>> promisedNodes; - promisedNodes.set_value(testGraph[currentNode]); - processEdges(promisedNodes); + [&](const string currentNode) { + return testGraph[currentNode]; } ); @@ -33,12 +29,10 @@ TEST(closure, correctClosure) { TEST(closure, properlyHandlesDirectExceptions) { struct TestExn {}; - set<string> aClosure; EXPECT_THROW( computeClosure<string>( {"A"}, - aClosure, - [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { + [&](const string currentNode) -> set<string> { throw TestExn(); } ), @@ -46,25 +40,4 @@ TEST(closure, properlyHandlesDirectExceptions) { ); } -TEST(closure, properlyHandlesExceptionsInPromise) { - struct TestExn {}; - set<string> aClosure; - EXPECT_THROW( - computeClosure<string>( - {"A"}, - aClosure, - [&](const string currentNode, function<void(promise<set<string>> &)> processEdges) { - promise<set<string>> promise; - try { - throw TestExn(); - } catch (...) { - promise.set_exception(std::current_exception()); - } - processEdges(promise); - } - ), - TestExn - ); -} - } |