1 package DBIx::Class::Storage::DBI::Replicated::Pool;
4 use MooseX::AttributeHelpers;
5 use DBIx::Class::Storage::DBI::Replicated::Replicant;
6 use List::Util qw(sum);
10 DBIx::Class::Storage::DBI::Replicated::Pool; Manage a pool of replicants
14 This class is used internally by L<DBIx::Class::Storage::DBI::Replicated>. You
15 shouldn't need to create instances of this class.
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.
25 This class defines the following attributes.
27 =head2 maximum_lag ($num)
29 This is a number which defines the maximum allowed lag returned by the
30 L<DBIx::Class::Storage::DBI/lag_behind_master> method. The default is 0. In
31 general, this should return a larger number when the replicant is lagging
32 behind it's master, however the implementation of this is database specific, so
33 don't count on this number having a fixed meaning. For example, MySQL will
34 return a number of seconds that the replicating database is lagging.
38 has 'maximum_lag' => (
46 =head2 replicant_type ($classname)
48 Base class used to instantiate replicants that are in the pool. Unless you
49 need to subclass L<DBIx::Class::Storage::DBI::Replicated::Replicant> you should
50 just leave this alone.
54 has 'replicant_type' => (
58 default=>'DBIx::Class::Storage::DBI',
60 'create_replicant' => 'new',
66 A hashref of replicant, with the key being the dsn and the value returning the
67 actual replicant storage. For example if the $dsn element is something like:
69 "dbi:SQLite:dbname=dbfile"
71 You could access the specific replicant via:
73 $schema->storage->replicants->{'dbname=dbfile'}
75 This attributes also supports the following helper methods
79 =item set_replicant($key=>$storage)
81 Pushes a replicant onto the HashRef under $key
83 =item get_replicant($key)
85 Retrieves the named replicant
89 Returns true if the Pool defines replicants.
93 The number of replicants in the pool
95 =item delete_replicant ($key)
97 removes the replicant under $key from the pool
103 has 'replicants' => (
105 metaclass => 'Collection::Hash',
106 isa=>'HashRef[DBIx::Class::Storage::DBI]',
109 'set' => 'set_replicant',
110 'get' => 'get_replicant',
111 'empty' => 'has_replicants',
112 'count' => 'num_replicants',
113 'delete' => 'delete_replicant',
119 This class defines the following methods.
121 =head2 connect_replicants ($schema, Array[$connect_info])
123 Given an array of $dsn suitable for connected to a database, create an
124 L<DBIx::Class::Storage::DBI::Replicated::Replicant> object and store it in the
125 L</replicants> attribute.
129 sub connect_replicants {
131 my $schema = shift @_;
133 my @newly_created = ();
134 foreach my $connect_info (@_) {
136 my $replicant = $self->create_replicant($schema);
137 $replicant->connect_info($connect_info);
138 $replicant->ensure_connected;
139 DBIx::Class::Storage::DBI::Replicated::Replicant->meta->apply($replicant);
141 my ($key) = ($connect_info->[0]=~m/^dbi\:.+\:(.+)$/);
142 $self->set_replicant( $key => $replicant);
143 push @newly_created, $replicant;
146 return @newly_created;
149 =head2 connected_replicants
151 Returns true if there are connected replicants. Actually is overloaded to
152 return the number of replicants. So you can do stuff like:
154 if( my $num_connected = $storage->has_connected_replicants ) {
155 print "I have $num_connected connected replicants";
157 print "Sorry, no replicants.";
160 This method will actually test that each replicant in the L</replicants> hashref
161 is actually connected, try not to hit this 10 times a second.
165 sub connected_replicants {
169 } $self->all_replicants );
172 =head2 active_replicants
174 This is an array of replicants that are considered to be active in the pool.
175 This does not check to see if they are connected, but if they are not, DBIC
176 should automatically reconnect them for us when we hit them with a query.
180 sub active_replicants {
182 return ( grep {$_} map {
184 } $self->all_replicants );
187 =head2 all_replicants
189 Just a simple array of all the replicant storages. No particular order to the
190 array is given, nor should any meaning be derived.
196 return values %{$self->replicants};
199 =head2 validate_replicants
201 This does a check to see if 1) each replicate is connected (or reconnectable),
202 2) that is ->is_replicating, and 3) that it is not exceeding the lag amount
203 defined by L</maximum_lag>. Replicants that fail any of these tests are set to
204 inactive, and thus removed from the replication pool.
206 This tests L<all_replicants>, since a replicant that has been previous marked
207 as inactive can be reactived should it start to pass the validation tests again.
209 See L<DBIx::Class::Storage::DBI> for more about checking if a replicating
210 connection is not following a master or is lagging.
212 Calling this method will generate queries on the replicant databases so it is
213 not recommended that you run them very often.
217 sub validate_replicants {
219 foreach my $replicant($self->all_replicants) {
221 $replicant->is_replicating &&
222 $replicant->lag_behind_master <= $self->maximum_lag &&
223 $replicant->ensure_connected
225 ## TODO:: Hook debug for this
226 $replicant->active(1)
228 ## TODO:: Hook debug for this
229 $replicant->active(0);
236 John Napiorkowski <john.napiorkowski@takkle.com>
240 You may distribute this code under the same terms as Perl itself.