From 7c311632576bc8f48ac43a9dd0fa07e86e6b47e6 Mon Sep 17 00:00:00 2001 From: Asim R P Date: Thu, 12 Sep 2019 17:19:45 +0530 Subject: [PATCH v1 2/2] Test to validate replay of WAL records involving drop database Authored by Paul Guo and Kyotaro Horiguchi. --- src/test/perl/PostgresNode.pm | 13 +++- src/test/perl/RecursiveCopy.pm | 33 +++++++++-- src/test/recovery/t/011_crash_recovery.pl | 99 ++++++++++++++++++++++++++++++- 3 files changed, 138 insertions(+), 7 deletions(-) diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index 270bd6c856..b5dc3a8918 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -546,13 +546,22 @@ target server since it isn't done by default. sub backup { - my ($self, $backup_name) = @_; + my ($self, $backup_name, %params) = @_; my $backup_path = $self->backup_dir . '/' . $backup_name; my $name = $self->name; + my @rest = (); + + if (defined $params{tablespace_mappings}) + { + my @ts_mappings = split(/,/, $params{tablespace_mappings}); + foreach my $elem (@ts_mappings) { + push(@rest, '--tablespace-mapping='.$elem); + } + } print "# Taking pg_basebackup $backup_name from node \"$name\"\n"; TestLib::system_or_bail('pg_basebackup', '-D', $backup_path, '-h', - $self->host, '-p', $self->port, '--no-sync'); + $self->host, '-p', $self->port, '--no-sync', @rest); print "# Backup finished\n"; return; } diff --git a/src/test/perl/RecursiveCopy.pm b/src/test/perl/RecursiveCopy.pm index baf5d0ac63..514ed90ae7 100644 --- a/src/test/perl/RecursiveCopy.pm +++ b/src/test/perl/RecursiveCopy.pm @@ -22,6 +22,7 @@ use warnings; use Carp; use File::Basename; use File::Copy; +use TestLib; =pod @@ -97,14 +98,38 @@ sub _copypath_recurse # invoke the filter and skip all further operation if it returns false return 1 unless &$filterfn($curr_path); - # Check for symlink -- needed only on source dir - # (note: this will fall through quietly if file is already gone) - croak "Cannot operate on symlink \"$srcpath\"" if -l $srcpath; - # Abort if destination path already exists. Should we allow directories # to exist already? croak "Destination path \"$destpath\" already exists" if -e $destpath; + # Check for symlink -- needed only on source dir + # (note: this will fall through quietly if file is already gone) + if (-l $srcpath) + { + croak "Cannot operate on symlink \"$srcpath\"" + if ($srcpath !~ /\/(pg_tblspc\/[0-9]+)$/); + + # We have mapped tablespaces. Copy them individually + my $linkname = $1; + my $tmpdir = TestLib::tempdir; + my $dstrealdir = TestLib::perl2host($tmpdir); + my $srcrealdir = readlink($srcpath); + + opendir(my $dh, $srcrealdir); + while (readdir $dh) + { + next if (/^\.\.?$/); + my $spath = "$srcrealdir/$_"; + my $dpath = "$dstrealdir/$_"; + + copypath($spath, $dpath); + } + closedir $dh; + + symlink $dstrealdir, $destpath; + return 1; + } + # If this source path is a file, simply copy it to destination with the # same name and we're done. if (-f $srcpath) diff --git a/src/test/recovery/t/011_crash_recovery.pl b/src/test/recovery/t/011_crash_recovery.pl index 526a3481fb..5ac7303dd6 100644 --- a/src/test/recovery/t/011_crash_recovery.pl +++ b/src/test/recovery/t/011_crash_recovery.pl @@ -15,7 +15,7 @@ if ($Config{osname} eq 'MSWin32') } else { - plan tests => 3; + plan tests => 5; } my $node = get_new_node('master'); @@ -66,3 +66,100 @@ is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]), 'aborted', 'xid is aborted after crash'); $tx->kill_kill; + +# Ensure that tablespace removal doesn't cause error while recovering +# the preceding create database with that tablespace. + +my $node_master = get_new_node('master2'); +$node_master->init(allows_streaming => 1); +$node_master->start; + +# Create tablespace +my $tspDir_master = TestLib::tempdir; +my $realTSDir_master = TestLib::perl2host($tspDir_master); +$node_master->safe_psql('postgres', "CREATE TABLESPACE ts1 LOCATION '$realTSDir_master'"); + +my $tspDir_standby = TestLib::tempdir; +my $realTSDir_standby = TestLib::perl2host($tspDir_standby); + +# Take backup +my $backup_name = 'my_backup'; +$node_master->backup($backup_name, + tablespace_mappings => + "$realTSDir_master=$realTSDir_standby"); +my $node_standby = get_new_node('standby2'); +$node_standby->init_from_backup($node_master, $backup_name, has_streaming => 1); +$node_standby->start; + +# Make sure connection is made +$node_master->poll_query_until( + 'postgres', 'SELECT count(*) = 1 FROM pg_stat_replication'); + +# Make sure to perform restartpoint after tablespace creation +$node_master->wait_for_catchup($node_standby, 'replay', + $node_master->lsn('replay')); +$node_standby->safe_psql('postgres', 'CHECKPOINT'); + +# Do immediate shutdown just after a sequence of CREAT DATABASE / DROP +# DATABASE / DROP TABLESPACE. This leaves a CREATE DATBASE WAL record +# that is to be applied to already-removed tablespace. +$node_master->safe_psql('postgres', + q[CREATE DATABASE db1 WITH TABLESPACE ts1; + DROP DATABASE db1; + DROP TABLESPACE ts1;]); +$node_master->wait_for_catchup($node_standby, 'replay', + $node_master->lsn('replay')); +$node_standby->stop('immediate'); + +# Should restart ignoring directory creation error. +is($node_standby->start(fail_ok => 1), 1); + + +# Ensure that tablespace removal doesn't cause error while recovering the +# preceding alter database set tablespace. + +$node_master = get_new_node('master3'); +$node_master->init(allows_streaming => 1); +$node_master->start; + +# Create tablespace +$tspDir_master = TestLib::tempdir; +$realTSDir_master = TestLib::perl2host($tspDir_master); +mkdir "$realTSDir_master/1"; +mkdir "$realTSDir_master/2"; +$node_master->safe_psql('postgres', "CREATE TABLESPACE ts1 LOCATION '$realTSDir_master/1'"); +$node_master->safe_psql('postgres', "CREATE TABLESPACE ts2 LOCATION '$realTSDir_master/2'"); + +$tspDir_standby = TestLib::tempdir; +$realTSDir_standby = TestLib::perl2host($tspDir_standby); + +# Take backup +$backup_name = 'my_backup'; +$node_master->backup($backup_name, + tablespace_mappings => + "$realTSDir_master/1=$realTSDir_standby/1,$realTSDir_master/2=$realTSDir_standby/2"); +$node_standby = get_new_node('standby3'); +$node_standby->init_from_backup($node_master, $backup_name, has_streaming => 1); +$node_standby->start; + +# Make sure connection is made +$node_master->poll_query_until( + 'postgres', 'SELECT count(*) = 1 FROM pg_stat_replication'); + +$node_master->safe_psql('postgres', "CREATE DATABASE db1 TABLESPACE ts1"); + +# Make sure to perform restartpoint after tablespace creation +$node_master->wait_for_catchup($node_standby, 'replay', + $node_master->lsn('replay')); +$node_standby->safe_psql('postgres', 'CHECKPOINT'); + +# Do immediate shutdown ... +$node_master->safe_psql('postgres', + q[ALTER DATABASE db1 SET TABLESPACE ts2; + DROP TABLESPACE ts1;]); +$node_master->wait_for_catchup($node_standby, 'replay', + $node_master->lsn('replay')); +$node_standby->stop('immediate'); + +# Should restart ignoring directory creation error. +is($node_standby->start(fail_ok => 1), 1); -- 2.14.3 (Apple Git-98)