From: Austin Ziegler Date: 2004-11-04T22:37:49+09:00 Subject: Re: [ANN] Transaction::Simple 1.2.0 On Thu, 4 Nov 2004 12:48:14 +0100, Michael Neumann wrote: > On Thu, Nov 04, 2004 at 12:13:20PM +0900, Austin Ziegler wrote: > > Contraindications > > ----------------- > > While Transaction::Simple is very useful, it has some severe limitations that > > must be understood. Transaction::Simple: > > > > * uses Marshal. Thus, any object which cannot be Marshal-ed cannot use > > Transaction::Simple. > > * does not manage resources. Resources external to the object and its instance > > variables are not managed at all. However, all instance variables and > > objects "belonging" to those instance variables are managed. If there are > > object reference counts to be handled, Transaction::Simple will probably > > cause problems. > > * is not thread-safe. In the ACID ("atomic, consistent, isolated, durable") > > test, Transaction::Simple provides C and D, but it is up to the user of > > Transaction::Simple to provide isolation. Transactions should be considered > > "critical sections" in multi-threaded applications. Thread safety can be > > ensured with Transaction::Simple::ThreadSafe. > > * does not maintain Object#__id__ values on rewind or abort. This may change > > for future versions that will be Ruby 1.8 or better only. > Hm, I've written a similar library for Wee, which saves snapshots of > objects, and is able to restore the old object from a snapshot. It does > not use Marshal, and maintains __id__ values correctly. > Snapshots are, what you call "transactions". Taking a quick look at your library, it looks like it does much the same as mine, except it uses an external object for transaction management and, obviously, doesn't use Marshal. There are several reasons that I implemented it this way, the most important being your implementation of Array#take_snapshot: it dups the array: irb#1(main):001:0> arr = %w(a b c d) => ["a", "b", "c", "d"] irb#1(main):002:0> arr2 = arr.dup => ["a", "b", "c", "d"] irb#1(main):003:0> arr2[0] << "z" => "az" irb#1(main):004:0> arr => ["az", "b", "c", "d"] irb#1(main):005:0> Transaction::Simple is a "deep" transaction: it applies the transaction to the object and all objects owned by the object. Transaction::Simple was developed initially for PDF::Writer (and generalised from there) because I needed to be able to have deep transactions for PDF document pages, which might have to be reverted to an initial state and reapplied in a different manner because we reached the end of the page before we should have (e.g., paragraph wrapping, although I think it's mostly used for table handling). The StateRegistry only takes a shallow copy of the object references, leading to a situation where I can revert to a snapshot but not have objects referring to values as they were at the time of the snapshot. Unfortunately, it's been so long since I wrote the paragraph above that I don't recall what technique I was going to use to restore the values of the object without destroying __id__. I do know that I detect whether an object responds to #replace and use that if it's present (thereby maintaining __id__). It's not foolproof -- as someone could implement a #replace that doesn't do what we expect. -austin -- Austin Ziegler * halostatue@gmail.com * Alternate: austin@halostatue.ca