summaryrefslogtreecommitdiffstats
path: root/lib/puppet/transaction.rb
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2005-06-27 21:44:46 +0000
committerLuke Kanies <luke@madstop.com>2005-06-27 21:44:46 +0000
commit8f95084cd854aef4e3493854e58cefd352cdc68d (patch)
treef31288d1cbbd60c0fdc7c04bbd6960516a6893be /lib/puppet/transaction.rb
parent6f074138779e558fd7017880f606dcf3527233f9 (diff)
downloadpuppet-8f95084cd854aef4e3493854e58cefd352cdc68d.tar.gz
puppet-8f95084cd854aef4e3493854e58cefd352cdc68d.tar.xz
puppet-8f95084cd854aef4e3493854e58cefd352cdc68d.zip
renaming blink to puppet
git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@302 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'lib/puppet/transaction.rb')
-rw-r--r--lib/puppet/transaction.rb162
1 files changed, 162 insertions, 0 deletions
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
new file mode 100644
index 000000000..87b2f950c
--- /dev/null
+++ b/lib/puppet/transaction.rb
@@ -0,0 +1,162 @@
+#!/usr/local/bin/ruby -w
+
+# $Id$
+
+# the class that actually walks our object/state tree, collects the changes,
+# and performs them
+
+# there are two directions of walking:
+# - first we recurse down the tree and collect changes
+# - then we walk back up the tree through 'refresh' after the changes
+
+require 'blink'
+require 'blink/statechange'
+
+#---------------------------------------------------------------
+module Blink
+class Transaction
+ attr_accessor :toplevel, :component
+
+ #---------------------------------------------------------------
+ # a bit of a gross hack; a global list of objects that have failed to sync,
+ # so that we can verify during later syncs that our dependencies haven't
+ # failed
+ def Transaction.init
+ @@failures = Hash.new(0)
+ @@changed = []
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # for now, just store the changes for executing linearly
+ # later, we might execute them as we receive them
+ def change(change)
+ @changes.push change
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # i don't need to worry about ordering, because it's not possible to specify
+ # an object as a dependency unless it's already been mentioned within the language
+ # thus, an object gets defined, then mentioned as a dependency, and the objects
+ # are synced in that order automatically
+ def evaluate
+ Blink.notice "executing %s changes or transactions" % @changes.length
+
+ return @changes.collect { |change|
+ if change.is_a?(Blink::StateChange)
+ change.transaction = self
+ events = nil
+ begin
+ events = [change.forward].flatten
+ #@@changed.push change.state.parent
+ rescue => detail
+ Blink.error("%s failed: %s" % [change,detail])
+ raise
+ # at this point, we would normally do error handling
+ # but i haven't decided what to do for that yet
+ # so just record that a sync failed for a given object
+ #@@failures[change.state.parent] += 1
+ # this still could get hairy; what if file contents changed,
+ # but a chmod failed? how would i handle that error? dern
+ end
+
+ if events.nil?
+ Blink.verbose "No events returned?"
+ else
+ # first handle the subscriptions on individual objects
+ events.each { |event|
+ change.state.parent.subscribers?(event).each { |sub|
+ sub.trigger(self)
+ }
+ }
+ end
+ events
+ elsif change.is_a?(Blink::Transaction)
+ change.evaluate
+ else
+ raise "Transactions cannot handle objects of type %s" % child.class
+ end
+ }.flatten.reject { |event|
+ event.nil?
+ }.each { |event|
+ # this handles subscriptions on the components, rather than
+ # on idividual objects
+ self.component.subscribers?(event).each { |sub|
+ sub.trigger(self)
+ }
+ }
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ # this should only be called by a Blink::Container object now
+ # and it should only receive an array
+ def initialize(tree)
+ @tree = tree
+ @toplevel = false
+
+ @triggered = Hash.new(0)
+
+ # of course, this won't work on the second run
+ unless defined? @@failures
+ @toplevel = true
+ self.class.init
+ end
+ # change collection is in-band, and message generation is out-of-band
+ # of course, exception raising is also out-of-band
+ @changes = @tree.collect { |child|
+ # these children are all Blink::Type instances
+ # not all of the children will return a change, and Containers
+ # return transactions
+ child.evaluate
+ }.flatten.reject { |child|
+ child.nil? # remove empties
+ }
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ def rollback
+ @changes.each { |change|
+ if change.is_a?(Blink::StateChange)
+ next unless change.run
+ #change.transaction = self
+ begin
+ change.backward
+ #@@changed.push change.state.parent
+ rescue => detail
+ Blink.error("%s rollback failed: %s" % [change,detail])
+ # at this point, we would normally do error handling
+ # but i haven't decided what to do for that yet
+ # so just record that a sync failed for a given object
+ #@@failures[change.state.parent] += 1
+ # this still could get hairy; what if file contents changed,
+ # but a chmod failed? how would i handle that error? dern
+ end
+ elsif change.is_a?(Blink::Transaction)
+ # yay, recursion
+ change.rollback
+ else
+ raise "Transactions cannot handle objects of type %s" % child.class
+ end
+ }
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ def triggercount(sub)
+ Blink.notice "Triggercount on %s is %s" % [sub,@triggered[sub]]
+ return @triggered[sub]
+ end
+ #---------------------------------------------------------------
+
+ #---------------------------------------------------------------
+ def triggered(sub)
+ @triggered[sub] += 1
+ Blink.notice "%s was triggered; count is %s" % [sub,@triggered[sub]]
+ end
+ #---------------------------------------------------------------
+end
+end
+#---------------------------------------------------------------