From: Rafael Kitover Date: Sat, 9 May 2009 03:31:15 +0000 (+0000) Subject: ::DBI::Replicated - add master_read_weight to ::Random balancer_type X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ee356d004e088518205ac720b37c31a64c9cd861;p=dbsrgits%2FDBIx-Class-Historic.git ::DBI::Replicated - add master_read_weight to ::Random balancer_type --- diff --git a/Makefile.PL b/Makefile.PL index 57b2be4..640e004 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -77,7 +77,7 @@ my %force_requires_if_author = ( , # t/93storage_replication.t - 'Moose', => 0.54, + 'Moose', => 0.77, 'MooseX::AttributeHelpers' => 0.12, 'MooseX::Types', => 0.10, 'namespace::clean' => 0.11, diff --git a/lib/DBIx/Class/Storage/DBI/Replicated.pm b/lib/DBIx/Class/Storage/DBI/Replicated.pm index bed8a1f..d6eb2fd 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated.pm @@ -275,7 +275,6 @@ has 'write_handler' => ( is=>'ro', isa=>Object, lazy_build=>1, - lazy_build=>1, handles=>[qw/ on_connect_do on_disconnect_do @@ -388,7 +387,9 @@ Lazy builder for the L attribute. sub _build_master { my $self = shift @_; - DBIx::Class::Storage::DBI->new($self->schema); + my $master = DBIx::Class::Storage::DBI->new($self->schema); + DBIx::Class::Storage::DBI::Replicated::WithDSN->meta->apply($master); + $master } =head2 _build_pool diff --git a/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/Random.pm b/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/Random.pm index 1e657b5..2b0aef9 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/Random.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated/Balancer/Random.pm @@ -2,6 +2,7 @@ package DBIx::Class::Storage::DBI::Replicated::Balancer::Random; use Moose; with 'DBIx::Class::Storage::DBI::Replicated::Balancer'; +use DBIx::Class::Storage::DBI::Replicated::Types 'Weight'; use namespace::clean -except => 'meta'; =head1 NAME @@ -27,6 +28,17 @@ you, patches welcome. This class defines the following attributes. +=head2 master_read_weight + +A number from 0 to 1 that specifies what weight to give the master when choosing +which backend to execute a read query on. A value of 0, which is the default, +does no reads from master, while a value of 1 gives it the same priority as any +single replicant. + +=cut + +has master_read_weight => (is => 'rw', isa => Weight, default => sub { 0 }); + =head1 METHODS This class defines the following methods. @@ -41,11 +53,24 @@ be requested several times in a row. sub next_storage { my $self = shift @_; - my @active_replicants = $self->pool->active_replicants; - my $count_active_replicants = $#active_replicants +1; - my $random_replicant = int(rand($count_active_replicants)); - - return $active_replicants[$random_replicant]; + + my @replicants = $self->pool->active_replicants; + my $master = $self->master; + + my $rnd = $self->random_number(@replicants + $self->master_read_weight); + + return $rnd >= @replicants ? $master : $replicants[int $rnd]; +} + +=head2 random_number + +Returns a random number from 0 to x, not including x. Uses perl's +L by default. + +=cut + +sub random_number { + rand($_[1]) } =head1 AUTHOR diff --git a/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm b/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm index 9e32ca3..9c9f1c2 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated/Replicant.pm @@ -2,7 +2,8 @@ package DBIx::Class::Storage::DBI::Replicated::Replicant; use Moose::Role; requires qw/_query_start/; -use MooseX::Types::Moose qw/Bool/; +with 'DBIx::Class::Storage::DBI::Replicated::WithDSN'; +use MooseX::Types::Moose 'Bool'; use namespace::clean -except => 'meta'; @@ -55,18 +56,6 @@ has 'active' => ( This class defines the following methods. -=head2 around: _query_start - -advice iof the _query_start method to add more debuggin - -=cut - -around '_query_start' => sub { - my ($method, $self, $sql, @bind) = @_; - my $dsn = $self->_dbi_connect_info->[0]; - $self->$method("DSN: $dsn SQL: $sql", @bind); -}; - =head2 debugobj Override the debugobj method to redirect this method call back to the master. @@ -79,7 +68,8 @@ sub debugobj { =head1 ALSO SEE -L<http://en.wikipedia.org/wiki/Replicant> +L, +L =head1 AUTHOR diff --git a/lib/DBIx/Class/Storage/DBI/Replicated/Types.pm b/lib/DBIx/Class/Storage/DBI/Replicated/Types.pm index c363a4b..b66748f 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated/Types.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated/Types.pm @@ -9,8 +9,8 @@ L =cut use MooseX::Types - -declare => [qw/BalancerClassNamePart/]; -use MooseX::Types::Moose qw/ClassName Str/; + -declare => [qw/BalancerClassNamePart Weight/]; +use MooseX::Types::Moose qw/ClassName Str Num/; class_type 'DBIx::Class::Storage::DBI'; class_type 'DBIx::Class::Schema'; @@ -29,6 +29,11 @@ coerce BalancerClassNamePart, $type; }; +subtype Weight, + as Num, + where { $_ >= 0 && $_ <= 1 }, + message { 'weight must be a decimal between 0 and 1' }; + =head1 AUTHOR John Napiorkowski diff --git a/lib/DBIx/Class/Storage/DBI/Replicated/WithDSN.pm b/lib/DBIx/Class/Storage/DBI/Replicated/WithDSN.pm new file mode 100644 index 0000000..69a3add --- /dev/null +++ b/lib/DBIx/Class/Storage/DBI/Replicated/WithDSN.pm @@ -0,0 +1,51 @@ +package DBIx::Class::Storage::DBI::Replicated::WithDSN; + +use Moose::Role; +requires qw/_query_start/; + +use namespace::clean -except => 'meta'; + +=head1 NAME + +DBIx::Class::Storage::DBI::Replicated::WithDSN - A DBI Storage Role with DSN +information in trace output + +=head1 SYNOPSIS + +This class is used internally by L. + +=head1 DESCRIPTION + +This role adds C info to storage debugging output. + +=head1 METHODS + +This class defines the following methods. + +=head2 around: _query_start + +Add C to debugging output. + +=cut + +around '_query_start' => sub { + my ($method, $self, $sql, @bind) = @_; + my $dsn = $self->_dbi_connect_info->[0]; + $self->$method("DSN: $dsn SQL: $sql", @bind); +}; + +=head1 ALSO SEE + +L + +=head1 AUTHOR + +John Napiorkowski + +=head1 LICENSE + +You may distribute this code under the same terms as Perl itself. + +=cut + +1; diff --git a/t/93storage_replication.t b/t/93storage_replication.t index f96d49b..40c24a5 100644 --- a/t/93storage_replication.t +++ b/t/93storage_replication.t @@ -11,7 +11,7 @@ BEGIN { eval "use DBIx::Class::Storage::DBI::Replicated; use Test::Moose"; plan $@ ? ( skip_all => "Deps not installed: $@" ) - : ( tests => 88 ); + : ( tests => 89 ); } use_ok 'DBIx::Class::Storage::DBI::Replicated::Pool'; @@ -80,6 +80,7 @@ TESTSCHEMACLASSES: { balancer_type=>'::Random', balancer_args=>{ auto_validate_every=>100, + master_read_weight => 1 }, } }, @@ -96,6 +97,7 @@ TESTSCHEMACLASSES: { balancer_type=>'::Random', balancer_args=> { auto_validate_every=>100, + master_read_weight => 1 }, deploy_args=>{ add_drop_table => 1, @@ -356,6 +358,28 @@ isa_ok $artist1 is $artist1->name, 'Ozric Tentacles' => 'Found expected name for first result'; +## Check that master_read_weight is honored +{ + no warnings 'once'; + + # turn off redefined warning + local $SIG{__WARN__} = sub {}; + + local + *DBIx::Class::Storage::DBI::Replicated::Balancer::Random::random_number = + sub { 999 }; + + $replicated->schema->storage->balancer->increment_storage; + + is $replicated->schema->storage->balancer->current_replicant, + $replicated->schema->storage->master + => 'master_read_weight is honored'; + + ## turn it off for the duration of the test + $replicated->schema->storage->balancer->master_read_weight(0); + $replicated->schema->storage->balancer->increment_storage; +} + ## Add some new rows that only the master will have This is because ## we overload any type of write operation so that is must hit the master ## database. @@ -684,3 +708,5 @@ ok $replicated->schema->resultset('Artist')->find(1) ## Delete the old database files $replicated->cleanup; + +# vim: sw=4 sts=4 :