package DBIx::Class::Storage::DBI::Replicated::Pool;
-use Moose;
-use MooseX::AttributeHelpers;
+use Moo;
use DBIx::Class::Storage::DBI::Replicated::Replicant;
use List::Util 'sum';
use Scalar::Util 'reftype';
use DBI ();
-use Carp::Clan qw/^DBIx::Class/;
-use MooseX::Types::Moose qw/Num Int ClassName HashRef/;
+use Types::Standard qw/Num Int ClassName HashRef Object/;
+use DBIx::Class::Storage::DBI::Replicated::Types 'DBICStorageDBI';
+use Try::Tiny;
use namespace::clean -except => 'meta';
=head1 DESCRIPTION
In a replicated storage type, there is at least one replicant to handle the
-read only traffic. The Pool class manages this replicant, or list of
+read-only traffic. The Pool class manages this replicant, or list of
replicants, and gives some methods for querying information about their status.
=head1 ATTRIBUTES
has 'maximum_lag' => (
is=>'rw',
isa=>Num,
- required=>1,
lazy=>1,
default=>0,
);
This is an integer representing a time since the last time the replicants were
validated. It's nothing fancy, just an integer provided via the perl L<time|perlfunc/time>
-builtin.
+built-in.
=cut
default=>'DBIx::Class::Storage::DBI',
handles=>{
'create_replicant' => 'new',
- },
+ },
);
=head2 replicants
A hashref of replicant, with the key being the dsn and the value returning the
-actual replicant storage. For example if the $dsn element is something like:
+actual replicant storage. For example, if the $dsn element is something like:
"dbi:SQLite:dbname=dbfile"
=item delete_replicant ($key)
-removes the replicant under $key from the pool
+Removes the replicant under $key from the pool
=back
has 'replicants' => (
is=>'rw',
- metaclass => 'Collection::Hash',
- isa=>HashRef['Object'],
+ isa=>HashRef[Object],
default=>sub {{}},
- provides => {
- 'set' => 'set_replicant',
- 'get' => 'get_replicant',
- 'empty' => 'has_replicants',
- 'count' => 'num_replicants',
- 'delete' => 'delete_replicant',
- 'values' => 'all_replicant_storages',
- },
);
+sub set_replicant { $_[0]->replicants->{$_[1]} = $_[2] }
+sub get_replicant { $_[0]->replicants->{$_[1]} }
+sub has_replicants { !!keys %{$_[0]->replicants} }
+sub num_replicants { 0+keys %{$_[0]->replicants} }
+sub delete_replicant { delete $_[0]->replicants->{$_[1]} }
+sub all_replicant_storages { values %{$_[0]->replicants} }
+
has next_unknown_replicant_id => (
is => 'rw',
- metaclass => 'Counter',
isa => Int,
default => 1,
- provides => {
- inc => 'inc_unknown_replicant_id'
- },
);
+sub inc_unknown_replicant_id {
+ my ($self) = @_;
+ $self->next_unknown_replicant_id($self->next_unknown_replicant_id + 1);
+}
+
+=head2 master
+
+Reference to the master Storage.
+
+=cut
+
+has master => (is => 'rw', isa => DBICStorageDBI, weak_ref => 1);
+
=head1 METHODS
This class defines the following methods.
}
$replicant->id($key);
- $self->set_replicant($key => $replicant);
+ $self->set_replicant($key => $replicant);
push @newly_created, $replicant;
}
$replicant->_determine_driver
});
- DBIx::Class::Storage::DBI::Replicated::Replicant->meta->apply($replicant);
+ Moo::Role->apply_roles_to_object(
+ $replicant,
+ 'DBIx::Class::Storage::DBI::Replicated::Replicant',
+ );
+
+ # link back to master
+ $replicant->master($self->master);
+
return $replicant;
}
connect. For the master database this is desirable, but since replicants are
allowed to fail, this behavior is not desirable. This method wraps the call
to ensure_connected in an eval in order to catch any generated errors. That
-way a slave can go completely offline (ie, the box itself can die) without
+way a slave can go completely offline (e.g. the box itself can die) without
bringing down your entire pool of databases.
=cut
sub _safely {
my ($self, $replicant, $name, $code) = @_;
- eval {
- $code->()
- };
- if ($@) {
- $replicant
- ->debugobj
- ->print(
- sprintf( "Exception trying to $name for replicant %s, error is %s",
- $replicant->_dbi_connect_info->[0], $@)
- );
- return;
- }
- return 1;
+ return try {
+ $code->();
+ 1;
+ } catch {
+ $replicant->debugobj->print(sprintf(
+ "Exception trying to $name for replicant %s, error is %s",
+ $replicant->_dbi_connect_info->[0], $_)
+ );
+ undef;
+ };
}
=head2 connected_replicants
defined by L</maximum_lag>. Replicants that fail any of these tests are set to
inactive, and thus removed from the replication pool.
-This tests L<all_replicants>, since a replicant that has been previous marked
-as inactive can be reactived should it start to pass the validation tests again.
+This tests L</all_replicants>, since a replicant that has been previous marked
+as inactive can be reactivated should it start to pass the validation tests again.
See L<DBIx::Class::Storage::DBI> for more about checking if a replicating
connection is not following a master or is lagging.
if($lag_behind_master <= $self->maximum_lag) {
$replicant->active(1);
} else {
- $replicant->active(0);
+ $replicant->active(0);
}
- }
+ }
} else {
$replicant->active(0);
}
$replicant->active(0);
}
}
- ## Mark that we completed this validation.
- $self->_last_validated(time);
+ ## Mark that we completed this validation.
+ $self->_last_validated(time);
}
-=head1 AUTHOR
+=head1 FURTHER QUESTIONS?
-John Napiorkowski <john.napiorkowski@takkle.com>
+Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
-=head1 LICENSE
+=head1 COPYRIGHT AND LICENSE
-You may distribute this code under the same terms as Perl itself.
+This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
+by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
+redistribute it and/or modify it under the same terms as the
+L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.
=cut
-__PACKAGE__->meta->make_immutable;
-
1;