[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, experimental, updated. debian/2.6.8-1-844-g7ec39d5

Daniel Pittman daniel at rimspace.net
Tue May 10 08:04:24 UTC 2011


The following commit has been merged in the experimental branch:
commit 9584cda2a529cdcf06d766692f5749c775ad7d14
Author: Daniel Pittman <daniel at rimspace.net>
Date:   Mon Jan 24 21:56:18 2011 -0800

    Feature #2597 -- use O(1) methods as often as possible.
    
    This uses a separate hash and array to track the visited path and the seen
    vertex data; while that is less efficient than using a single data structure,
    it avoids on O(n) operation on the stack to determine if we have previously
    visited a vertex.

diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
index 793e598..5833cf7 100644
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@ -113,6 +113,7 @@ class Puppet::SimpleGraph
         s.number          = s.number + 1
 
         s.stack.push(vertex)
+        s.seen[vertex] = true
 
         frame.children = adjacent(vertex)
         frame.step     = :children
@@ -125,28 +126,29 @@ class Puppet::SimpleGraph
             frame.step = :after_recursion
             frame.child = child
             recur.push OpenStruct.new :node => child
-          elsif s.stack.member? child then
-            # Performance note: the stack membership test *should* be done with a
-            # constant time check, but I was lazy and used something that is
-            # likely to be O(N) where N is the stack depth; this will bite us
-            # eventually, and should be improved before the change lands.
-            #
-            # OTOH, this is only invoked on a very cold path, when things have
-            # gone wrong anyhow, right now.  I feel that getting the code out is
-            # worth more than that final performance boost. --daniel 2011-01-22
+          elsif s.seen[child] then
             s.lowlink[vertex] = [s.lowlink[vertex], s.index[child]].min
           end
         else
           if s.lowlink[vertex] == s.index[vertex] then
-            # REVISIT: Surely there must be a nicer way to partition this around an
-            # index, but I don't know what it is.  This works. :/ --daniel 2011-01-22
+            this_scc = []
+            begin
+              top = s.stack.pop
+              s.seen[top] = false
+              this_scc << top
+            end until top == vertex
+            # NOTE: if we don't reverse we get the components in the opposite
+            # order to what a human being would expect; reverse should be an
+            # O(1) operation, without even copying, because we know the length
+            # of the source, but I worry that an implementation will get this
+            # wrong.  Still, the worst case is O(n) for n vertices as we can't
+            # possibly put a vertex into two SCCs.
             #
-            # Performance note: this might also suffer an O(stack depth) performance
-            # hit, better replaced with something that is O(1) for splitting the
-            # stack into parts.
-            tmp = s.stack.slice!(0, s.stack.index(vertex))
-            s.scc.push(s.stack)
-            s.stack = tmp
+            # Also, my feeling is that most implementations are going to do
+            # better with a reverse operation than a string of 'unshift'
+            # insertions at the head of the array; if they were going to mess
+            # up the performance of one, it would be unshift.
+            s.scc << this_scc.reverse
           end
           recur.pop               # done with this node, finally.
         end
@@ -168,7 +170,8 @@ class Puppet::SimpleGraph
   # This has an unhealthy relationship with the 'tarjan' method above, which
   # it uses to implement the detection of strongly connected components.
   def find_cycles_in_graph
-    state = OpenStruct.new :number => 0, :index => {}, :lowlink => {}, :stack => [], :scc => []
+    state = OpenStruct.new :number => 0, :index => {}, :lowlink => {}, :scc => [],
+                           :stack => [], :seen => {}
 
     # we usually have a disconnected graph, must walk all possible roots
     vertices.each do |vertex|
@@ -177,7 +180,8 @@ class Puppet::SimpleGraph
       end
     end
 
-    return state.scc.select { |c| c.length > 1 }
+    result = state.scc.select { |c| c.length > 1 }
+    return result
   end
 
   # Perform a BFS on the sub graph representing the cycle, with a view to

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list