[Pkg-puppet-devel] [SCM] Puppet packaging for Debian branch, upstream, updated. 0.25.4-89-gcbbd363

James Turnbull james at lovedthanlost.net
Tue May 18 09:04:01 UTC 2010


The following commit has been merged in the upstream branch:
commit 56b575393bb9db99b25182d7d167a2768b561e6e
Author: Brice Figureau <brice-puppet at daysofwonder.com>
Date:   Sat Mar 20 14:13:31 2010 +0100

    Fix inefficient SimpleGraph#matching_edge
    
    This method has two issues:
     * it is inefficient when there are many events
     * it tries to match edges that shouldn't be matched
    
    With recursive file resources, many change events can be generated.
    The method used to find the good ones is pretty inefficient, allocating
    arrays and/or appending to arrays which is a slow operation that can
    consume lot of memory.
    
    Still with recursife file resources, the current code tries to match the
    events with edges pointing to generated sub-file-resources, which is not
    necessary. In fact this all happens because we masquerade the sub-generated
    resources with the topmost resource whic itself has auto-required links
    to them. There is no reason to send back those events to where they were
    generated.
    
    This patch tries to minimize allocations or array appending, it also collect
    event names (instead of events themselve) while matching since there are
    great chances there are way less events names than events (and we're matchin
    by name).
    
    This patch also makes sure we select only edges that don't point back to
    the event sources.
    
    Results for matching 1100 events:
     * old code: 22s
     * new code:  0.02s
    
    This patch also helps on the memory consumption side since the GC has
    almost no work to perform.
    
    Signed-off-by: Brice Figureau <brice-puppet at daysofwonder.com>

diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
index 5e8f5cd..37a08e7 100644
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@ -64,6 +64,14 @@ class Puppet::SimpleGraph
             end
         end
 
+        def each_out_edges
+            @adjacencies[:out].values.each do |edges|
+                edges.each do |edge|
+                    yield edge
+                end
+            end
+        end
+
         # The other vertex in the edge.
         def other_vertex(direction, edge)
             case direction
@@ -146,20 +154,37 @@ class Puppet::SimpleGraph
     # Collect all of the edges that the passed events match.  Returns
     # an array of edges.
     def matching_edges(events, base = nil)
-        events.collect do |event|
-            source = base || event.source
-
-            unless vertex?(source)
-                Puppet.warning "Got an event from invalid vertex %s" % source.ref
-                next
+        # collect edges out from sources
+        if base
+            # consider only edges which are not pointing to any event sources
+            # which is what a recursive file resources produces
+            event_sources = events.inject({}) { |hash, event| hash[event.source] = event.source ; hash}
+            edges = (adjacent(base, :direction => :out, :type => :edges) - event_sources.keys)
+        else
+            edges = events.inject([]) do |edges,event|
+                if wrapper = @vertices[event.source]
+                    wrapper.each_out_edges do |edge|
+                        edges << edge
+                    end
+                else
+                    Puppet.warning "Got an event from invalid #{event.source.ref}"
+                end
+                edges
             end
-            # Get all of the edges that this vertex should forward events
-            # to, which is the same thing as saying all edges directly below
-            # This vertex in the graph.
-            adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
-                edge.match?(event.name)
+        end
+
+        # find all the different event names, we assume there won't be that many
+        # which should greatly shorten the next loop and reduce the cross-join
+        # between events x out-edges
+        event_names = events.inject({}) { |hash, event| hash[event.name] = event.name ; hash }
+
+        # match all our events to the edges
+        event_names.keys.inject([]) do |matching, event_name|
+            edges.each do |edge|
+                matching << edge if edge.match?(event_name)
             end
-        end.compact.flatten
+            matching
+        end
     end
 
     # Return a reversed version of this graph.
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index e132b72..53b1c51 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -215,15 +215,17 @@ class Transaction
         # Collect the targets of any subscriptions to those events.  We pass
         # the parent resource in so it will override the source in the events,
         # since eval_generated children can't have direct relationships.
-        relationship_graph.matching_edges(events, resource).each do |orig_edge|
-            # We have to dup the label here, else we modify the original edge label,
-            # which affects whether a given event will match on the next run, which is,
-            # of course, bad.
-            edge = orig_edge.class.new(orig_edge.source, orig_edge.target, orig_edge.label)
-            edge.event = events.collect { |e| e.name }
-            set_trigger(edge)
+        Puppet::Util.benchmark(:debug, "Time for triggering #{events.size} events to edges") do
+            b = relationship_graph.matching_edges(events, resource)
+            b.each do |orig_edge|
+                # We have to dup the label here, else we modify the original edge label,
+                # which affects whether a given event will match on the next run, which is,
+                # of course, bad.
+                edge = orig_edge.class.new(orig_edge.source, orig_edge.target, orig_edge.label)
+                edge.event = events.collect { |e| e.name }
+                set_trigger(edge)
+            end
         end
-
         # And return the events for collection
         events
     end
diff --git a/spec/unit/simple_graph.rb b/spec/unit/simple_graph.rb
index 22d6ebe..7919d0c 100755
--- a/spec/unit/simple_graph.rb
+++ b/spec/unit/simple_graph.rb
@@ -372,6 +372,20 @@ describe Puppet::SimpleGraph do
             edges.should be_include(@edges["a/b"])
             edges.should be_include(@edges["a/c"])
         end
+
+        describe "from generated resources" do
+            before :each do
+                @topsource = stub 'source'
+                @edges["a/topsource"] = Puppet::Relationship.new(@topsource, "a", {:event => :yay, :callback => :refresh})
+                @graph.add_edge(@edges["a/topsource"])
+            end
+
+            it "should not match with edges pointing back to events sources" do
+                @edges["a/b"].expects(:match?).never
+                @edges["a/topsource"].expects(:match?)
+                @graph.matching_edges([@event], @topsource)
+            end
+        end
     end
 
     describe "when determining dependencies" do

-- 
Puppet packaging for Debian



More information about the Pkg-puppet-devel mailing list