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