From: Rafael Kitover Date: Thu, 11 Feb 2010 10:35:01 +0000 (+0000) Subject: Merge 'handle_all_storage_methods_in_replicated' into 'trunk' X-Git-Tag: v0.08119~23 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=4a951411c6e34265eabac04117dbcb6d9e6d7936;hp=e398f77e59be21bfdb90087caa30a092c87df0d6;p=dbsrgits%2FDBIx-Class.git Merge 'handle_all_storage_methods_in_replicated' into 'trunk' r21090@hlagh (orig r7836): caelum | 2009-11-02 06:40:52 -0500 new branch to fix unhandled methods in Storage::DBI::Replicated r21091@hlagh (orig r7837): caelum | 2009-11-02 06:42:00 -0500 add test to display unhandled methods r21092@hlagh (orig r7838): caelum | 2009-11-02 06:55:34 -0500 minor fix to last committed test r21093@hlagh (orig r7839): caelum | 2009-11-02 09:26:00 -0500 minor test code cleanup r23125@hlagh (orig r8607): caelum | 2010-02-10 19:25:51 -0500 add unimplemented Storage::DBI methods to ::DBI::Replicated r23130@hlagh (orig r8612): ribasushi | 2010-02-11 05:12:48 -0500 Podtesting exclusion --- diff --git a/lib/DBIx/Class/Storage/DBI/Replicated.pm b/lib/DBIx/Class/Storage/DBI/Replicated.pm index 9eb92dd..64198da 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated.pm @@ -33,6 +33,7 @@ use DBIx::Class::Storage::DBI::Replicated::Types qw/BalancerClassNamePart DBICSc use MooseX::Types::Moose qw/ClassName HashRef Object/; use Scalar::Util 'reftype'; use Hash::Merge 'merge'; +use List::Util qw/min max/; use namespace::clean -except => 'meta'; @@ -276,12 +277,17 @@ has 'read_handler' => ( select select_single columns_info_for + _dbh_columns_info_for + _select /], ); =head2 write_handler -Defines an object that implements the write side of L. +Defines an object that implements the write side of L, +as well as methods that don't write or read that can be called on only one +storage, methods that return a C<$dbh>, and any methods that don't make sense to +run on a replicant. =cut @@ -292,7 +298,10 @@ has 'write_handler' => ( handles=>[qw/ on_connect_do on_disconnect_do + on_connect_call + on_disconnect_call connect_info + _connect_info throw_exception sql_maker sqlt_type @@ -330,6 +339,57 @@ has 'write_handler' => ( svp_release relname_to_table_alias _straight_join_to_node + _dbh_last_insert_id + _fix_bind_params + _default_dbi_connect_attributes + _dbi_connect_info + auto_savepoint + _sqlt_version_ok + _query_end + bind_attribute_by_data_type + transaction_depth + _dbh + _select_args + _dbh_execute_array + _sql_maker_args + _sql_maker + _query_start + _sqlt_version_error + _per_row_update_delete + _dbh_begin_work + _dbh_execute_inserts_with_no_binds + _select_args_to_query + _svp_generate_name + _multipk_update_delete + source_bind_attributes + _normalize_connect_info + _parse_connect_do + _dbh_commit + _execute_array + _placeholders_supported + _verify_pid + savepoints + _sqlt_minimum_version + _sql_maker_opts + _conn_pid + _typeless_placeholders_supported + _conn_tid + _dbh_autocommit + _native_data_type + _get_dbh + sql_maker_class + _dbh_rollback + _adjust_select_args_for_complex_prefetch + _resolve_ident_sources + _resolve_column_info + _prune_unused_joins + _strip_cond_qualifiers + _parse_order_by + _resolve_aliastypes_from_select_args + _execute + _do_query + _dbh_sth + _dbh_execute /], ); @@ -809,6 +869,165 @@ sub cursor_class { $self->master->cursor_class; } +=head2 cursor + +set cursor class on all storages, or return master's, alias for L +above. + +=cut + +sub cursor { + my ($self, $cursor_class) = @_; + + if ($cursor_class) { + $_->cursor($cursor_class) for $self->all_storages; + } + $self->master->cursor; +} + +=head2 unsafe + +sets the L option on all storages or returns +master's current setting + +=cut + +sub unsafe { + my $self = shift; + + if (@_) { + $_->unsafe(@_) for $self->all_storages; + } + + return $self->master->unsafe; +} + +=head2 disable_sth_caching + +sets the L option on all storages +or returns master's current setting + +=cut + +sub disable_sth_caching { + my $self = shift; + + if (@_) { + $_->disable_sth_caching(@_) for $self->all_storages; + } + + return $self->master->disable_sth_caching; +} + +=head2 lag_behind_master + +returns the highest Replicant L +setting + +=cut + +sub lag_behind_master { + my $self = shift; + + return max map $_->lag_behind_master, $self->replicants; +} + +=head2 is_replicating + +returns true if all replicants return true for +L + +=cut + +sub is_replicating { + my $self = shift; + + return (grep $_->is_replicating, $self->replicants) == ($self->replicants); +} + +=head2 connect_call_datetime_setup + +calls L for all storages + +=cut + +sub connect_call_datetime_setup { + my $self = shift; + $_->connect_call_datetime_setup for $self->all_storages; +} + +sub _populate_dbh { + my $self = shift; + $_->_populate_dbh for $self->all_storages; +} + +sub _connect { + my $self = shift; + $_->_connect for $self->all_storages; +} + +sub _rebless { + my $self = shift; + $_->_rebless for $self->all_storages; +} + +sub _determine_driver { + my $self = shift; + $_->_determine_driver for $self->all_storages; +} + +sub _driver_determined { + my $self = shift; + + if (@_) { + $_->_driver_determined(@_) for $self->all_storages; + } + + return $self->master->_driver_determined; +} + +sub _init { + my $self = shift; + + $_->_init for $self->all_storages; +} + +sub _run_connection_actions { + my $self = shift; + + $_->_run_connection_actions for $self->all_storages; +} + +sub _do_connection_actions { + my $self = shift; + + if (@_) { + $_->_do_connection_actions(@_) for $self->all_storages; + } +} + +sub connect_call_do_sql { + my $self = shift; + $_->connect_call_do_sql(@_) for $self->all_storages; +} + +sub disconnect_call_do_sql { + my $self = shift; + $_->disconnect_call_do_sql(@_) for $self->all_storages; +} + +sub _seems_connected { + my $self = shift; + + return min map $_->_seems_connected, $self->all_storages; +} + +sub _ping { + my $self = shift; + + return min map $_->_ping, $self->all_storages; +} + =head1 GOTCHAS Due to the fact that replicants can lag behind a master, you must take care to diff --git a/t/03podcoverage.t b/t/03podcoverage.t index b060014..bcda97d 100644 --- a/t/03podcoverage.t +++ b/t/03podcoverage.t @@ -86,6 +86,13 @@ my $exceptions = { /] }, + 'DBIx::Class::Storage::DBI::Replicated*' => { + ignore => [ qw/ + connect_call_do_sql + disconnect_call_do_sql + /] + }, + 'DBIx::Class::ClassResolver::PassThrough' => { skip => 1 }, 'DBIx::Class::Componentised' => { skip => 1 }, 'DBIx::Class::Relationship::*' => { skip => 1 }, @@ -95,7 +102,6 @@ my $exceptions = { 'DBIx::Class::Storage::DBI::Replicated::Types' => { skip => 1 }, # test some specific components whose parents are exempt below - 'DBIx::Class::Storage::DBI::Replicated*' => {}, 'DBIx::Class::Relationship::Base' => {}, # internals diff --git a/t/storage/replication.t b/t/storage/replication.t index c7485b4..5b74ab9 100644 --- a/t/storage/replication.t +++ b/t/storage/replication.t @@ -266,6 +266,56 @@ for my $method (qw/by_connect_info by_storage_type/) { => 'configured balancer_type'; } +### check that all Storage::DBI methods are handled by ::Replicated +{ + my @storage_dbi_methods = Class::MOP::Class + ->initialize('DBIx::Class::Storage::DBI')->get_all_method_names; + + my @replicated_methods = DBIx::Class::Storage::DBI::Replicated->meta + ->get_all_method_names; + +# remove constants and OTHER_CRAP + @storage_dbi_methods = grep !/^[A-Z_]+\z/, @storage_dbi_methods; + +# remove CAG accessors + @storage_dbi_methods = grep !/_accessor\z/, @storage_dbi_methods; + +# remove DBIx::Class (the root parent, with CAG and stuff) methods + my @root_methods = Class::MOP::Class->initialize('DBIx::Class') + ->get_all_method_names; + my %count; + $count{$_}++ for (@storage_dbi_methods, @root_methods); + + @storage_dbi_methods = grep $count{$_} != 2, @storage_dbi_methods; + +# make hashes + my %storage_dbi_methods; + @storage_dbi_methods{@storage_dbi_methods} = (); + my %replicated_methods; + @replicated_methods{@replicated_methods} = (); + +# remove ::Replicated-specific methods + for my $method (@replicated_methods) { + delete $replicated_methods{$method} + unless exists $storage_dbi_methods{$method}; + } + @replicated_methods = keys %replicated_methods; + +# check that what's left is implemented + %count = (); + $count{$_}++ for (@storage_dbi_methods, @replicated_methods); + + if ((grep $count{$_} == 2, @storage_dbi_methods) == @storage_dbi_methods) { + pass 'all DBIx::Class::Storage::DBI methods implemented'; + } + else { + my @unimplemented = grep $count{$_} == 1, @storage_dbi_methods; + + fail 'the following DBIx::Class::Storage::DBI methods are unimplemented: ' + . "@unimplemented"; + } +} + ok $replicated->schema->storage->meta => 'has a meta object';