File Coverage

blib/lib/DBIx/AutoReconnect.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             # $Id: AutoReconnect.pm,v 1.3 2005/07/08 08:30:09 dk Exp $
2              
3             package DBIx::AutoReconnect;
4              
5 1     1   2576 use DBI;
  0            
  0            
6             use strict;
7             use vars qw(%instances %defaults $VERSION);
8              
9             $VERSION = '0.01';
10              
11             %defaults = (
12             ReconnectTimeout => 60,
13             ReconnectMaxTries => 5,
14             ReconnectFailure => undef,
15             );
16              
17             sub connect
18             {
19             my ( $class, $dsn, $user, $pass, $opt, @extras) = @_;
20              
21             $opt = {} unless $opt;
22             my $profile = {
23             conninfo => [ $dsn, $user, $pass, $opt, @extras ],
24             dbh => undef,
25             do_connect => 1,
26             };
27              
28             # XXX DBI doesn't say its defaults out, so hack
29             $opt->{PrintError} = 1 unless defined $opt->{PrintError};
30              
31             for ( keys %defaults) {
32             if ( exists $opt->{$_}) {
33             $profile->{$_} = $opt->{$_};
34             delete $opt->{$_};
35             } else {
36             $profile->{$_} = $defaults{$_};
37             };
38             }
39              
40             my $self = {};
41             tie %{$self}, 'DBIx::AutoReconnect::TieHash', $profile;
42              
43             bless $self, $class;
44             $instances{"$self"} = $profile;
45            
46             return $self-> __dbh_connect ? $self : undef;
47             }
48              
49             sub __dbh_connect
50             {
51             my $self = $instances{"$_[0]"};
52              
53             return $self-> {dbh} unless $self->{do_connect};
54              
55             my $tries = 0;
56             my $downtime = 0;
57             RETRY: while ( 1) {
58             {
59             local $self->{conninfo}->[3]-> {RaiseError} = 0;
60             if ( $self-> {dbh} = DBI-> connect( @{$self->{conninfo}})) {
61             warn "DBIx::AutoReconnect: successfully reconnected after $tries tries and $downtime sec downtime\n"
62             if $tries > 0 and $self->{conninfo}->[3]-> {PrintError};
63             last RETRY;
64             }
65             }
66             $self-> {ReconnectFailure}->() if $self-> {ReconnectFailure};
67             $tries++;
68             if ( defined ($self-> {ReconnectMaxTries}) and $self-> {ReconnectMaxTries} <= $tries) {
69             if ( $self->{conninfo}->[3]-> {RaiseError}) {
70             die $DBI::errstr;
71             } else {
72             return undef;
73             }
74             }
75             if ( $self-> {ReconnectTimeout} > 0) {
76             warn "DBIx::AutoReconnect: sleeping for $self->{ReconnectTimeout} seconds\n"
77             if $self-> {conninfo}->[3]->{PrintError};
78             sleep $self-> {ReconnectTimeout};
79             $downtime += $self-> {ReconnectTimeout};
80             }
81             }
82              
83             return $self-> {dbh};
84             }
85              
86             sub begin_work {
87             die "DBI::begin_work() is not to be used together with DBIx::AutoReconnect"
88             }
89             sub rollback {
90             die "DBI::rollback() is not to be used together with DBIx::AutoReconnect"
91             }
92             sub commit {
93             die "DBI::commit() is not to be used together with DBIx::AutoReconnect"
94             }
95              
96             sub get_handle { $instances{"$_[0]"}->{dbh} }
97              
98             sub disconnect
99             {
100             my $self = $instances{"$_[0]"};
101              
102             $self-> {dbh}-> disconnect;
103             $self-> {do_connect} = 0;
104             $self-> {dbh} = undef;
105             }
106              
107             sub AUTOLOAD
108             {
109             use vars qw($AUTOLOAD);
110              
111             my $method = $AUTOLOAD;
112             $method =~ s/^.*:([^:]+)$/$1/;
113              
114             my $obj = shift;
115             my $self = $instances{"$obj"};
116              
117             my ( $ret, @ret);
118              
119             my $wa = wantarray;
120              
121             while ( 1) {
122             unless ( $self->{dbh}) {
123             $self-> {conninfo}->[3]-> {RaiseError} ?
124             croak( "DBIx::AutoReconnect: not connected" ) :
125             return;
126             }
127              
128             eval {
129             local $self->{dbh}->{RaiseError} = 1;
130             if ( $wa) {
131             @ret = $self-> {dbh}-> $method(@_);
132             } else {
133             $ret = $self-> {dbh}-> $method(@_);
134             }
135             };
136             last unless $@;
137              
138             if ( $self->{dbh}->ping) {
139             die $@;
140             } else {
141             $obj-> __dbh_connect;
142             }
143             }
144              
145             return $wa ? @ret : $ret;
146             }
147              
148             sub DESTROY
149             {
150             my $self = $instances{"$_[0]"};
151             $self-> {do_connect} = 0;
152              
153             delete $instances{"$_[0]"};
154             }
155              
156              
157             package DBIx::AutoReconnect::TieHash;
158              
159             sub TIEHASH
160             {
161             my ( $class, $profile) = @_;
162             bless $profile, $class;
163             }
164              
165             sub FETCH
166             {
167             my ( $self, $key) = @_;
168             if ( exists $DBIx::AutoReconnect::defaults{$key}) {
169             return $self-> {$key};
170             } else {
171             return $self-> {dbh}->{$key};
172             }
173             }
174              
175             sub STORE
176             {
177             my ( $self, $key, $val) = @_;
178             if ( exists $DBIx::AutoReconnect::defaults{$key}) {
179             $self-> {$key} = $val;
180             } else {
181             $self-> {conninfo}->[3]->{$key} = $val;
182             $self-> {dbh}->{$key} = $val;
183             }
184             }
185              
186             1;
187              
188             __DATA__