fixed braindead typo in docs telling people to use a version of Moose that does not...
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Replicated.pm
1 package DBIx::Class::Storage::DBI::Replicated;
2
3 BEGIN {
4   use Carp::Clan qw/^DBIx::Class/;
5         
6   ## Modules required for Replication support not required for general DBIC
7   ## use, so we explicitly test for these.
8         
9   my %replication_required = (
10     Moose => '0.54',
11     MooseX::AttributeHelpers => '0.12',
12     Moose::Util::TypeConstraints => '0.54',
13     Class::MOP => '0.63',
14   );
15         
16   my @didnt_load;
17   
18   for my $module (keys %replication_required) {
19         eval "use $module $replication_required{$module}";
20         push @didnt_load, "$module $replication_required{$module}"
21          if $@;
22   }
23         
24   croak("@{[ join ', ', @didnt_load ]} are missing and are required for Replication")
25     if @didnt_load;     
26 }
27
28 use DBIx::Class::Storage::DBI;
29 use DBIx::Class::Storage::DBI::Replicated::Pool;
30 use DBIx::Class::Storage::DBI::Replicated::Balancer;
31
32 =head1 NAME
33
34 DBIx::Class::Storage::DBI::Replicated - BETA Replicated database support
35
36 =head1 SYNOPSIS
37
38 The Following example shows how to change an existing $schema to a replicated
39 storage type, add some replicated (readonly) databases, and perform reporting
40 tasks.
41
42   ## Change storage_type in your schema class
43   $schema->storage_type( ['::DBI::Replicated', {balancer=>'::Random'}] );
44   
45   ## Add some slaves.  Basically this is an array of arrayrefs, where each
46   ## arrayref is database connect information
47   
48   $schema->storage->connect_replicants(
49     [$dsn1, $user, $pass, \%opts],
50     [$dsn2, $user, $pass, \%opts],
51     [$dsn3, $user, $pass, \%opts],
52   );
53   
54   ## Now, just use the $schema as normal
55   $schema->resultset('Source')->search({name=>'etc'});
56   
57   ## You can force a given query to use a particular storage using the search
58   ### attribute 'force_pool'.  For example:
59   
60   my $RS = $schema->resultset('Source')->search(undef, {force_pool=>'master'});
61   
62   ## Now $RS will force everything (both reads and writes) to use whatever was
63   ## setup as the master storage.  'master' is hardcoded to always point to the
64   ## Master, but you can also use any Replicant name.  Please see:
65   ## L<DBIx::Class::Storage::Replicated::Pool> and the replicants attribute for
66   ## More. Also see transactions and L</execute_reliably> for alternative ways
67   ## to force read traffic to the master.
68   
69 =head1 DESCRIPTION
70
71 Warning: This class is marked BETA.  This has been running a production
72 website using MySQL native replication as its backend and we have some decent
73 test coverage but the code hasn't yet been stressed by a variety of databases.
74 Individual DB's may have quirks we are not aware of.  Please use this in first
75 development and pass along your experiences/bug fixes.
76
77 This class implements replicated data store for DBI. Currently you can define
78 one master and numerous slave database connections. All write-type queries
79 (INSERT, UPDATE, DELETE and even LAST_INSERT_ID) are routed to master
80 database, all read-type queries (SELECTs) go to the slave database.
81
82 Basically, any method request that L<DBIx::Class::Storage::DBI> would normally
83 handle gets delegated to one of the two attributes: L</read_handler> or to
84 L</write_handler>.  Additionally, some methods need to be distributed
85 to all existing storages.  This way our storage class is a drop in replacement
86 for L<DBIx::Class::Storage::DBI>.
87
88 Read traffic is spread across the replicants (slaves) occuring to a user
89 selected algorithm.  The default algorithm is random weighted.
90
91 =head1 NOTES
92
93 The consistancy betweeen master and replicants is database specific.  The Pool
94 gives you a method to validate it's replicants, removing and replacing them
95 when they fail/pass predefined criteria.  Please make careful use of the ways
96 to force a query to run against Master when needed.
97
98 =head1 REQUIREMENTS
99
100 Replicated Storage has additional requirements not currently part of L<DBIx::Class>
101
102   Moose => 0.54
103   MooseX::AttributeHelpers => 0.12 
104   Moose::Util::TypeConstraints => 0.54
105   Class::MOP => 0.63
106   
107 You will need to install these modules manually via CPAN or make them part of the
108 Makefile for your distribution.
109
110 =head1 ATTRIBUTES
111
112 This class defines the following attributes.
113
114 =head2 schema
115
116 The underlying L<DBIx::Class::Schema> object this storage is attaching
117
118 =cut
119
120 has 'schema' => (
121     is=>'rw',
122     isa=>'DBIx::Class::Schema',
123     weak_ref=>1,
124     required=>1,
125 );
126
127 =head2 pool_type
128
129 Contains the classname which will instantiate the L</pool> object.  Defaults 
130 to: L<DBIx::Class::Storage::DBI::Replicated::Pool>.
131
132 =cut
133
134 has 'pool_type' => (
135   is=>'ro',
136   isa=>'ClassName',
137   required=>1,
138   default=>'DBIx::Class::Storage::DBI::Replicated::Pool',
139   handles=>{
140     'create_pool' => 'new',
141   },
142 );
143
144 =head2 pool_args
145
146 Contains a hashref of initialized information to pass to the Balancer object.
147 See L<DBIx::Class::Storage::Replicated::Pool> for available arguments.
148
149 =cut
150
151 has 'pool_args' => (
152   is=>'ro',
153   isa=>'HashRef',
154   lazy=>1,
155   required=>1,
156   default=>sub { {} },
157 );
158
159
160 =head2 balancer_type
161
162 The replication pool requires a balance class to provider the methods for
163 choose how to spread the query load across each replicant in the pool.
164
165 =cut
166
167 subtype 'DBIx::Class::Storage::DBI::Replicated::BalancerClassNamePart',
168   as 'ClassName';
169     
170 coerce 'DBIx::Class::Storage::DBI::Replicated::BalancerClassNamePart',
171   from 'Str',
172   via {
173         my $type = $_;
174     if($type=~m/^::/) {
175       $type = 'DBIx::Class::Storage::DBI::Replicated::Balancer'.$type;
176     }  
177     Class::MOP::load_class($type);  
178     $type;      
179   };
180
181 has 'balancer_type' => (
182   is=>'ro',
183   isa=>'DBIx::Class::Storage::DBI::Replicated::BalancerClassNamePart',
184   coerce=>1,
185   required=>1,
186   default=> 'DBIx::Class::Storage::DBI::Replicated::Balancer::First',
187   handles=>{
188     'create_balancer' => 'new',
189   },
190 );
191
192 =head2 balancer_args
193
194 Contains a hashref of initialized information to pass to the Balancer object.
195 See L<DBIx::Class::Storage::Replicated::Balancer> for available arguments.
196
197 =cut
198
199 has 'balancer_args' => (
200   is=>'ro',
201   isa=>'HashRef',
202   lazy=>1,
203   required=>1,
204   default=>sub { {} },
205 );
206
207 =head2 pool
208
209 Is a <DBIx::Class::Storage::DBI::Replicated::Pool> or derived class.  This is a
210 container class for one or more replicated databases.
211
212 =cut
213
214 has 'pool' => (
215   is=>'ro',
216   isa=>'DBIx::Class::Storage::DBI::Replicated::Pool',
217   lazy_build=>1,
218   handles=>[qw/
219     connect_replicants    
220     replicants
221     has_replicants
222   /],
223 );
224
225 =head2 balancer
226
227 Is a <DBIx::Class::Storage::DBI::Replicated::Balancer> or derived class.  This 
228 is a class that takes a pool (<DBIx::Class::Storage::DBI::Replicated::Pool>)
229
230 =cut
231
232 has 'balancer' => (
233   is=>'ro',
234   isa=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
235   lazy_build=>1,
236   handles=>[qw/auto_validate_every/],
237 );
238
239 =head2 master
240
241 The master defines the canonical state for a pool of connected databases.  All
242 the replicants are expected to match this databases state.  Thus, in a classic
243 Master / Slaves distributed system, all the slaves are expected to replicate
244 the Master's state as quick as possible.  This is the only database in the
245 pool of databases that is allowed to handle write traffic.
246
247 =cut
248
249 has 'master' => (
250   is=> 'ro',
251   isa=>'DBIx::Class::Storage::DBI',
252   lazy_build=>1,
253 );
254
255 =head1 ATTRIBUTES IMPLEMENTING THE DBIx::Storage::DBI INTERFACE
256
257 The following methods are delegated all the methods required for the 
258 L<DBIx::Class::Storage::DBI> interface.
259
260 =head2 read_handler
261
262 Defines an object that implements the read side of L<BIx::Class::Storage::DBI>.
263
264 =cut
265
266 has 'read_handler' => (
267   is=>'rw',
268   isa=>'Object',
269   lazy_build=>1,
270   handles=>[qw/
271     select
272     select_single
273     columns_info_for
274   /],    
275 );
276
277 =head2 write_handler
278
279 Defines an object that implements the write side of L<BIx::Class::Storage::DBI>.
280
281 =cut
282
283 has 'write_handler' => (
284   is=>'ro',
285   isa=>'Object',
286   lazy_build=>1,
287   lazy_build=>1,
288   handles=>[qw/   
289     on_connect_do
290     on_disconnect_do       
291     connect_info
292     throw_exception
293     sql_maker
294     sqlt_type
295     create_ddl_dir
296     deployment_statements
297     datetime_parser
298     datetime_parser_type        
299     last_insert_id
300     insert
301     insert_bulk
302     update
303     delete
304     dbh
305     txn_begin
306     txn_do
307     txn_commit
308     txn_rollback
309     txn_scope_guard
310     sth
311     deploy
312     with_deferred_fk_checks
313
314     reload_row
315     _prep_for_execute
316     configure_sqlt
317     
318   /],
319 );
320
321 =head1 METHODS
322
323 This class defines the following methods.
324
325 =head2 BUILDARGS
326
327 L<DBIx::Class::Schema> when instantiating it's storage passed itself as the
328 first argument.  So we need to massage the arguments a bit so that all the
329 bits get put into the correct places.
330
331 =cut
332
333 sub BUILDARGS {
334   my ($class, $schema, $storage_type_args, @args) = @_; 
335   
336   return {
337         schema=>$schema, 
338         %$storage_type_args,
339         @args
340   }
341 }
342
343 =head2 _build_master
344
345 Lazy builder for the L</master> attribute.
346
347 =cut
348
349 sub _build_master {
350   my $self = shift @_;
351   DBIx::Class::Storage::DBI->new($self->schema);
352 }
353
354 =head2 _build_pool
355
356 Lazy builder for the L</pool> attribute.
357
358 =cut
359
360 sub _build_pool {
361   my $self = shift @_;
362   $self->create_pool(%{$self->pool_args});
363 }
364
365 =head2 _build_balancer
366
367 Lazy builder for the L</balancer> attribute.  This takes a Pool object so that
368 the balancer knows which pool it's balancing.
369
370 =cut
371
372 sub _build_balancer {
373   my $self = shift @_;
374   $self->create_balancer(
375     pool=>$self->pool, 
376     master=>$self->master,
377     %{$self->balancer_args},
378   );
379 }
380
381 =head2 _build_write_handler
382
383 Lazy builder for the L</write_handler> attribute.  The default is to set this to
384 the L</master>.
385
386 =cut
387
388 sub _build_write_handler {
389   return shift->master;
390 }
391
392 =head2 _build_read_handler
393
394 Lazy builder for the L</read_handler> attribute.  The default is to set this to
395 the L</balancer>.
396
397 =cut
398
399 sub _build_read_handler {
400   return shift->balancer;
401 }
402
403 =head2 around: connect_replicants
404
405 All calls to connect_replicants needs to have an existing $schema tacked onto
406 top of the args, since L<DBIx::Storage::DBI> needs it.
407
408 =cut
409
410 around 'connect_replicants' => sub {
411   my ($method, $self, @args) = @_;
412   $self->$method($self->schema, @args);
413 };
414
415 =head2 all_storages
416
417 Returns an array of of all the connected storage backends.  The first element
418 in the returned array is the master, and the remainings are each of the
419 replicants.
420
421 =cut
422
423 sub all_storages {
424   my $self = shift @_;
425   return grep {defined $_ && blessed $_} (
426      $self->master,
427      $self->replicants,
428   );
429 }
430
431 =head2 execute_reliably ($coderef, ?@args)
432
433 Given a coderef, saves the current state of the L</read_handler>, forces it to
434 use reliable storage (ie sets it to the master), executes a coderef and then
435 restores the original state.
436
437 Example:
438
439   my $reliably = sub {
440     my $name = shift @_;
441     $schema->resultset('User')->create({name=>$name});
442     my $user_rs = $schema->resultset('User')->find({name=>$name}); 
443     return $user_rs;
444   };
445
446   my $user_rs = $schema->storage->execute_reliably($reliably, 'John');
447
448 Use this when you must be certain of your database state, such as when you just
449 inserted something and need to get a resultset including it, etc.
450
451 =cut
452
453 sub execute_reliably {
454   my ($self, $coderef, @args) = @_;
455   
456   unless( ref $coderef eq 'CODE') {
457     $self->throw_exception('Second argument must be a coderef');
458   }
459   
460   ##Get copy of master storage
461   my $master = $self->master;
462   
463   ##Get whatever the current read hander is
464   my $current = $self->read_handler;
465   
466   ##Set the read handler to master
467   $self->read_handler($master);
468   
469   ## do whatever the caller needs
470   my @result;
471   my $want_array = wantarray;
472   
473   eval {
474     if($want_array) {
475       @result = $coderef->(@args);
476     } elsif(defined $want_array) {
477       ($result[0]) = ($coderef->(@args));
478     } else {
479       $coderef->(@args);
480     }       
481   };
482   
483   ##Reset to the original state
484   $self->read_handler($current); 
485   
486   ##Exception testing has to come last, otherwise you might leave the 
487   ##read_handler set to master.
488   
489   if($@) {
490     $self->throw_exception("coderef returned an error: $@");
491   } else {
492     return $want_array ? @result : $result[0];
493   }
494 }
495
496 =head2 set_reliable_storage
497
498 Sets the current $schema to be 'reliable', that is all queries, both read and
499 write are sent to the master
500   
501 =cut
502
503 sub set_reliable_storage {
504   my $self = shift @_;
505   my $schema = $self->schema;
506   my $write_handler = $self->schema->storage->write_handler;
507   
508   $schema->storage->read_handler($write_handler);
509 }
510
511 =head2 set_balanced_storage
512
513 Sets the current $schema to be use the </balancer> for all reads, while all
514 writea are sent to the master only
515   
516 =cut
517
518 sub set_balanced_storage {
519   my $self = shift @_;
520   my $schema = $self->schema;
521   my $write_handler = $self->schema->storage->balancer;
522   
523   $schema->storage->read_handler($write_handler);
524 }
525
526 =head2 around: txn_do ($coderef)
527
528 Overload to the txn_do method, which is delegated to whatever the
529 L<write_handler> is set to.  We overload this in order to wrap in inside a
530 L</execute_reliably> method.
531
532 =cut
533
534 around 'txn_do' => sub {
535   my($txn_do, $self, $coderef, @args) = @_;
536   $self->execute_reliably(sub {$self->$txn_do($coderef, @args)}); 
537 };
538
539 =head2 connected
540
541 Check that the master and at least one of the replicants is connected.
542
543 =cut
544
545 sub connected {
546   my $self = shift @_;
547   return
548     $self->master->connected &&
549     $self->pool->connected_replicants;
550 }
551
552 =head2 ensure_connected
553
554 Make sure all the storages are connected.
555
556 =cut
557
558 sub ensure_connected {
559   my $self = shift @_;
560   foreach my $source ($self->all_storages) {
561     $source->ensure_connected(@_);
562   }
563 }
564
565 =head2 limit_dialect
566
567 Set the limit_dialect for all existing storages
568
569 =cut
570
571 sub limit_dialect {
572   my $self = shift @_;
573   foreach my $source ($self->all_storages) {
574     $source->limit_dialect(@_);
575   }
576   return $self->master->quote_char;
577 }
578
579 =head2 quote_char
580
581 Set the quote_char for all existing storages
582
583 =cut
584
585 sub quote_char {
586   my $self = shift @_;
587   foreach my $source ($self->all_storages) {
588     $source->quote_char(@_);
589   }
590   return $self->master->quote_char;
591 }
592
593 =head2 name_sep
594
595 Set the name_sep for all existing storages
596
597 =cut
598
599 sub name_sep {
600   my $self = shift @_;
601   foreach my $source ($self->all_storages) {
602     $source->name_sep(@_);
603   }
604   return $self->master->name_sep;
605 }
606
607 =head2 set_schema
608
609 Set the schema object for all existing storages
610
611 =cut
612
613 sub set_schema {
614   my $self = shift @_;
615   foreach my $source ($self->all_storages) {
616     $source->set_schema(@_);
617   }
618 }
619
620 =head2 debug
621
622 set a debug flag across all storages
623
624 =cut
625
626 sub debug {
627   my $self = shift @_;
628   if(@_) {
629     foreach my $source ($self->all_storages) {
630       $source->debug(@_);
631     }   
632   }
633   return $self->master->debug;
634 }
635
636 =head2 debugobj
637
638 set a debug object across all storages
639
640 =cut
641
642 sub debugobj {
643   my $self = shift @_;
644   if(@_) {
645     foreach my $source ($self->all_storages) {
646       $source->debugobj(@_);
647     }   
648   }
649   return $self->master->debugobj;
650 }
651
652 =head2 debugfh
653
654 set a debugfh object across all storages
655
656 =cut
657
658 sub debugfh {
659   my $self = shift @_;
660   if(@_) {
661     foreach my $source ($self->all_storages) {
662       $source->debugfh(@_);
663     }   
664   }
665   return $self->master->debugfh;
666 }
667
668 =head2 debugcb
669
670 set a debug callback across all storages
671
672 =cut
673
674 sub debugcb {
675   my $self = shift @_;
676   if(@_) {
677     foreach my $source ($self->all_storages) {
678       $source->debugcb(@_);
679     }   
680   }
681   return $self->master->debugcb;
682 }
683
684 =head2 disconnect
685
686 disconnect everything
687
688 =cut
689
690 sub disconnect {
691   my $self = shift @_;
692   foreach my $source ($self->all_storages) {
693     $source->disconnect(@_);
694   }
695 }
696
697 =head1 GOTCHAS
698
699 Due to the fact that replicants can lag behind a master, you must take care to
700 make sure you use one of the methods to force read queries to a master should
701 you need realtime data integrity.  For example, if you insert a row, and then
702 immediately re-read it from the database (say, by doing $row->discard_changes)
703 or you insert a row and then immediately build a query that expects that row
704 to be an item, you should force the master to handle reads.  Otherwise, due to
705 the lag, there is no certainty your data will be in the expected state.
706
707 For data integrity, all transactions automatically use the master storage for
708 all read and write queries.  Using a transaction is the preferred and recommended
709 method to force the master to handle all read queries.
710
711 Otherwise, you can force a single query to use the master with the 'force_pool'
712 attribute:
713
714   my $row = $resultset->search(undef, {force_pool=>'master'})->find($pk);
715
716 This attribute will safely be ignore by non replicated storages, so you can use
717 the same code for both types of systems.
718
719 Lastly, you can use the L</execute_reliably> method, which works very much like
720 a transaction.
721
722 For debugging, you can turn replication on/off with the methods L</set_reliable_storage>
723 and L</set_balanced_storage>, however this operates at a global level and is not
724 suitable if you have a shared Schema object being used by multiple processes,
725 such as on a web application server.  You can get around this limitation by
726 using the Schema clone method.
727
728   my $new_schema = $schema->clone;
729   $new_schema->set_reliable_storage;
730   
731   ## $new_schema will use only the Master storage for all reads/writes while
732   ## the $schema object will use replicated storage.
733
734 =head1 AUTHOR
735
736   John Napiorkowski <john.napiorkowski@takkle.com>
737
738 Based on code originated by:
739
740   Norbert Csongrádi <bert@cpan.org>
741   Peter Siklósi <einon@einon.hu>
742
743 =head1 LICENSE
744
745 You may distribute this code under the same terms as Perl itself.
746
747 =cut
748
749 __PACKAGE__->meta->make_immutable;
750
751 1;