Merge 'trunk' into 'replication_dedux'
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replicated / Pool.pm
1 package DBIx::Class::Storage::DBI::Replicated::Pool;
2
3 use Moose;
4 use MooseX::AttributeHelpers;
5 use DBIx::Class::Storage::DBI::Replicated::Replicant;
6 use List::Util qw(sum);
7
8 =head1 NAME
9
10 DBIx::Class::Storage::DBI::Replicated::Pool; Manage a pool of replicants
11
12 =head1 SYNOPSIS
13
14 This class is used internally by L<DBIx::Class::Storage::DBI::Replicated>.  You
15 shouldn't need to create instances of this class.
16     
17 =head1 DESCRIPTION
18
19 In a replicated storage type, there is at least one replicant to handle the
20 read only traffic.  The Pool class manages this replicant, or list of 
21 replicants, and gives some methods for querying information about their status.
22
23 =head1 ATTRIBUTES
24
25 This class defines the following attributes.
26
27 =head2 replicant_type
28
29 Base class used to instantiate replicants that are in the pool.  Unless you
30 need to subclass L<DBIx::Class::Storage::DBI::Replicated::Replicant> you should
31 just leave this alone.
32
33 =cut
34
35 has 'replicant_type' => (
36     is=>'ro',
37     isa=>'ClassName',
38     required=>1,
39     default=>'DBIx::Class::Storage::DBI::Replicated::Replicant',
40     handles=>{
41         'create_replicant' => 'new',
42     },  
43 );
44
45 =head2 replicants
46
47 A hashref of replicant, with the key being the dsn and the value returning the
48 actual replicant storage.  For example if the $dsn element is something like:
49
50     "dbi:SQLite:dbname=dbfile"
51     
52 You could access the specific replicant via:
53
54     $schema->storage->replicants->{'dbname=dbfile'}
55     
56 This attributes also supports the following helper methods
57
58 =over 4
59
60 =item set_replicant($key=>$storage)
61
62 Pushes a replicant onto the HashRef under $key
63
64 =item get_replicant($key)
65
66 Retrieves the named replicant
67
68 =item has_replicants
69
70 Returns true if the Pool defines replicants.
71
72 =item num_replicants
73
74 The number of replicants in the pool
75
76 =item delete_replicant ($key)
77
78 removes the replicant under $key from the pool
79
80 =back
81
82 =cut
83
84 has 'replicants' => (
85     is=>'rw',
86     metaclass => 'Collection::Hash',
87     isa=>'HashRef[DBIx::Class::Storage::DBI::Replicated::Replicant]',
88     default=>sub {{}},
89     provides  => {
90                 'set' => 'set_replicant',
91                 'get' => 'get_replicant',            
92                 'empty' => 'has_replicants',
93                 'count' => 'num_replicants',
94                 'delete' => 'delete_replicant',
95         },
96 );
97
98 =head1 METHODS
99
100 This class defines the following methods.
101
102 =head2 connect_replicants ($schema, Array[$connect_info])
103
104 Given an array of $dsn suitable for connected to a database, create an
105 L<DBIx::Class::Storage::DBI::Replicated::Replicant> object and store it in the
106 L</replicants> attribute.
107
108 =cut
109
110 sub connect_replicants {
111         my $self = shift @_;
112         my $schema = shift @_;
113         
114         my @newly_created = ();
115         foreach my $connect_info (@_) {
116                 my $replicant = $self->create_replicant($schema);
117                 $replicant->connect_info($connect_info);
118                 $replicant->ensure_connected;
119                 my ($key) = ($connect_info->[0]=~m/^dbi\:.+\:(.+)$/);
120                 $self->set_replicant( $key => $replicant);      
121                 push @newly_created, $replicant;
122         }
123         
124         return @newly_created;
125 }
126
127 =head2 connected_replicants
128
129 Returns true if there are connected replicants.  Actually is overloaded to
130 return the number of replicants.  So you can do stuff like:
131
132     if( my $num_connected = $storage->has_connected_replicants ) {
133         print "I have $num_connected connected replicants";
134     } else {
135         print "Sorry, no replicants.";
136     }
137
138 This method will actually test that each replicant in the L</replicants> hashref
139 is actually connected, try not to hit this 10 times a second.
140
141 =cut
142
143 sub connected_replicants {
144         my $self = shift @_;
145         return sum( map {
146                 $_->connected ? 1:0
147         } $self->all_replicants );
148 }
149
150 =head2 active_replicants
151
152 This is an array of replicants that are considered to be active in the pool.
153 This does not check to see if they are connected, but if they are not, DBIC
154 should automatically reconnect them for us when we hit them with a query.
155
156 =cut
157
158 sub active_replicants {
159     my $self = shift @_;
160     return ( grep {$_} map {
161         $_->active ? $_:0
162     } $self->all_replicants );
163 }
164
165 =head2 all_replicants
166
167 Just a simple array of all the replicant storages.  No particular order to the
168 array is given, nor should any meaning be derived.
169
170 =cut
171
172 sub all_replicants {
173         my $self = shift @_;
174         return values %{$self->replicants};
175 }
176
177 =head1 AUTHOR
178
179 John Napiorkowski <john.napiorkowski@takkle.com>
180
181 =head1 LICENSE
182
183 You may distribute this code under the same terms as Perl itself.
184
185 =cut
186
187 1;