1 package DBIx::Class::Storage::DBI::Replicated;
4 use DBIx::Class::Storage::DBI;
5 use DBIx::Class::Storage::DBI::Replicated::Pool;
6 use DBIx::Class::Storage::DBI::Replicated::Balancer;
7 use Scalar::Util qw(blessed);
9 extends 'DBIx::Class::Storage::DBI', 'Moose::Object';
13 DBIx::Class::Storage::DBI::Replicated - ALPHA Replicated database support
17 The Following example shows how to change an existing $schema to a replicated
18 storage type, add some replicated (readonly) databases, and perform reporting
21 ## Change storage_type in your schema class
22 $schema->storage_type( '::DBI::Replicated' );
24 ## Add some slaves. Basically this is an array of arrayrefs, where each
25 ## arrayref is database connect information
27 $schema->storage->connect_replicants(
28 [$dsn1, $user, $pass, \%opts],
29 [$dsn1, $user, $pass, \%opts],
30 [$dsn1, $user, $pass, \%opts],
35 Warning: This class is marked ALPHA. We are using this in development and have
36 some basic test coverage but the code hasn't yet been stressed by a variety
37 of databases. Individual DB's may have quirks we are not aware of. Please
38 use this in development and pass along your experiences/bug fixes.
40 This class implements replicated data store for DBI. Currently you can define
41 one master and numerous slave database connections. All write-type queries
42 (INSERT, UPDATE, DELETE and even LAST_INSERT_ID) are routed to master
43 database, all read-type queries (SELECTs) go to the slave database.
45 Basically, any method request that L<DBIx::Class::Storage::DBI> would normally
46 handle gets delegated to one of the two attributes: L</master_storage> or to
47 L</current_replicant_storage>. Additionally, some methods need to be distributed
48 to all existing storages. This way our storage class is a drop in replacement
49 for L<DBIx::Class::Storage::DBI>.
51 Read traffic is spread across the replicants (slaves) occuring to a user
52 selected algorithm. The default algorithm is random weighted.
54 TODO more details about the algorithm.
58 This class defines the following attributes.
62 Contains the classname which will instantiate the L</pool> object. Defaults
63 to: L<DBIx::Class::Storage::DBI::Replicated::Pool>.
72 default=>'DBIx::Class::Storage::DBI::Replicated::Pool',
74 'create_pool' => 'new',
81 The replication pool requires a balance class to provider the methods for
82 choose how to spread the query load across each replicant in the pool.
86 has 'balancer_type' => (
91 default=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
93 'create_balancer' => 'new',
100 Is a <DBIx::Class::Storage::DBI::Replicated::Pool> or derived class. This is a
101 container class for one or more replicated databases.
107 isa=>'DBIx::Class::Storage::DBI::Replicated::Pool',
121 Is a <DBIx::Class::Storage::DBI::Replicated::Balancer> or derived class. This
122 is a class that takes a pool (<DBIx::Class::Storage::DBI::Replicated::Pool>)
128 isa=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
135 The master defines the canonical state for a pool of connected databases. All
136 the replicants are expected to match this databases state. Thus, in a classic
137 Master / Slaves distributed system, all the slaves are expected to replicate
138 the Master's state as quick as possible. This is the only database in the
139 pool of databases that is allowed to handle write traffic.
145 isa=>'DBIx::Class::Storage::DBI',
150 =head1 ATTRIBUTES IMPLEMENTING THE DBIx::Storage::DBI INTERFACE
152 The following methods are delegated all the methods required for the
153 L<DBIx::Class::Storage::DBI> interface.
157 Defines an object that implements the read side of L<BIx::Class::Storage::DBI>.
161 has 'read_handler' => (
175 Defines an object that implements the write side of L<BIx::Class::Storage::DBI>.
179 has 'write_handler' => (
192 deployment_statements
213 This class defines the following methods.
217 L<DBIx::Class::Schema> when instantiating it's storage passed itself as the
218 first argument. We need to invoke L</new> on the underlying parent class, make
219 sure we properly give it a L<Moose> meta class, and then correctly instantiate
220 our attributes. Basically we pass on whatever the schema has in it's class
221 data for 'storage_type_args' to our replicated storage type.
226 my $class = shift @_;
227 my $schema = shift @_;
228 my $storage_type_args = shift @_;
229 my $obj = $class->SUPER::new($schema, $storage_type_args, @_);
231 return $class->meta->new_object(
232 __INSTANCE__ => $obj,
240 Lazy builder for the L</master> attribute.
245 DBIx::Class::Storage::DBI->new;
250 Lazy builder for the L</pool> attribute.
258 =head2 _build_balancer
260 Lazy builder for the L</balancer> attribute. This takes a Pool object so that
261 the balancer knows which pool it's balancing.
265 sub _build_balancer {
267 $self->create_balancer(pool=>$self->pool);
270 =head2 _build_write_handler
272 Lazy builder for the L</write_handler> attribute. The default is to set this to
277 sub _build_write_handler {
278 return shift->master;
281 =head2 _build_read_handler
283 Lazy builder for the L</read_handler> attribute. The default is to set this to
288 sub _build_read_handler {
289 return shift->balancer;
292 =head2 around: connect_replicants
294 All calls to connect_replicants needs to have an existing $schema tacked onto
295 top of the args, since L<DBIx::Storage::DBI> needs it.
299 around 'connect_replicants' => sub {
300 my ($method, $self, @args) = @_;
301 $self->$method($self->schema, @args);
306 Returns an array of of all the connected storage backends. The first element
307 in the returned array is the master, and the remainings are each of the
315 return grep {defined $_ && blessed $_} (
321 =head2 set_reliable_storage
323 Sets the current $schema to be 'reliable', that is all queries, both read and
324 write are sent to the master
328 sub set_reliable_storage {
330 my $schema = $self->schema;
331 my $write_handler = $self->schema->storage->write_handler;
333 $schema->storage->read_handler($write_handler);
336 =head2 set_balanced_storage
338 Sets the current $schema to be use the </balancer> for all reads, while all
339 writea are sent to the master only
343 sub set_balanced_storage {
345 my $schema = $self->schema;
346 my $write_handler = $self->schema->storage->balancer;
348 $schema->storage->read_handler($write_handler);
353 Check that the master and at least one of the replicants is connected.
361 $self->master->connected &&
362 $self->pool->connected_replicants;
365 =head2 ensure_connected
367 Make sure all the storages are connected.
371 sub ensure_connected {
373 foreach my $source ($self->all_storages) {
374 $source->ensure_connected(@_);
380 Set the limit_dialect for all existing storages
386 foreach my $source ($self->all_storages) {
387 $source->limit_dialect(@_);
393 Set the quote_char for all existing storages
399 foreach my $source ($self->all_storages) {
400 $source->quote_char(@_);
406 Set the name_sep for all existing storages
412 foreach my $source ($self->all_storages) {
413 $source->name_sep(@_);
419 Set the schema object for all existing storages
425 foreach my $source ($self->all_storages) {
426 $source->set_schema(@_);
432 set a debug flag across all storages
438 foreach my $source ($self->all_storages) {
445 set a debug object across all storages
451 foreach my $source ($self->all_storages) {
452 $source->debugobj(@_);
458 set a debugfh object across all storages
464 foreach my $source ($self->all_storages) {
465 $source->debugfh(@_);
471 set a debug callback across all storages
477 foreach my $source ($self->all_storages) {
478 $source->debugcb(@_);
484 disconnect everything
490 foreach my $source ($self->all_storages) {
491 $source->disconnect(@_);
497 Norbert Csongrádi <bert@cpan.org>
499 Peter Siklósi <einon@einon.hu>
501 John Napiorkowski <john.napiorkowski@takkle.com>
505 You may distribute this code under the same terms as Perl itself.