package DBIx::Class::Storage::DBI::Replicated;
use Moose;
+use DBIx::Class::Storage::DBI;
use DBIx::Class::Storage::DBI::Replicated::Pool;
+use DBIx::Class::Storage::DBI::Replicated::Balancer;
+use Scalar::Util qw(blessed);
-#extends 'DBIx::Class::Storage::DBI', 'Moose::Object';
+extends 'DBIx::Class::Storage::DBI', 'Moose::Object';
=head1 NAME
The Following example shows how to change an existing $schema to a replicated
storage type, add some replicated (readonly) databases, and perform reporting
-tasks
+tasks.
## Change storage_type in your schema class
$schema->storage_type( '::DBI::Replicated' );
## Add some slaves. Basically this is an array of arrayrefs, where each
## arrayref is database connect information
- $schema->storage->create_replicants(
+ $schema->storage->connect_replicants(
[$dsn1, $user, $pass, \%opts],
[$dsn1, $user, $pass, \%opts],
[$dsn1, $user, $pass, \%opts],
- ## This is just going to use the standard DBIC connect method, so it
- ## supports everything that method supports, such as connecting to an
- ## existing database handle.
- [$dbh],
- \%global_opts
);
- ## a hash of replicants, keyed by their DSN
- my %replicants = $schema->storage->replicants;
- my $replicant = $schema->storage->get_replicant($dsn);
- $replicant->status;
- $replicant->is_active;
- $replicant->active;
-
=head1 DESCRIPTION
Warning: This class is marked ALPHA. We are using this in development and have
handles=>[qw/
on_connect_do
on_disconnect_do
- columns_info_for
connect_info
throw_exception
sql_maker
txn_rollback
sth
deploy
+ schema
/],
);
attribute has methods to help you shuffle through all the available replicants
via it's balancer object.
-This attribute defines the following reader/writer methods
-
-=over 4
-
-=item get_current_replicant
-
-Returns the contained L<DBIx::Class::Storage::DBI> replicant
-
-=item set_current_replicant
-
-Set the attribute to a given L<DBIx::Class::Storage::DBI> (or subclass) object.
-
-=back
-
We split the reader/writer to make it easier to selectively override how the
replicant is altered.
has 'current_replicant' => (
is=> 'rw',
- reader=>'get_current_replicant',
- writer=>'set_current_replicant',
isa=>'DBIx::Class::Storage::DBI',
lazy_build=>1,
handles=>[qw/
);
-=head2 replicant_storage_pool_type
+=head2 pool_type
-Contains the classname which will instantiate the L</replicant_storage_pool>
-object. Defaults to: L<DBIx::Class::Storage::DBI::Replicated::Pool>.
+Contains the classname which will instantiate the L</pool> object. Defaults
+to: L<DBIx::Class::Storage::DBI::Replicated::Pool>.
=cut
-has 'replicant_storage_pool_type' => (
+has 'pool_type' => (
is=>'ro',
isa=>'ClassName',
required=>1,
+ lazy=>1,
default=>'DBIx::Class::Storage::DBI::Replicated::Pool',
- handles=> {
- 'create_replicant_storage_pool' => 'new',
+ handles=>{
+ 'create_pool' => 'new',
},
);
-=head2 pool_balancer_type
+=head2 balancer_type
The replication pool requires a balance class to provider the methods for
choose how to spread the query load across each replicant in the pool.
=cut
-has 'pool_balancer_type' => (
+has 'balancer_type' => (
is=>'ro',
isa=>'ClassName',
required=>1,
- default=>'DBIx::Class::Storage::DBI::Replicated::Pool::Balancer',
- handles=> {
- 'create_replicant_storage_pool' => 'new',
+ lazy=>1,
+ default=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
+ handles=>{
+ 'create_balancer' => 'new',
},
);
-=head2 replicant_storage_pool
+=head2 pool
-Holds the list of connected replicants, their status and other housekeeping or
-reporting methods.
+Is a <DBIx::Class::Storage::DBI::Replicated::Pool> or derived class. This is a
+container class for one or more replicated databases.
=cut
-has 'replicant_storage_pool' => (
+has 'pool' => (
is=>'ro',
isa=>'DBIx::Class::Storage::DBI::Replicated::Pool',
lazy_build=>1,
- handles=>[qw/replicant_storages/],
+ handles=>[qw/
+ replicants
+ has_replicants
+ connect_replicants
+ num_replicants
+ delete_replicant
+ /],
);
+=head2 balancer
+
+Is a <DBIx::Class::Storage::DBI::Replicated::Balancer> or derived class. This
+is a class that takes a pool (<DBIx::Class::Storage::DBI::Replicated::Pool>)
+
+=cut
+
+has 'balancer' => (
+ is=>'ro',
+ isa=>'DBIx::Class::Storage::DBI::Replicated::Balancer',
+ lazy_build=>1,
+ handles=>[qw/next_storage/],
+);
=head1 METHODS
This class defines the following methods.
-=head2 new
+=head2 _build_master
-Make sure we properly inherit from L<Moose>.
+Lazy builder for the L</master> attribute.
=cut
-sub new {
- my $class = shift @_;
- my $obj = $class->SUPER::new(@_);
-
- return $class->meta->new_object(
- __INSTANCE__ => $obj, @_
- );
+sub _build_master {
+ DBIx::Class::Storage::DBI->new;
}
-=head2 _build_master_storage
-Lazy builder for the L</master_storage> attribute.
+=head2 _build_current_replicant
+
+Lazy builder for the L</current_replicant_storage> attribute.
=cut
-sub _build_next_replicant_storage {
- DBIx::Class::Storage::DBI->new;
+sub _build_current_replicant {
+ my $self = shift @_;
+ $self->next_storage($self->pool);
}
-=head2 _build_current_replicant_storage
+=head2 _build_pool
-Lazy builder for the L</current_replicant_storage> attribute.
+Lazy builder for the L</pool> attribute.
=cut
-sub _build_current_replicant_storage {
- shift->replicant_storage_pool->first;
+sub _build_pool {
+ my $self = shift @_;
+ $self->create_pool;
}
-=head2 _build_replicant_storage_pool
+=head2 _build_balancer
-Lazy builder for the L</replicant_storage_pool> attribute.
+Lazy builder for the L</balancer> attribute.
=cut
-sub _build_replicant_storage_pool {
+sub _build_balancer {
my $self = shift @_;
- $self->create_replicant_storage_pool;
+ $self->create_balancer;
}
-=head2 around: create_replicant_storage_pool
+=head2 around: create_replicants
-Make sure all calles to the method set a default balancer type to our current
-balancer type.
+All calls to create_replicants needs to have an existing $schema tacked onto
+top of the args
=cut
-around 'create_replicant_storage_pool' => sub {
- my ($method, $self, @args) = @_;
- return $self->$method(balancer_type=>$self->pool_balancer_type, @args);
-}
+around 'connect_replicants' => sub {
+ my ($method, $self, @args) = @_;
+ $self->$method($self->schema, @args);
+};
-=head2 after: get_current_replicant_storage
+=head2 after: select, select_single, columns_info_for
Advice on the current_replicant_storage attribute. Each time we use a replicant
we need to change it via the storage pool algorithm. That way we are spreading
=cut
-after 'get_current_replicant_storage' => sub {
+after 'select' => sub {
my $self = shift @_;
- my $next_replicant = $self->replicant_storage_pool->next;
- $self->next_replicant_storage($next_replicant);
-};
+ my $next_replicant = $self->next_storage($self->pool);
+ $self->current_replicant($next_replicant);
+};
-=head2 find_or_create
+after 'select_single' => sub {
+ my $self = shift @_;
+ my $next_replicant = $self->next_storage($self->pool);
-First do a find on the replicant. If no rows are found, pass it on to the
-L</master_storage>
+ $self->current_replicant($next_replicant);
+};
-=cut
+after 'columns_info_for' => sub {
+ my $self = shift @_;
+ my $next_replicant = $self->next_storage($self->pool);
-sub find_or_create {
- my $self = shift @_;
-}
+ $self->current_replicant($next_replicant);
+};
=head2 all_storages
sub all_storages {
my $self = shift @_;
- return (
- $self->master_storage,
- $self->replicant_storages,
+ return grep {defined $_ && blessed $_} (
+ $self->master,
+ $self->replicants,
);
}
my $self = shift @_;
return
- $self->master_storage->connected &&
- $self->replicant_storage_pool->has_connected_slaves;
+ $self->master->connected &&
+ $self->pool->connected_replicants;
}
sub ensure_connected {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->ensure_connected(@_);
}
}
sub limit_dialect {
my $self = shift @_;
- foreach $source (shift->all_sources) {
- $source->name_sep(@_);
+ foreach my $source ($self->all_storages) {
+ $source->limit_dialect(@_);
}
}
sub quote_char {
my $self = shift @_;
- foreach $source (shift->all_sources) {
- $source->name_sep(@_);
+ foreach my $source ($self->all_storages) {
+ $source->quote_char(@_);
}
}
sub name_sep {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->name_sep(@_);
}
}
sub set_schema {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->set_schema(@_);
}
}
sub debug {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->debug(@_);
}
}
sub debugobj {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->debugobj(@_);
}
}
sub debugfh {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->debugfh(@_);
}
}
sub debugcb {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->debugcb(@_);
}
}
sub disconnect {
my $self = shift @_;
- foreach $source (shift->all_sources) {
+ foreach my $source ($self->all_storages) {
$source->disconnect(@_);
}
}
## Other standard DBI connection or DBD custom attributes added as
## usual. Additionally, we have two custom attributes for defining
## slave information and controlling how the underlying DBD::Multi
- slaves_connect_info => [
+ connect_replicants => [
## Define each slave like a 'normal' DBI connection, but you add
## in a DBD::Multi custom attribute to define how the slave is
## prioritized. Please see DBD::Multi for more.
- [$slave1dsn, $user, $password, {%slave1opts, priority=>10}],
- [$slave2dsn, $user, $password, {%slave2opts, priority=>10}],
- [$slave3dsn, $user, $password, {%slave3opts, priority=>20}],
- ## add in a preexisting database handle
- [$dbh, '','', {priority=>30}],
- ## DBD::Multi will call this coderef for connects
- [sub { DBI->connect(< DSN info >) }, '', '', {priority=>40}],
- ## If the last item is hashref, we use that for DBD::Multi's
- ## configuration information. Again, see DBD::Multi for more.
- {timeout=>25, failed_max=>2},
+ [$slave1dsn, $user, $password, {%slave1opts}],
+ [$slave2dsn, $user, $password, {%slave2opts}],
+ [$slave3dsn, $user, $password, {%slave3opts}],
],
},
);