From c879a20850f2035cd87b1693da26cadf30affe11 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 22 Apr 2016 20:50:06 +0200 Subject: Factor out parallel processing of work items that have dependencies --- src/libutil/thread-pool.hh | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'src/libutil/thread-pool.hh') diff --git a/src/libutil/thread-pool.hh b/src/libutil/thread-pool.hh index 939bcf1ef93b..78b63467d62e 100644 --- a/src/libutil/thread-pool.hh +++ b/src/libutil/thread-pool.hh @@ -6,6 +6,7 @@ #include #include #include +#include namespace nix { @@ -54,4 +55,63 @@ private: void workerEntry(); }; +/* Process in parallel a set of items of type T that have a partial + ordering between them. Thus, any item is only processed after all + its dependencies have been processed. */ +template +void processGraph( + ThreadPool & pool, + const std::set & nodes, + std::function(const T &)> getEdges, + std::function processNode) +{ + struct Graph { + std::set left; + std::map> refs, rrefs; + std::function wrap; + }; + + ref> graph_ = make_ref>(); + + auto wrapWork = [&pool, graph_, processNode](const T & node) { + processNode(node); + + /* Enqueue work for all nodes that were waiting on this one. */ + { + auto graph(graph_->lock()); + graph->left.erase(node); + for (auto & rref : graph->rrefs[node]) { + auto & refs(graph->refs[rref]); + auto i = refs.find(node); + assert(i != refs.end()); + refs.erase(i); + if (refs.empty()) + pool.enqueue(std::bind(graph->wrap, rref)); + } + } + }; + + { + auto graph(graph_->lock()); + graph->left = nodes; + graph->wrap = wrapWork; + } + + /* Build the dependency graph; enqueue all nodes with no + dependencies. */ + for (auto & node : nodes) { + auto refs = getEdges(node); + { + auto graph(graph_->lock()); + for (auto & ref : refs) + if (ref != node && graph->left.count(ref)) { + graph->refs[node].insert(ref); + graph->rrefs[ref].insert(node); + } + if (graph->refs[node].empty()) + pool.enqueue(std::bind(graph->wrap, node)); + } + } +} + } -- cgit 1.4.1