X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI%2FReplicated%2FBalancer.pm;h=82d3b6ae6fa45099e58ae95525a00a28e8184946;hb=8273e845426f0187b4ad6c4a1b42286fa09a648f;hp=5021ed9686a9652d884192b2de4696de4ba0835f;hpb=21fc471939bf782a3ae38f8c71a4563fe50592d3;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm b/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm index 5021ed9..82d3b6a 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm @@ -2,15 +2,19 @@ package DBIx::Class::Storage::DBI::Replicated::Balancer; use Moose::Role; requires 'next_storage'; +use MooseX::Types::Moose qw/Int/; +use DBIx::Class::Storage::DBI::Replicated::Pool; +use DBIx::Class::Storage::DBI::Replicated::Types qw/DBICStorageDBI/; +use namespace::clean -except => 'meta'; =head1 NAME -DBIx::Class::Storage::DBI::Replicated::Balancer - A Software Load Balancer +DBIx::Class::Storage::DBI::Replicated::Balancer - A Software Load Balancer =head1 SYNOPSIS This role is used internally by L. - + =head1 DESCRIPTION Given a pool (L) of replicated @@ -23,15 +27,16 @@ This class defines the following attributes. =head2 auto_validate_every ($seconds) -If auto_validate has some sort of value, run the L every -$seconds. Be careful with this, because if you set it to 0 you will end up -validating every query. +If auto_validate has some sort of value, run +L +every $seconds. Be careful with this, because if you set it to 0 you +will end up validating every query. =cut has 'auto_validate_every' => ( is=>'rw', - isa=>'Int', + isa=>Int, predicate=>'has_auto_validate_every', ); @@ -45,7 +50,7 @@ ultimate fallback. has 'master' => ( is=>'ro', - isa=>'DBIx::Class::Storage::DBI', + isa=>DBICStorageDBI, required=>1, ); @@ -66,18 +71,18 @@ has 'pool' => ( Replicant storages (slaves) handle all read only traffic. The assumption is that your database will become readbound well before it becomes write bound -and that being able to spread your read only traffic around to multiple +and that being able to spread your read only traffic around to multiple databases is going to help you to scale traffic. This attribute returns the next slave to handle a read request. Your L attribute has methods to help you shuffle through all the available replicants -via it's balancer object. +via its balancer object. =cut has 'current_replicant' => ( is=> 'rw', - isa=>'DBIx::Class::Storage::DBI', + isa=>DBICStorageDBI, lazy_build=>1, handles=>[qw/ select @@ -106,8 +111,8 @@ sub _build_current_replicant { This method should be defined in the class which consumes this role. Given a pool object, return the next replicant that will serve queries. The -default behavior is to grap the first replicant it finds but you can write -your own subclasses of L to +default behavior is to grab the first replicant it finds but you can write +your own subclasses of L to support other balance systems. This returns from the pool of active replicants. If there are no active @@ -123,22 +128,29 @@ or just just forgot to create them :) =cut +my $on_master; + around 'next_storage' => sub { my ($next_storage, $self, @args) = @_; my $now = time; - + ## Do we need to validate the replicants? if( - $self->has_auto_validate_every && + $self->has_auto_validate_every && ($self->auto_validate_every + $self->pool->last_validated) <= $now ) { $self->pool->validate_replicants; } - + ## Get a replicant, or the master if none if(my $next = $self->$next_storage(@args)) { + $self->master->debugobj->print("Moved back to slave\n") if $on_master; + $on_master = 0; return $next; } else { + $self->master->debugobj->print("No Replicants validate, falling back to master reads.\n") + unless $on_master++; + return $self->master; } }; @@ -165,10 +177,12 @@ the load evenly (hopefully) across existing capacity. around 'select' => sub { my ($select, $self, @args) = @_; - + if (my $forced_pool = $args[-1]->{force_pool}) { delete $args[-1]->{force_pool}; - return $self->_get_forced_pool($forced_pool)->select(@args); + return $self->_get_forced_pool($forced_pool)->select(@args); + } elsif($self->master->{transaction_depth}) { + return $self->master->select(@args); } else { $self->increment_storage; return $self->$select(@args); @@ -185,10 +199,12 @@ the load evenly (hopefully) across existing capacity. around 'select_single' => sub { my ($select_single, $self, @args) = @_; - + if (my $forced_pool = $args[-1]->{force_pool}) { delete $args[-1]->{force_pool}; - return $self->_get_forced_pool($forced_pool)->select_single(@args); + return $self->_get_forced_pool($forced_pool)->select_single(@args); + } elsif($self->master->{transaction_depth}) { + return $self->master->select_single(@args); } else { $self->increment_storage; return $self->$select_single(@args); @@ -220,16 +236,16 @@ sub _get_forced_pool { return $forced_pool; } elsif($forced_pool eq 'master') { return $self->master; - } elsif(my $replicant = $self->pool->replicants($forced_pool)) { + } elsif(my $replicant = $self->pool->replicants->{$forced_pool}) { return $replicant; } else { $self->master->throw_exception("$forced_pool is not a named replicant."); - } + } } =head1 AUTHOR -John Napiorkowski +John Napiorkowski =head1 LICENSE