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 transaction!"; $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 rolled back"; } sub code (&) {return $_[0]} 1;