| Filename | /usr/share/perl5/DBIx/Class/Storage/TxnScopeGuard.pm |
| Statements | Executed 0 statements in 0s |
| Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 9.94ms | 10.1ms | DBIx::Class::Storage::TxnScopeGuard::BEGIN@10 |
| 1 | 1 | 1 | 19µs | 19µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@7 |
| 1 | 1 | 1 | 18µs | 31µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@3 |
| 1 | 1 | 1 | 11µs | 20µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@4 |
| 1 | 1 | 1 | 10µs | 36µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@5 |
| 1 | 1 | 1 | 10µs | 57µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@9 |
| 1 | 1 | 1 | 9µs | 28µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@6 |
| 1 | 1 | 1 | 8µs | 26µs | DBIx::Class::Storage::TxnScopeGuard::BEGIN@8 |
| 0 | 0 | 0 | 0s | 0s | DBIx::Class::Storage::TxnScopeGuard::DESTROY |
| 0 | 0 | 0 | 0s | 0s | DBIx::Class::Storage::TxnScopeGuard::__ANON__[:80] |
| 0 | 0 | 0 | 0s | 0s | DBIx::Class::Storage::TxnScopeGuard::__ANON__[:81] |
| 0 | 0 | 0 | 0s | 0s | DBIx::Class::Storage::TxnScopeGuard::commit |
| 0 | 0 | 0 | 0s | 0s | DBIx::Class::Storage::TxnScopeGuard::new |
| Line | State ments |
Time on line |
Calls | Time in subs |
Code |
|---|---|---|---|---|---|
| 1 | package DBIx::Class::Storage::TxnScopeGuard; | ||||
| 2 | |||||
| 3 | 2 | 44µs | # spent 31µs (18+13) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@3 which was called:
# once (18µs+13µs) by DBIx::Class::Storage::BEGIN@18 at line 3 # spent 31µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@3
# spent 13µs making 1 call to strict::import | ||
| 4 | 2 | 30µs | # spent 20µs (11+10) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@4 which was called:
# once (11µs+10µs) by DBIx::Class::Storage::BEGIN@18 at line 4 # spent 20µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@4
# spent 10µs making 1 call to warnings::import | ||
| 5 | 2 | 63µs | # spent 36µs (10+26) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@5 which was called:
# once (10µs+26µs) by DBIx::Class::Storage::BEGIN@18 at line 5 # spent 36µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@5
# spent 26µs making 1 call to Exporter::import | ||
| 6 | 2 | 47µs | # spent 28µs (9+19) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@6 which was called:
# once (9µs+19µs) by DBIx::Class::Storage::BEGIN@18 at line 6 # spent 28µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@6
# spent 19µs making 1 call to Exporter::import | ||
| 7 | 1 | 19µs | # spent 19µs within DBIx::Class::Storage::TxnScopeGuard::BEGIN@7 which was called:
# once (19µs+0s) by DBIx::Class::Storage::BEGIN@18 at line 7 # spent 19µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@7 | ||
| 8 | 2 | 44µs | # spent 26µs (8+18) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@8 which was called:
# once (8µs+18µs) by DBIx::Class::Storage::BEGIN@18 at line 8 # spent 26µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@8
# spent 18µs making 1 call to Exporter::import | ||
| 9 | 2 | 104µs | # spent 57µs (10+47) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@9 which was called:
# once (10µs+47µs) by DBIx::Class::Storage::BEGIN@18 at line 9 # spent 57µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@9
# spent 47µs making 1 call to DBIx::Class::Carp::import | ||
| 10 | 2 | 10.3ms | # spent 10.1ms (9.94+188µs) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@10 which was called:
# once (9.94ms+188µs) by DBIx::Class::Storage::BEGIN@18 at line 10 # spent 10.1ms making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@10
# spent 188µs making 1 call to namespace::clean::import | ||
| 11 | |||||
| 12 | sub new { | ||||
| 13 | my ($class, $storage) = @_; | ||||
| 14 | |||||
| 15 | my $guard = { | ||||
| 16 | inactivated => 0, | ||||
| 17 | storage => $storage, | ||||
| 18 | }; | ||||
| 19 | |||||
| 20 | # we are starting with an already set $@ - in order for things to work we need to | ||||
| 21 | # be able to recognize it upon destruction - store its weakref | ||||
| 22 | # recording it before doing the txn_begin stuff | ||||
| 23 | # | ||||
| 24 | # FIXME FRAGILE - any eval that fails but *does not* rethrow between here | ||||
| 25 | # and the unwind will trample over $@ and invalidate the entire mechanism | ||||
| 26 | # There got to be a saner way of doing this... | ||||
| 27 | if (is_exception $@) { | ||||
| 28 | weaken( | ||||
| 29 | $guard->{existing_exception_ref} = (ref($@) eq '') ? \$@ : $@ | ||||
| 30 | ); | ||||
| 31 | } | ||||
| 32 | |||||
| 33 | $storage->txn_begin; | ||||
| 34 | |||||
| 35 | weaken( $guard->{dbh} = $storage->_dbh ); | ||||
| 36 | |||||
| 37 | bless $guard, ref $class || $class; | ||||
| 38 | |||||
| 39 | $guard; | ||||
| 40 | } | ||||
| 41 | |||||
| 42 | sub commit { | ||||
| 43 | my $self = shift; | ||||
| 44 | |||||
| 45 | $self->{storage}->throw_exception("Refusing to execute multiple commits on scope guard $self") | ||||
| 46 | if $self->{inactivated}; | ||||
| 47 | |||||
| 48 | $self->{storage}->txn_commit; | ||||
| 49 | $self->{inactivated} = 1; | ||||
| 50 | } | ||||
| 51 | |||||
| 52 | sub DESTROY { | ||||
| 53 | my $self = shift; | ||||
| 54 | |||||
| 55 | return if $self->{inactivated}; | ||||
| 56 | |||||
| 57 | # if our dbh is not ours anymore, the $dbh weakref will go undef | ||||
| 58 | $self->{storage}->_verify_pid unless DBIx::Class::_ENV_::BROKEN_FORK; | ||||
| 59 | return unless $self->{dbh}; | ||||
| 60 | |||||
| 61 | my $exception = $@ if ( | ||||
| 62 | is_exception $@ | ||||
| 63 | and | ||||
| 64 | ( | ||||
| 65 | ! defined $self->{existing_exception_ref} | ||||
| 66 | or | ||||
| 67 | refaddr( ref($@) eq '' ? \$@ : $@ ) != refaddr($self->{existing_exception_ref}) | ||||
| 68 | ) | ||||
| 69 | ); | ||||
| 70 | |||||
| 71 | { | ||||
| 72 | local $@; | ||||
| 73 | |||||
| 74 | carp 'A DBIx::Class::Storage::TxnScopeGuard went out of scope without explicit commit or error. Rolling back.' | ||||
| 75 | unless defined $exception; | ||||
| 76 | |||||
| 77 | my $rollback_exception; | ||||
| 78 | # do minimal connectivity check due to weird shit like | ||||
| 79 | # https://rt.cpan.org/Public/Bug/Display.html?id=62370 | ||||
| 80 | try { $self->{storage}->_seems_connected && $self->{storage}->txn_rollback } | ||||
| 81 | catch { $rollback_exception = shift }; | ||||
| 82 | |||||
| 83 | if ( $rollback_exception and ( | ||||
| 84 | ! defined blessed $rollback_exception | ||||
| 85 | or | ||||
| 86 | ! $rollback_exception->isa('DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION') | ||||
| 87 | ) ) { | ||||
| 88 | # append our text - THIS IS A TEMPORARY FIXUP! | ||||
| 89 | # a real stackable exception object is in the works | ||||
| 90 | if (ref $exception eq 'DBIx::Class::Exception') { | ||||
| 91 | $exception->{msg} = "Transaction aborted: $exception->{msg} " | ||||
| 92 | ."Rollback failed: ${rollback_exception}"; | ||||
| 93 | } | ||||
| 94 | elsif ($exception) { | ||||
| 95 | $exception = "Transaction aborted: ${exception} " | ||||
| 96 | ."Rollback failed: ${rollback_exception}"; | ||||
| 97 | } | ||||
| 98 | else { | ||||
| 99 | carp (join ' ', | ||||
| 100 | "********************* ROLLBACK FAILED!!! ********************", | ||||
| 101 | "\nA rollback operation failed after the guard went out of scope.", | ||||
| 102 | 'This is potentially a disastrous situation, check your data for', | ||||
| 103 | "consistency: $rollback_exception" | ||||
| 104 | ); | ||||
| 105 | } | ||||
| 106 | } | ||||
| 107 | } | ||||
| 108 | |||||
| 109 | $@ = $exception; | ||||
| 110 | } | ||||
| 111 | |||||
| 112 | 1; | ||||
| 113 | |||||
| 114 | 1 | 1.01ms | __END__ # spent 1.01ms making 1 call to B::Hooks::EndOfScope::XS::__ANON__ |