From: ara.t.howard@... Date: 2006-08-19T04:11:37+09:00 Subject: Re: Refactoring transactional support within Puppet (long) On Sat, 19 Aug 2006, Luke Kanies wrote: > It's totally unclear what's going on there, and it's not exactly easy to use. > I'd also like to make it simple for people to use transactions if they want, > but I want it to be a good bit simpler: > > report = Puppet.transaction do > sudoers = Puppet::Type.create(:type => :file, :path => "/etc/sudoers") > sudoers.uid = 0 unless sudoers.uid == 0 > end > > That way people could still get the logging and rollback that always come > with transactions, but only if they wanted them and in a way that they can > see what's happening. By the way, the objects often live much longer than > the transactions -- I have a long-running daemon that instantiates the > objects once and applies them all in a new transaction every half hour. > > I think all of these problems (getting rid of '@is' and '@should', > simplifying transactional use, and simplifying use of the objects) can have > a single solution, but I don't know what it is. It could be something like > objects somehow knowing whether they're running under a transaction, but I > don't know how I'd do that without making transactions either a singleton > (which I can't afford, because I know sometimes I'll need subtransactions) > or very complex (e.g., creating a 'transaction' instance variable for every > object, and then nil'ing that variable at the end of the transaction). > > Anyone have any ideas? Any recommendations for what you'd want this library > interface to look like, either using transactions or not? 1) make transactions re-entrant AND singleton 2) make __all__ operations take place in a transaction eg def initialize ... @transaction_mutex = Mutex.new @in_transaction = false ... end def transaction @transaction_mutex.sychronize do if @in_transaction yield else it = @in_transaction begin @in_transaction = true yield ensure @in_transaction = it end end end end alias_method "t", "transaction" ... def foo() t{ @foo = 42 } end def bar() t{ @bar = 42 } end def foobar() t{ foo and bar } end the state may have to global/module-level for this to work, but you get the idea. probably the easiest way is module Transaction # all transaction (global) state and methods end class C include Transaction end etc. 2 cts. -a -- to foster inner awareness, introspection, and reasoning is more efficient than meditation and prayer. - h.h. the 14th dali lama