line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package Ima::DBI::Contextual; |
3
|
|
|
|
|
|
|
|
4
|
3
|
|
|
3
|
|
2343
|
use strict; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
110
|
|
5
|
3
|
|
|
3
|
|
17
|
use warnings 'all'; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
94
|
|
6
|
3
|
|
|
3
|
|
15
|
use Carp 'confess'; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
199
|
|
7
|
3
|
|
|
3
|
|
7043
|
use DBI; |
|
3
|
|
|
|
|
83978
|
|
|
3
|
|
|
|
|
234
|
|
8
|
3
|
|
|
3
|
|
39
|
use Digest::MD5 'md5_hex'; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
196
|
|
9
|
3
|
|
|
3
|
|
13088
|
use Time::HiRes 'usleep'; |
|
3
|
|
|
|
|
7161
|
|
|
3
|
|
|
|
|
16
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '1.006'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
my $cache = { }; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub set_db |
16
|
|
|
|
|
|
|
{ |
17
|
1
|
|
|
1
|
0
|
22
|
my ($pkg) = shift; |
18
|
1
|
50
|
|
|
|
4
|
$pkg = ref($pkg) ? ref($pkg) : $pkg; |
19
|
1
|
|
|
|
|
3
|
my ($name) = shift; |
20
|
1
|
|
|
|
|
3
|
my @dsn_with_attrs = @_; |
21
|
1
|
|
|
|
|
3
|
my @dsn = grep { ! ref($_) } @_; |
|
3
|
|
|
|
|
8
|
|
22
|
1
|
|
|
|
|
1
|
my ($attrs) = grep { ref($_) } @_; |
|
3
|
|
|
|
|
6
|
|
23
|
1
|
|
|
|
|
8
|
my $default_attrs = { |
24
|
|
|
|
|
|
|
RaiseError => 1, |
25
|
|
|
|
|
|
|
AutoCommit => 0, |
26
|
|
|
|
|
|
|
PrintError => 0, |
27
|
|
|
|
|
|
|
Taint => 1, |
28
|
|
|
|
|
|
|
AutoInactiveDestroy => 1, |
29
|
|
|
|
|
|
|
}; |
30
|
1
|
50
|
|
|
|
4
|
map { $attrs->{$_} = $default_attrs->{$_} unless defined($attrs->{$_}) } |
|
5
|
|
|
|
|
26
|
|
31
|
|
|
|
|
|
|
keys %$default_attrs; |
32
|
|
|
|
|
|
|
|
33
|
1
|
|
|
|
|
6
|
@dsn_with_attrs = ( @dsn, $attrs ); |
34
|
|
|
|
|
|
|
|
35
|
3
|
|
|
3
|
|
1536
|
no strict 'refs'; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
111
|
|
36
|
3
|
|
|
3
|
|
18
|
no warnings 'redefine'; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
2918
|
|
37
|
1
|
|
|
|
|
9
|
*{"$pkg\::db_$name"} = $pkg->_mk_closure( $name, \@dsn, $attrs ); |
|
1
|
|
|
|
|
12
|
|
38
|
1
|
|
|
|
|
6
|
return; |
39
|
|
|
|
|
|
|
}# end set_db() |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub _mk_closure |
43
|
|
|
|
|
|
|
{ |
44
|
1
|
|
|
1
|
|
3
|
my ($pkg, $name, $dsn, $attrs) = @_; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
return sub { |
47
|
3
|
|
|
3
|
|
920
|
my ($class) = @_; |
48
|
|
|
|
|
|
|
|
49
|
3
|
|
|
|
|
11
|
my @dsn = @$dsn; |
50
|
|
|
|
|
|
|
|
51
|
3
|
|
|
|
|
12
|
$attrs->{pid} = $$; |
52
|
3
|
|
|
|
|
23
|
my $key = $class->_context( $name, \@dsn, $attrs ); |
53
|
3
|
|
|
|
|
6
|
my $dbh; |
54
|
3
|
100
|
|
|
|
13
|
if( $dbh = $cache->{$key}->{dbh} ) |
55
|
|
|
|
|
|
|
{ |
56
|
2
|
50
|
|
|
|
13
|
if( $class->_ping($dbh) ) |
57
|
|
|
|
|
|
|
{ |
58
|
|
|
|
|
|
|
# dbh belongs to this process and it's good: |
59
|
|
|
|
|
|
|
# YAY: |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
else |
62
|
|
|
|
|
|
|
{ |
63
|
|
|
|
|
|
|
# dbh has gone stale. reconnect: |
64
|
0
|
|
|
|
|
0
|
my $child_attrs = { %$attrs }; |
65
|
0
|
|
|
|
|
0
|
my $clone = $dbh->clone($child_attrs); |
66
|
0
|
|
|
|
|
0
|
$dbh->{InactiveDestroy} = 1; |
67
|
0
|
|
|
|
|
0
|
undef($dbh); |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# Now - make sure that the clone worked: |
70
|
0
|
0
|
|
|
|
0
|
if( $class->_ping( $clone ) ) |
71
|
|
|
|
|
|
|
{ |
72
|
|
|
|
|
|
|
# This is a good clone - use it: |
73
|
0
|
|
|
|
|
0
|
$dbh = $cache->{$key}->{dbh} = $clone; |
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
else |
76
|
|
|
|
|
|
|
{ |
77
|
|
|
|
|
|
|
# The clone was no good - reconnect: |
78
|
0
|
|
|
|
|
0
|
$dbh = $cache->{$key}->{dbh} = DBI->connect_cached(@dsn, $attrs); |
79
|
|
|
|
|
|
|
}# end if() |
80
|
|
|
|
|
|
|
}# end if() |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
else |
83
|
|
|
|
|
|
|
{ |
84
|
|
|
|
|
|
|
# We have not connected yet - engage: |
85
|
1
|
|
|
|
|
10
|
$dbh = $cache->{$key}->{dbh} = DBI->connect_cached(@dsn, $attrs); |
86
|
|
|
|
|
|
|
}# end if() |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# Finally: |
89
|
3
|
|
|
|
|
15033
|
return $dbh; |
90
|
1
|
|
|
|
|
9
|
}; |
91
|
|
|
|
|
|
|
}# end _mk_closure() |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub _context |
95
|
|
|
|
|
|
|
{ |
96
|
3
|
|
|
3
|
|
15
|
my ($class, $name, $dsn, $attrs) = @_; |
97
|
|
|
|
|
|
|
|
98
|
3
|
|
|
|
|
8
|
my @parts = ($name ); |
99
|
3
|
|
|
|
|
10
|
$attrs->{child_pid} = $$; |
100
|
3
|
50
|
|
|
|
13
|
eval { push @parts, threads->tid } |
|
0
|
|
|
|
|
0
|
|
101
|
|
|
|
|
|
|
if $INC{'threads.pm'}; |
102
|
3
|
|
|
|
|
8
|
foreach( $dsn, $attrs ) |
103
|
|
|
|
|
|
|
{ |
104
|
6
|
100
|
|
|
|
21
|
if( ref($_) eq 'HASH' ) |
|
|
50
|
|
|
|
|
|
105
|
|
|
|
|
|
|
{ |
106
|
3
|
|
|
|
|
5
|
my $h = $_; |
107
|
3
|
|
|
|
|
23
|
push @parts, map {"$_=$h->{$_}"} sort keys %$h; |
|
21
|
|
|
|
|
68
|
|
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
elsif( ref($_) eq 'ARRAY' ) |
110
|
|
|
|
|
|
|
{ |
111
|
3
|
|
|
|
|
8
|
push @parts, @$_; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
else |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
|
|
0
|
push @parts, $_; |
116
|
|
|
|
|
|
|
}# end if() |
117
|
|
|
|
|
|
|
}# end foreach() |
118
|
|
|
|
|
|
|
|
119
|
3
|
|
|
|
|
63
|
return md5_hex(join ", ", @parts); |
120
|
|
|
|
|
|
|
}# end _context() |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub _ping |
124
|
|
|
|
|
|
|
{ |
125
|
2
|
|
|
2
|
|
3
|
my ($class, $dbh) = @_; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# Forgive the "If Slalom" - putting each condition on a separate line gives us |
128
|
|
|
|
|
|
|
# better error messages were one of them to fail: |
129
|
2
|
50
|
|
|
|
10
|
if( $dbh ) |
130
|
|
|
|
|
|
|
{ |
131
|
2
|
50
|
|
|
|
31
|
if( $dbh->FETCH('Active') ) |
132
|
|
|
|
|
|
|
{ |
133
|
2
|
50
|
|
|
|
12
|
if( $dbh->ping ) |
134
|
|
|
|
|
|
|
{ |
135
|
2
|
|
|
|
|
113
|
return $dbh; |
136
|
|
|
|
|
|
|
}# end if() |
137
|
|
|
|
|
|
|
}# end if() |
138
|
|
|
|
|
|
|
}# end if() |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
0
|
|
|
|
|
|
return; |
142
|
|
|
|
|
|
|
}# end _ping() |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub rollback |
146
|
|
|
|
|
|
|
{ |
147
|
0
|
|
|
0
|
0
|
|
my ($class) = @_; |
148
|
0
|
|
|
|
|
|
confess 'Deprecated'; |
149
|
0
|
|
|
|
|
|
$class->db_Main->rollback; |
150
|
|
|
|
|
|
|
}# end dbi_rollback() |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
sub commit |
154
|
|
|
|
|
|
|
{ |
155
|
0
|
|
|
0
|
0
|
|
my ($class) = @_; |
156
|
0
|
|
|
|
|
|
confess 'Deprecated'; |
157
|
0
|
|
|
|
|
|
$class->db_Main->commit; |
158
|
|
|
|
|
|
|
}# end dbi_commit() |
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
1;# return true: |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
=pod |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=head1 NAME |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Ima::DBI::Contextual - Liteweight context-aware dbi handle cache and utility methods. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head1 DEPRECATED |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
This module has been deprecated. Do not use. |
171
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=head1 SYNOPSIS |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
package Foo; |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
use base 'Ima::DBI::Contextual'; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
my @dsn = ( 'DBI:mysql:dbname:hostname', 'username', 'password', { |
179
|
|
|
|
|
|
|
RaiseError => 0, |
180
|
|
|
|
|
|
|
}); |
181
|
|
|
|
|
|
|
__PACKAGE__->set_db('Main', @dsn); |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
Then, elsewhere: |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
my $dbh = Foo->db_Main; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# Use $dbh like you normally would: |
188
|
|
|
|
|
|
|
my $sth = $dbh->prepare( ... ); |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=head1 DESCRIPTION |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
If you like L but need it to be more context-aware (eg: tie dbi connections to |
193
|
|
|
|
|
|
|
more than the name and process id) then you need C. |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=head1 RANT |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
B: For permanent relief of symptoms related to hosting multiple mod_perl |
198
|
|
|
|
|
|
|
web applications on one server, where each application uses a different database |
199
|
|
|
|
|
|
|
but they all refer to the database handle via C<< Class->db_Main >>. Such symptoms |
200
|
|
|
|
|
|
|
may include: |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=over 4 |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=item * Wonky behavior which causes one website to fail because it's connected to the wrong database. |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
Scenario - Everything is going fine, you're clicking around walking your client through |
207
|
|
|
|
|
|
|
a demo of the web application and then BLAMMO - B<500 server error>! Another click and it's OK. WTF? |
208
|
|
|
|
|
|
|
You look at the log for Foo application and it says something like "C" |
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
Funny thing is - you never connected to that database. You have no idea B it is trying to connect to that database. |
211
|
|
|
|
|
|
|
Pouring over the guts in L it's clear that L only caches database |
212
|
|
|
|
|
|
|
handles by Process ID (C<$$>) and name (eg: db_B). So if the same Apache child |
213
|
|
|
|
|
|
|
process has more than one application running within it and each application has C then |
214
|
|
|
|
|
|
|
I. |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=item * Wondering for years what happened. |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Years, no less. |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
=item * Not impressing your boss. |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
Yeah - it can happen - when you have them take a look at your new shumwidget and |
223
|
|
|
|
|
|
|
instead of working - it I work. All your preaching about unit tests and |
224
|
|
|
|
|
|
|
DRY go right out the window when the basics (eg - connecting to the B) are broken. |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=back |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=head1 SEE ALSO |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
L |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
=head1 AUTHOR |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
John Drago |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head1 LICENSE |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
This software is B software and may be used and redistributed under the same |
239
|
|
|
|
|
|
|
terms as Perl itself. |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |
242
|
|
|
|
|
|
|
|