[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: [ANN] Transaction::Simple 1.3.0

John Lam

5/5/2005 7:41:00 PM

Yes - what you're saying does make sense.

I was thinking about cases where you're performing transactions against large objects, say a hash table.

Since the target objects don't know anything about transactions (and you don't know anything about their internal state) then this would wind up duplicating a lot of state.

However, if an object were Tx aware, then it would know how to manage its state in face of a transaction manager. Adding a single entry to a hash table wouldn't require copying the entire table first - you'd simply record the fact that you are adding a record and add it at commit-time.

At this point you'll need to have 2-phase commit protocols - telling each object to prepare to commit before actually committing. Any object that fails to prepare to commit aborts the entire Tx.

This is probably a lot more complicated than what you have envisioned (after all these are *Simple* transactions). I think this will still be very useful for many situations where you aren't modifying very large objects (or are not doing many such Tx in parallel).

-John

________________________________

From: Austin Ziegler [mailto:halostatue@gmail.com]
Sent: Thu 5/5/2005 3:17 PM
To: ruby-talk ML
Subject: Re: [ANN] Transaction::Simple 1.3.0



On 5/5/05, John Lam <jlam@iunknown.com> wrote:
> Wow wow wow! This is so massively cool. Thanks for creating this.
> I can't wait to spend some quality time with this.
>
> Do you snapshot state as the objects are modified? If so, does
> this avoid the problem of requiring two phase commit in your
> transaction groups?

I'm not quite sure what you're saying here. Transaction snapshots
are taken when you start the transaction:

require 'transaction/simple/group'

x = "Hello, you."
y = "And you, too."

g = Transaction::Simple::Group.new(x, y)
g.start_transaction(:first) # -> [ x, y ]
g.transaction_open?(:first) # -> true
x.transaction_open?(:first) # -> true
y.transaction_open?(:first) # -> true

At this point, the transaction state of x and y is set. 'g' doesn't
maintain any transaction state; x and y do independently. Strictly
speaking, the transaction group is just a synchronizer.

x.gsub!(/you/, "world") # -> "Hello, world."
y.gsub!(/you/, "me") # -> "And me, too."

Here, we've modified both x and y. No new snapshot has yet been
made.

g.start_transaction(:second) # -> [ x, y ]

There. That takes another snapshot and gives it the transaction name
of :second.

x.gsub!(/world/, "HAL") # -> "Hello, HAL."
y.gsub!(/me/, "Dave") # -> "And Dave, too."

Another modification.

g.rewind_transaction(:second) # -> [ x, y ]
x # -> "Hello, world."
y # -> "And me, too."

We've rewound the transaction on each object to its original state
here.

x.gsub!(/world/, "HAL") # -> "Hello, HAL."
y.gsub!(/me/, "Dave") # -> "And Dave, too."

g.commit_transaction(:second) # -> [ x, y ]
x # -> "Hello, HAL."
y # -> "And Dave, too."

Changes are made and the second transaction is committed on both
objects. Note: if something goes wrong in the committing of the
first object, then the second object won't be committed.

g.abort_transaction(:first) # -> [ x, y ]
x = -> "Hello, you."
y = -> "And you, too."

This aborts the transaction and restores the state of the objects to
their original value. Except that they are now able to do
transactions.

Make sense?

Most of this code is based on what I did for block transactions:

Transaction::Simple.start_named(:foo, x, y) do |tx, ty|
...
end

I may go through at some point and unify the implementations here
and provide block forms of the transaction group methods.

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca






3 Answers

Austin Ziegler

5/5/2005 7:49:00 PM

0

On 5/5/05, John Lam <jlam@iunknown.com> wrote:
> Yes - what you're saying does make sense.
>
> I was thinking about cases where you're performing transactions
> against large objects, say a hash table.

Well, I do these against large objects. Transaction::Simple is a
fundamental support library for PDF::Writer. Just about the only
time it sees update is when I need to update it for PDF::Writer ;).

> Since the target objects don't know anything about transactions
> (and you don't know anything about their internal state) then this
> would wind up duplicating a lot of state.

Well, that's not really true. With Transaction::Simple, the target
object does become transaction-aware -- but it has nothing to do
with a "transaction manager" or database transactions.

> However, if an object were Tx aware, then it would know how to
> manage its state in face of a transaction manager. Adding a single
> entry to a hash table wouldn't require copying the entire table
> first - you'd simply record the fact that you are adding a record
> and add it at commit-time.

Right. This isn't a transaction log that can be replayed. This does
the simplest possible thing (which is why there are a number of
limitatiosn): it takes a Marshal.dump of the object.

> At this point you'll need to have 2-phase commit protocols -
> telling each object to prepare to commit before actually
> committing. Any object that fails to prepare to commit aborts the
> entire Tx.

Well, I don't know if it's currently used, but DHH added
Transaction::Simple support to ActiveRecord a while back so that
when you do a transaction with ActiveRecord, if the database
transaction fails, it also causes the object transaction to fail.

> This is probably a lot more complicated than what you have
> envisioned (after all these are *Simple* transactions). I think
> this will still be very useful for many situations where you
> aren't modifying very large objects (or are not doing many such Tx
> in parallel).

Perhaps. Something like this might be possible with a Builder
object, but it would require a level of wrapping that I'm not -- at
this point -- interested in dealing with.

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca



Logan Capaldo

5/5/2005 11:35:00 PM

0

On 5/5/05, Austin Ziegler <halostatue@gmail.com> wrote:
> On 5/5/05, John Lam <jlam@iunknown.com> wrote:
> > Yes - what you're saying does make sense.
> >
> > I was thinking about cases where you're performing transactions
> > against large objects, say a hash table.
>
> Well, I do these against large objects. Transaction::Simple is a
> fundamental support library for PDF::Writer. Just about the only
> time it sees update is when I need to update it for PDF::Writer ;).
>
> > Since the target objects don't know anything about transactions
> > (and you don't know anything about their internal state) then this
> > would wind up duplicating a lot of state.
>
> Well, that's not really true. With Transaction::Simple, the target
> object does become transaction-aware -- but it has nothing to do
> with a "transaction manager" or database transactions.
>
> > However, if an object were Tx aware, then it would know how to
> > manage its state in face of a transaction manager. Adding a single
> > entry to a hash table wouldn't require copying the entire table
> > first - you'd simply record the fact that you are adding a record
> > and add it at commit-time.
>
> Right. This isn't a transaction log that can be replayed. This does
> the simplest possible thing (which is why there are a number of
> limitatiosn): it takes a Marshal.dump of the object.
>
> > At this point you'll need to have 2-phase commit protocols -
> > telling each object to prepare to commit before actually
> > committing. Any object that fails to prepare to commit aborts the
> > entire Tx.
>
> Well, I don't know if it's currently used, but DHH added
> Transaction::Simple support to ActiveRecord a while back so that
> when you do a transaction with ActiveRecord, if the database
> transaction fails, it also causes the object transaction to fail.
>
> > This is probably a lot more complicated than what you have
> > envisioned (after all these are *Simple* transactions). I think
> > this will still be very useful for many situations where you
> > aren't modifying very large objects (or are not doing many such Tx
> > in parallel).
>
> Perhaps. Something like this might be possible with a Builder
> object, but it would require a level of wrapping that I'm not -- at
> this point -- interested in dealing with.
>
> -austin
> --
> Austin Ziegler * halostatue@gmail.com
> * Alternate: austin@halostatue.ca
>
>

This is cool. Would things like this work?

v = SomeObject.new
v.extend(Transaction::Simple)

begin
v.start_transaction
v.someMethodThatMightRaiseAnExceptionLeavingTheObjectInAnInvalidState
v.commit_transaction
rescue SaidException
v.abort_transaction
end



Austin Ziegler

5/6/2005 1:46:00 AM

0

On 5/5/05, Logan Capaldo <logancapaldo@gmail.com> wrote:
> This is cool. Would things like this work?
>
> v = SomeObject.new
> v.extend(Transaction::Simple)
>
> begin
> v.start_transaction
v.bad_method
> v.commit_transaction
> rescue SaidException
> v.abort_transaction
> end

That, Logan, is one of the very reasons that this package exists.

You can also go:

begin
v.start_transaction
if v.bad_method
v.commit_transaction
else
v.abort_transaction
rescue SillyException
v.rewind_transaction
v.recover
retry
end

-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca