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