Filename | /usr/share/perl5/DBIx/Class/Storage/TxnScopeGuard.pm |
Statements | Executed 17 statements in 1.60ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 19µs | 19µs | BEGIN@7 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 17µs | 29µs | BEGIN@3 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 15µs | 294µs | BEGIN@10 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 13µs | 31µs | BEGIN@6 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 12µs | 69µs | BEGIN@9 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 9µs | 32µs | BEGIN@5 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 9µs | 18µs | BEGIN@4 | DBIx::Class::Storage::TxnScopeGuard::
1 | 1 | 1 | 8µs | 24µs | BEGIN@8 | DBIx::Class::Storage::TxnScopeGuard::
0 | 0 | 0 | 0s | 0s | DESTROY | DBIx::Class::Storage::TxnScopeGuard::
0 | 0 | 0 | 0s | 0s | __ANON__[:80] | DBIx::Class::Storage::TxnScopeGuard::
0 | 0 | 0 | 0s | 0s | __ANON__[:81] | DBIx::Class::Storage::TxnScopeGuard::
0 | 0 | 0 | 0s | 0s | commit | DBIx::Class::Storage::TxnScopeGuard::
0 | 0 | 0 | 0s | 0s | new | DBIx::Class::Storage::TxnScopeGuard::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package DBIx::Class::Storage::TxnScopeGuard; | ||||
2 | |||||
3 | 2 | 44µs | 2 | 41µs | # spent 29µs (17+12) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@3 which was called:
# once (17µs+12µs) by DBIx::Class::Storage::BEGIN@18 at line 3 # spent 29µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@3
# spent 12µs making 1 call to strict::import |
4 | 2 | 34µs | 2 | 26µs | # spent 18µs (9+9) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@4 which was called:
# once (9µs+9µs) by DBIx::Class::Storage::BEGIN@18 at line 4 # spent 18µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@4
# spent 9µs making 1 call to warnings::import |
5 | 2 | 54µs | 2 | 55µs | # spent 32µs (9+23) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@5 which was called:
# once (9µs+23µs) by DBIx::Class::Storage::BEGIN@18 at line 5 # spent 32µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@5
# spent 23µs making 1 call to Exporter::import |
6 | 2 | 49µs | 2 | 49µs | # spent 31µs (13+18) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@6 which was called:
# once (13µs+18µs) by DBIx::Class::Storage::BEGIN@18 at line 6 # spent 31µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@6
# spent 18µs making 1 call to Exporter::import |
7 | 2 | 39µs | 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 | 50µs | 2 | 39µs | # spent 24µs (8+15) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@8 which was called:
# once (8µs+15µs) by DBIx::Class::Storage::BEGIN@18 at line 8 # spent 24µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@8
# spent 15µs making 1 call to Exporter::import |
9 | 2 | 45µs | 2 | 126µs | # spent 69µs (12+57) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@9 which was called:
# once (12µs+57µs) by DBIx::Class::Storage::BEGIN@18 at line 9 # spent 69µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@9
# spent 57µs making 1 call to DBIx::Class::Carp::import |
10 | 2 | 1.28ms | 2 | 573µs | # spent 294µs (15+279) within DBIx::Class::Storage::TxnScopeGuard::BEGIN@10 which was called:
# once (15µs+279µs) by DBIx::Class::Storage::BEGIN@18 at line 10 # spent 294µs making 1 call to DBIx::Class::Storage::TxnScopeGuard::BEGIN@10
# spent 279µ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 | 2µs | 1; | ||
113 | |||||
114 | 1 | 249µs | __END__ # spent 249µs making 1 call to B::Hooks::EndOfScope::XS::__ANON__ |