From: John Napiorkowski Date: Thu, 29 May 2008 18:30:39 +0000 (+0000) Subject: discard changes now is forced to use master for replication. changed discard_changes... X-Git-Tag: v0.08240~402^2~34 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=ed213e857791d1cfb0f1a0e32674e81358e19564;p=dbsrgits%2FDBIx-Class.git discard changes now is forced to use master for replication. changed discard_changes guts to point to new method called reload_row in storage. fixed problem with replicated transactionws not returning the right thing. added tests to all the above --- diff --git a/lib/DBIx/Class/PK.pm b/lib/DBIx/Class/PK.pm index b2efdf8..bb820e2 100644 --- a/lib/DBIx/Class/PK.pm +++ b/lib/DBIx/Class/PK.pm @@ -37,23 +37,8 @@ changes made since the row was last read from storage. sub discard_changes { my ($self) = @_; - delete $self->{_dirty_columns}; - return unless $self->in_storage; # Don't reload if we aren't real! - - my $reload = $self->result_source->resultset->find( - map { $self->$_ } $self->primary_columns - ); - unless ($reload) { # If we got deleted in the mean-time - $self->in_storage(0); - return $self; - } - - %$self = %$reload; - - # Avoid a possible infinite loop with - # sub DESTROY { $_[0]->discard_changes } - bless $reload, 'Do::Not::Exist'; - + my $storage = $self->result_source->schema->storage; + $storage->reload_row($self); return $self; } diff --git a/lib/DBIx/Class/Storage.pm b/lib/DBIx/Class/Storage.pm index dd61ba0..df4434e 100644 --- a/lib/DBIx/Class/Storage.pm +++ b/lib/DBIx/Class/Storage.pm @@ -438,6 +438,15 @@ only. sub select_single { die "Virtual method!" } +=head2 reload_row ($row) + +given a L object, 'reloads' it from the storage. This will +destroy any existing changes you have not yet saved. + +=cut + +sub reload_row { die "Virtual method!" } + =head2 columns_info_for Returns metadata for the given source's columns. This diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 212be1e..6c9b97d 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -1296,6 +1296,28 @@ sub select_single { return @row; } +sub reload_row { + my ($self, $row) = @_; + delete $row->{_dirty_columns}; + return unless $row->in_storage; # Don't reload if we aren't real! + + my $reload = $row->result_source->resultset->find( + map { $row->$_ } $row->primary_columns + ); + unless ($reload) { # If we got deleted in the mean-time + $row->in_storage(0); + return $row; + } + + $row = %$reload; + + # Avoid a possible infinite loop with + # sub DESTROY { $_[0]->discard_changes } + bless $reload, 'Do::Not::Exist'; + + return $row; +} + =head2 sth =over 4 diff --git a/lib/DBIx/Class/Storage/DBI/Replicated.pm b/lib/DBIx/Class/Storage/DBI/Replicated.pm index c95a084..efabb05 100644 --- a/lib/DBIx/Class/Storage/DBI/Replicated.pm +++ b/lib/DBIx/Class/Storage/DBI/Replicated.pm @@ -229,6 +229,7 @@ has 'write_handler' => ( sth deploy schema + reload_row /], ); @@ -385,9 +386,10 @@ Example: my $name = shift @_; $schema->resultset('User')->create({name=>$name}); my $user_rs = $schema->resultset('User')->find({name=>$name}); + return $user_rs; }; - $schema->storage->execute_reliably($reliably, 'John'); + my $user_rs = $schema->storage->execute_reliably($reliably, 'John'); Use this when you must be certain of your database state, such as when you just inserted something and need to get a resultset including it, etc. @@ -411,16 +413,31 @@ sub execute_reliably { $self->read_handler($master); ## do whatever the caller needs + my @result; + my $want_array = wantarray; + eval { - $coderef->(@args); + if($want_array) { + @result = $coderef->(@args); + } + elsif(defined $want_array) { + ($result[0]) = ($coderef->(@args)); + } else { + $coderef->(@args); + } }; + ##Reset to the original state + $self->schema->storage->read_handler($current); + + ##Exception testing has to come last, otherwise you might leave the + ##read_handler set to master. + if($@) { $self->throw_exception("coderef returned an error: $@"); + } else { + return $want_array ? @result : $result[0]; } - - ##Reset to the original state - $self->schema->storage->read_handler($current); } =head2 set_reliable_storage @@ -466,6 +483,20 @@ sub txn_do { $self->execute_reliably($coderef, @args); } +=head2 reload_row ($row) + +Overload to the reload_row method so that the reloading is always directed to +the master storage. + +=cut + +around 'reload_row' => sub { + my ($reload_row, $self, $row) = @_; + $self->execute_reliably(sub { + $self->$reload_row(shift); + }, $row); +}; + =head2 connected Check that the master and at least one of the replicants is connected. diff --git a/t/93storage_replication.t b/t/93storage_replication.t index 7765767..b2b3732 100644 --- a/t/93storage_replication.t +++ b/t/93storage_replication.t @@ -9,7 +9,7 @@ BEGIN { eval "use Moose; use Test::Moose"; plan $@ ? ( skip_all => 'needs Moose for testing' ) - : ( tests => 57 ); + : ( tests => 71 ); } use_ok 'DBIx::Class::Storage::DBI::Replicated::Pool'; @@ -455,30 +455,81 @@ ok my $unreliably = sub { } => 'created coderef properly'; throws_ok {$replicated->schema->storage->execute_reliably($unreliably)} - qr/coderef returned an error: Can't find source for ArtistXX/ + qr/Can't find source for ArtistXX/ => 'Bad coderef throws proper error'; +## Make sure replication came back + +ok $replicated->schema->resultset('Artist')->find(3) + => 'replicant reactivated'; + ## make sure transactions are set to execute_reliably ok my $transaction = sub { + my $id = shift @_; + $replicated ->schema ->populate('Artist', [ [ qw/artistid name/ ], - [ 666, "Children of the Grave"], + [ $id, "Children of the Grave"], ]); - ok my $result = $replicated->schema->resultset('Artist')->find(666); + ok my $result = $replicated->schema->resultset('Artist')->find($id); + ok my $more = $replicated->schema->resultset('Artist')->find(1); + + return ($result, $more); }; -$replicated->schema->txn_do($transaction); +## Test the transaction with multi return +{ + ok my @return = $replicated->schema->txn_do($transaction, 666) + => 'did transaction'; + + is $return[0]->id, 666 + => 'first returned value is correct'; + + is $return[1]->id, 1 + => 'second returned value is correct'; +} + +## Test that asking for single return works +{ + ok my $return = $replicated->schema->txn_do($transaction, 777) + => 'did transaction'; + + is $return->id, 777 + => 'first returned value is correct'; +} + +## Test transaction returning a single value + +{ + ok my $result = $replicated->schema->txn_do(sub { + ok my $more = $replicated->schema->resultset('Artist')->find(1); + return $more; + }) => 'successfully processed transaction'; + + is $result->id, 1 + => 'Got expected single result from transaction'; +} ## Make sure replication came back -ok $replicated->schema->resultset('Artist')->find(5) +ok $replicated->schema->resultset('Artist')->find(1) => 'replicant reactivated'; + +## Test Discard changes + +{ + ok my $artist = $replicated->schema->resultset('Artist')->find(2) + => 'got an artist to test discard changes'; + + ok $artist->discard_changes + => 'properly discard changes'; +} ## Delete the old database files $replicated->cleanup;