diff options
author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-12-17 22:19:49 +0000 |
---|---|---|
committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-12-17 22:19:49 +0000 |
commit | 10dbb17ed1b2241618f13973d02e17de1dd4e44f (patch) | |
tree | 1619f774897304979ff26cf5dfc5df7eb53bfbb2 | |
parent | b01ffe6fa50e92a4586199096c1f6995ad8dd617 (diff) | |
download | puppet-10dbb17ed1b2241618f13973d02e17de1dd4e44f.tar.gz puppet-10dbb17ed1b2241618f13973d02e17de1dd4e44f.tar.xz puppet-10dbb17ed1b2241618f13973d02e17de1dd4e44f.zip |
Some more graph optimizations; I think I am now close enough that I am basically just going to spend a bit more time making sure the modeling is right in the transactions, and then walk away for now.
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1947 980ebf18-57e1-0310-9a29-db15c13687c0
-rw-r--r-- | lib/puppet/gratr/adjacency_graph.rb | 41 | ||||
-rw-r--r-- | lib/puppet/pgraph.rb | 17 | ||||
-rw-r--r-- | lib/puppet/transaction.rb | 97 | ||||
-rwxr-xr-x | test/other/transactions.rb | 10 |
4 files changed, 114 insertions, 51 deletions
diff --git a/lib/puppet/gratr/adjacency_graph.rb b/lib/puppet/gratr/adjacency_graph.rb index bea50e8c8..a02ed0b2f 100644 --- a/lib/puppet/gratr/adjacency_graph.rb +++ b/lib/puppet/gratr/adjacency_graph.rb @@ -107,18 +107,43 @@ module GRATR # * add_edge!(Edge[source,target], "Label") # * add_edge!(source,target, "Label") def add_edge!(u, v=nil, l=nil, n=nil) - n = u.number if u.class.include? EdgeNumber and n.nil? - u, v, l = u.source, u.target, u.label if u.kind_of? GRATR::Edge - return self if not @allow_loops and u == v - n = (@next_edge_number+=1) unless n if @parallel_edges - add_vertex!(u); add_vertex!(v) + if u.class.include? EdgeNumber and n.nil? + n = u.number + end + if u.kind_of? GRATR::Edge + edge = u + u, v, l = u.source, u.target, u.label + end + if not @allow_loops and u == v + return self + end + if @parallel_edges and ! n + n = (@next_edge_number+=1) + end + add_vertex!(u); + add_vertex!(v) @vertex_dict[u].add(v) - (@edge_number[u] ||= @edgelist_class.new).add(n) if @parallel_edges + + if @parallel_edges + (@edge_number[u] ||= @edgelist_class.new).add(n) + end unless directed? @vertex_dict[v].add(u) - (@edge_number[v] ||= @edgelist_class.new).add(n) if @parallel_edges + if @parallel_edges + (@edge_number[v] ||= @edgelist_class.new).add(n) + end end - self[n ? edge_class[u,v,n] : edge_class[u,v]] = l if l + + if l + unless edge + if n + edge = edge_class[u,v,n] + else + edge = edge_class[u,v] + end + end + self[edge] = l + end self end diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb index 56363f9a9..ce7bc52b8 100644 --- a/lib/puppet/pgraph.rb +++ b/lib/puppet/pgraph.rb @@ -60,8 +60,8 @@ class Puppet::PGraph < GRATR::Digraph # Determine all of the leaf nodes below a given vertex. def leaves(vertex, type = :dfs) tree = tree_from_vertex(vertex, type) - leaves = tree.keys.find_all { |c| adjacent(c, :direction => :out).empty? } - return leaves + l = tree.keys.find_all { |c| adjacent(c, :direction => :out).empty? } + return l end # Collect all of the edges that the passed events match. Returns @@ -100,32 +100,33 @@ class Puppet::PGraph < GRATR::Digraph # to the leaves instead next unless vertex.is_a?(type) - leaves = other.leaves(vertex) - if leaves.empty? + #oleaves = other.leaves(vertex) + oleaves = other.adjacent(vertex, :direction => :out) + if oleaves.empty? remove_vertex!(vertex) next end # First create new edges for each of the :in edges adjacent(vertex, :direction => :in, :type => :edges).each do |edge| - leaves.each do |leaf| + oleaves.each do |leaf| add_edge!(edge.source, leaf, edge.label) if cyclic? raise ArgumentError, "%s => %s results in a loop" % - [up, leaf] + [edge.source, leaf] end end end # Then for each of the out edges adjacent(vertex, :direction => :out, :type => :edges).each do |edge| - leaves.each do |leaf| + oleaves.each do |leaf| add_edge!(leaf, edge.target, edge.label) if cyclic? raise ArgumentError, "%s => %s results in a loop" % - [leaf, down] + [leaf, edge.target] end end end diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index 67d016c15..ff78281ad 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -16,7 +16,10 @@ class Transaction Puppet.config.setdefaults(:transaction, :tags => ["", "Tags to use to find resources. If this is set, then only resources tagged with the specified tags will be applied. - Values must be comma-separated."] + Values must be comma-separated."], + :evaltrace => [false, "Whether each resource should log when it is + being evaluated. This allows you to interactively see exactly + what is being done."] ) # Add some additional times for reporting @@ -47,12 +50,12 @@ class Transaction # If a resource is going to be deleted but it still has dependencies, then # don't delete it unless it's implicit. - if ! resource.implicit? and deps = @relgraph.dependents(resource) and ! deps.empty? and changes.detect { |change| - change.state.name == :ensure and change.should == :absent - } - resource.warning "%s still depend%s on me -- not deleting" % - [deps.collect { |r| r.ref }.join(","), if deps.length > 1; ""; else "s"; end] - return [] + if ! resource.implicit? and deleting?(changes) + if deps = @relgraph.dependents(resource) and ! deps.empty? + resource.warning "%s still depend%s on me -- not deleting" % + [deps.collect { |r| r.ref }.join(","), if deps.length > 1; ""; else "s"; end] + return [] + end end unless changes.is_a? Array @@ -126,42 +129,62 @@ class Transaction end @resources.clear end - + + # Copy an important relationships from the parent to the newly-generated + # child resource. + def copy_relationships(resource, children) + depthfirst = resource.depthfirst? + + # We only have to worry about dependents, because any dependencies + # already missed their chance to register an event for us. + dependents = @relgraph.adjacent(resource, + :direction => :out, :type => :edges).reject { |e| ! e.callback } + + #sources = @relgraph.adjacent(resource, + # :direction => :in, :type => :edges).reject { |e| ! e.callback } + + children.each do |gen_child| + if depthfirst + @relgraph.add_edge!(gen_child, resource) + else + @relgraph.add_edge!(resource, gen_child) + end + dependents.each do |edge| + @relgraph.add_edge!(gen_child, edge.target, edge.label) + end + #sources.each do |edge| + # @relgraph.add_edge!(edge.source, gen_child, edge.label) + #end + end + end + + # Are we deleting this resource? + def deleting?(changes) + changes.detect { |change| + change.state.name == :ensure and change.should == :absent + } + end + # See if the resource generates new resources at evaluation time. def eval_generate(resource) if resource.respond_to?(:eval_generate) if children = resource.eval_generate - depthfirst = resource.depthfirst? - dependents = @relgraph.adjacent(resource, :direction => :out, :type => :edges) - targets = @relgraph.adjacent(resource, :direction => :in, :type => :edges) - children.each do |gen_child| - if depthfirst - @relgraph.add_edge!(gen_child, resource) - else - @relgraph.add_edge!(resource, gen_child) - end - dependents.each do |edge| - @relgraph.add_edge!(gen_child, edge.target, edge.label) - end - targets.each do |edge| - @relgraph.add_edge!(edge.source, gen_child, edge.label) - end - @generated << gen_child - end + copy_relationships(resource, children) + @generated += children return children end end end # Evaluate a single resource. - def eval_resource(resource) + def eval_resource(resource, checkskip = true) events = [] if resource.is_a?(Puppet::Type::Component) raise Puppet::DevError, "Got a component to evaluate" end - if skip?(resource) + if checkskip and skip?(resource) @resourcemetrics[:skipped] += 1 else @resourcemetrics[:scheduled] += 1 @@ -172,7 +195,8 @@ class Transaction if resource.depthfirst? and children children.each do |child| - events += eval_resource(child) + # The child will never be skipped when the parent isn't + events += eval_resource(child, false) end end @@ -180,7 +204,7 @@ class Transaction seconds = thinmark do events += apply(resource) end - + if ! resource.depthfirst? and children children.each do |child| events += eval_resource(child) @@ -218,13 +242,23 @@ class Transaction begin allevents = @sorted_resources.collect { |resource| - eval_resource(resource) + ret = nil + seconds = thinmark do + ret = eval_resource(resource) + end + + if Puppet[:evaltrace] + resource.info "Evaluated in %0.2f seconds" % seconds + end + ret }.flatten.reject { |e| e.nil? } ensure # And then close the transaction log. Puppet::Log.close(@report) end + @relgraph.to_jpg(File.expand_path("~/tmp/graphs"), "simple_relgraph") + Puppet.debug "Finishing transaction %s with %s changes" % [self.object_id, @count] @@ -247,7 +281,8 @@ class Transaction # enough to check the immediate dependencies, which is why we use # a tree from the reversed graph. skip = false - @relgraph.dependencies(resource).each do |dep| + deps = @relgraph.dependencies(resource) + deps.each do |dep| if fails = failed?(dep) resource.notice "Dependency %s[%s] has %s failures" % [dep.class.name, dep.name, @failures[dep]] diff --git a/test/other/transactions.rb b/test/other/transactions.rb index d9a173986..2ae4b1b13 100755 --- a/test/other/transactions.rb +++ b/test/other/transactions.rb @@ -677,10 +677,12 @@ class TestTransactions < Test::Unit::TestCase assert(trans.relgraph.vertex?(ra), "Did not add ra to rel_graph" % name) - # Now make sure this generated resource has the same relationships as the generating - # resource - assert(trans.relgraph.edge?(yay, ra), - "yay is not required by ra") + # Now make sure this generated resource has the same relationships as + # the generating resource + #assert(trans.relgraph.edge?(yay, ra), + # "yay is not required by ra") + assert(trans.relgraph.edge?(ya, rah), + "rah is not subscribed to ya") assert(trans.relgraph.edge?(ya, ra), "ra is not subscribed to ya") |