File Coverage

blib/lib/DBIx/Aurora/Instance.pm
Criterion Covered Total %
statement 24 79 30.3
branch 0 20 0.0
condition 0 5 0.0
subroutine 8 23 34.7
pod 0 9 0.0
total 32 136 23.5


line stmt bran cond sub pod time code
1             package DBIx::Aurora::Instance;
2 1     1   3 use strict;
  1         7  
  1         22  
3 1     1   2 use warnings;
  1         1  
  1         17  
4 1     1   387 use DBIx::Handler;
  1         18870  
  1         26  
5 1     1   7 use Time::HiRes;
  1         1  
  1         7  
6              
7             sub new {
8 0     0 0   my ($class, $connect_info, $opts) = @_;
9 0   0       $opts ||= {};
10              
11 0           my $self = bless {
12             handler => undef,
13             is_readonly => undef,
14             is_unreachable => undef,
15             maybe_reader => 1,
16             connected_at => 0,
17             }, $class;
18              
19             my $on_connection_event = sub {
20 0     0     my ($mode, $dbh, $additional) = @_;
21 0 0         if (my $orig = $opts->{$mode}) {
22 0 0         if (not ref $orig) {
    0          
    0          
23 0           $dbh->do($orig);
24             } elsif (ref $orig eq 'CODE') {
25 0           $orig->($dbh);
26             } elsif (ref $orig eq 'ARRAY') {
27 0           $dbh->do($_) for @$orig;
28             } else {
29 0           Carp::croak "Invalid $mode: " . ref $orig;
30             }
31             }
32 0           $additional->($mode, $dbh);
33 0           };
34              
35             $self->{handler} = DBIx::Handler->new(
36             $connect_info->[0],
37             $connect_info->[1],
38             $connect_info->[2],
39             {
40              
41             AutoCommit => 0,
42             mysql_connect_timeout => 1,
43             mysql_write_timeout => 1,
44             mysql_read_timeout => 1,
45 0           %{$connect_info->[3]},
46             RaiseError => 1,
47             },
48             {
49             on_connect_do => sub {
50 0     0     my $dbh = shift;
51             $on_connection_event->(on_connect_do => $dbh, sub {
52 0           my ($mode, $dbh) = @_;
53 0           my $is_readonly = do {
54 0           my $sql = 'SELECT @@global.innodb_read_only AS readonly';
55 0           my $row = $dbh->selectrow_hashref($sql);
56 0           $row->{readonly};
57             };
58 0           $self->{is_readonly} = $is_readonly;
59 0           $self->{maybe_reader} = $is_readonly;
60 0           $self->{connected_at} = Time::HiRes::time;
61 0           });
62             },
63             on_disconnect_do => sub {
64 0     0     my $dbh = shift;
65             $on_connection_event->(on_disconnect_do => $dbh, sub {
66 0           my ($mode, $dbh) = @_;
67 0           $self->{is_readonly} = undef;
68 0           $self->{connected_at} = 0;
69             # DO NOT `undef $self->{maybe_reader}`;
70 0           });
71             },
72             }
73 0           );
74              
75 0           $self;
76             }
77              
78             sub handler {
79 0     0 0   my $self = shift;
80              
81 0           eval { $self->{handler}->dbh };
  0            
82 0 0         if (my $e = $@) {
83 0 0         if ($e =~ /DBI connect\(.+\) failed:/) {
84 0 0 0       if ($e =~ /Can't connect to MySQL server on '[^']*' \(111\)/) { # failover
    0          
    0          
85 0           Carp::croak(DBIx::Aurora::Instance::Exception::Connectivity::Failover->new($e));
86             } elsif ($e =~ /Lost connection to MySQL server at/) {
87 0           Carp::croak(DBIx::Aurora::Instance::Exception::Connectivity::LostConnection->new($e));
88             } elsif ( # unexpected connection errors
89             $e =~ /Unknown MySQL server host '[^']*' \(0\)/
90             or $e =~ /Can't connect to MySQL server on/
91             ) {
92             # FIXME $self->{is_unreachable} = 1;
93 0           Carp::croak(DBIx::Aurora::Instance::Exception::Connectivity::Unreachable->new($e));
94             } else {
95 0           Carp::croak(DBIx::Aurora::Instance::Exception::Connectivity->new($e));
96             }
97             } else {
98 0           Carp::croak($e);
99             }
100             }
101              
102 0           return $self->{handler};
103             }
104              
105             sub disconnect {
106 0     0 0   my $self = shift;
107 0           $self->{is_readonly} = undef;
108             # DO NOT `undef $self->{maybe_reader}`;
109 0 0         $self->{handler} && $self->{handler}->disconnect;
110             }
111              
112 0     0 0   sub maybe_writer { !shift->{maybe_reader} }
113 0     0 0   sub maybe_reader { shift->{maybe_reader} }
114 0     0 0   sub is_writer { !shift->{is_readonly} }
115 0     0 0   sub is_reader { shift->{is_readonly} }
116 0     0 0   sub is_unreachable { shift->{is_unreachable} }
117 0     0 0   sub connected_at { shift->{connected_at} }
118              
119 0     0     sub DESTROY { $_[0]->disconnect }
120              
121             package
122             DBIx::Aurora::Instance::Exception::Connectivity;
123 1     1   1612 use overload '""' => sub { shift->{msg} };
  1     0   857  
  1         6  
  0         0  
124              
125             sub new {
126 0     0     my ($class, $msg) = @_;
127 0           bless { msg => $msg }, $class;
128             }
129              
130             package
131             DBIx::Aurora::Instance::Exception::Connectivity::Failover;
132 1     1   484 use parent -norequire, 'DBIx::Aurora::Instance::Exception::Connectivity';
  1         212  
  1         5  
133              
134             package
135             DBIx::Aurora::Instance::Exception::Connectivity::LostConnection;
136 1     1   45 use parent -norequire, 'DBIx::Aurora::Instance::Exception::Connectivity';
  1         2  
  1         3  
137              
138             package
139             DBIx::Aurora::Instance::Exception::Connectivity::Unreachable;
140 1     1   35 use parent -norequire, 'DBIx::Aurora::Instance::Exception::Connectivity';
  1         1  
  1         3  
141              
142             1;
143             __END__