in reply to RFC: Transactions.pm

Nice idea. I don't like the global $T though. Not only you have to do

our $T = $object; transaction {...}
but it also means that there may only be one object in the transaction. It would be much nicer if you could pass the object(s) to the transaction() directly. Like
transaction [$dbh1, $dbh2] => code{...}; # or transaction ($dbh1, $dbh2) => code{...};
Here's the modified version that allows both:
package Transactions; use strict; use Carp qw(croak); use Exporter::Tidy default => [ qw(transaction commit rollback code) ] +; our $VERSION = '0.04j'; my @trans; my $trancount = 0; sub commit () { my $vars = pop @trans or croak "commit called outside transaction! +"; $trancount--; if ($trancount == 0) { # the outermost transaction $_->commit for reverse @$vars; } else { push @{$trans[-1]}, @$vars; } local $^W; # "exiting sub via last" last __TRANSACTION; } sub rollback () { my $vars = pop @trans or croak "rollback called outside transactio +n!"; $trancount--; $_->rollback for reverse @$vars; local $^W; # "exiting sub via last" last __TRANSACTION; } sub transaction ($$;@) { my $block = pop @_; my @vars = @_; @vars = @{$vars[0]} if (@vars == 1 and ref($vars[0]) eq 'ARRAY'); push @trans, \@vars; $trancount++; __TRANSACTION: { eval { $_->begin_work for @vars; $block->(); }; $@ ? rollback : commit; } $@ and croak $@ . "commit not safe after errors, transaction rolle +d back"; } sub code (&) {return $_[0]} 1;
As you can note it tries to handle nesting transactions as well. The handling is like this: the ->commit for inner transactions is postponed to the successfull end of the outermost one, the rollback of a transaction only rollbacks that transaction and the transactions nested within it, but does not affect the outer transactions. Not sure this exactly matches the way rollback is handled in databases, but this at least makes sense.

Another small fix is that the "commit not safe after errors, transaction rolled back" message should be croak()ed, not die()d.

Jenda
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
   -- Rick Osborne

Edit by castaway: Closed small tag in signature

Replies are listed 'Best First'.
Re: Re: RFC: Transactions.pm
by Juerd (Abbot) on Apr 28, 2003 at 12:10 UTC

    but it also means that there may only be one object in the transaction.

    See my example in another node in this thread about how you can easily write a wrapper package to allow this.

    sub code (&) {return $_[0]}

    Why not just use sub instead of code and call like transaction [ $foo, $bar ], sub { ... };?

    Another small fix is that the "commit not safe after errors, transaction rolled back" message should be croak()ed, not die()d.

    Not really. Note that $@ already contains the caller's filename and line number. I think this looks very nice:

    died at foo.pl line 13. commit not safe after errors, transaction rolled back at Transactions. +pm line 123.

    I wanted a (&) prototype to allow the sub keyword to be left out. So I tried several solutions to select a transaction capable object, $T being my most recent try.

    But the more I think about it, typing sub isn't so bad. As you say, if you simply supply the dbh to transaction(), nested transactions can be supported.

    I'll whip up a third version soon.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      1) Because

      transaction $bdh => code{ ... }
      reads better than
      transaction $bdh, sub { ... }
      . That's the only reason.

      2) Well, it may contain the filename&linenumber of the original error message, but not of the place where the transaction ends and where therefore it's commited or rolled back. I think it makes more sense to append the position of the closing brace of the transaction block than some line within Transaction.pm. Try to throw an exception within a second level transaction. You'll end up with something like:

      Some error commit not safe after errors, transaction rolled back at Transactions. +pm line 123 commit not safe after errors, transaction rolled back at Transactions. +pm line 123
      Not very helpfull I'd think :-)

      Here is the script I used to test my version of the module:

      Jenda
      Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
         -- Rick Osborne

      Edit by castaway: Closed small tag in signature

        Of course you can write that as
        transaction $dbh => sub { ... };
        as well. You know, thinking about this topic, it occured to me that this is where Perl6 user exposed parsing would allow us to superimpose such features on the language seamlessly, without all the caveats inherent to Perl5 solutions.

        Makeshifts last the longest.