X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBI%2FReplicated%2FBalancer.pm;h=798c0ef556b9e617162a7102b3c07499ccf17e85;hb=41916570b3a93b05746e23b73c9a9b5005bc0d2e;hp=241d66602888d80340a4d5938fdc7e9c963b118d;hpb=64cdad22d9b4022de379ae43174c15ce8dc81b59;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 241d666..798c0ef 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated/Balancer.pm @@ -2,10 +2,13 @@ package DBIx::Class::Storage::DBI::Replicated::Balancer; use Moose::Role; requires 'next_storage'; +use MooseX::Types::Moose qw/Int/; + +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 @@ -31,7 +34,7 @@ validating every query. has 'auto_validate_every' => ( is=>'rw', - isa=>'Int', + isa=>Int, predicate=>'has_auto_validate_every', ); @@ -126,35 +129,57 @@ or just just forgot to create them :) 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->auto_validate_every + $self->pool->last_validated) <= $now - ) { + ) { $self->pool->validate_replicants; } - + ## Get a replicant, or the master if none - my $next = $self->$next_storage(@args); - return $next ? $next:$self->master; + if(my $next = $self->$next_storage(@args)) { + return $next; + } else { + $self->master->debugobj->print("No Replicants validate, falling back to master reads. "); + return $self->master; + } }; -=head2 before: select +=head2 increment_storage -Advice on the select attribute. Each time we use a replicant -we need to change it via the storage pool algorithm. That way we are spreading -the load evenly (hopefully) across existing capacity. +Rolls the Storage to whatever is next in the queue, as defined by the Balancer. =cut -before 'select' => sub { +sub increment_storage { my $self = shift @_; my $next_replicant = $self->next_storage; $self->current_replicant($next_replicant); +} + +=head2 around: select + +Advice on the select attribute. Each time we use a replicant +we need to change it via the storage pool algorithm. That way we are spreading +the load evenly (hopefully) across existing capacity. + +=cut + +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); + } else { + $self->increment_storage; + return $self->$select(@args); + } }; -=head2 before: select_single +=head2 around: select_single Advice on the select_single attribute. Each time we use a replicant we need to change it via the storage pool algorithm. That way we are spreading @@ -162,10 +187,16 @@ the load evenly (hopefully) across existing capacity. =cut -before 'select_single' => sub { - my $self = shift @_; - my $next_replicant = $self->next_storage; - $self->current_replicant($next_replicant); +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); + } else { + $self->increment_storage; + return $self->$select_single(@args); + } }; =head2 before: columns_info_for @@ -178,10 +209,28 @@ the load evenly (hopefully) across existing capacity. before 'columns_info_for' => sub { my $self = shift @_; - my $next_replicant = $self->next_storage; - $self->current_replicant($next_replicant); + $self->increment_storage; }; +=head2 _get_forced_pool ($name) + +Given an identifier, find the most correct storage object to handle the query. + +=cut + +sub _get_forced_pool { + my ($self, $forced_pool) = @_; + if(blessed $forced_pool) { + return $forced_pool; + } elsif($forced_pool eq 'master') { + return $self->master; + } 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