diff options
Diffstat (limited to 'src/bin/pg_rewind/RewindTest.pm')
-rw-r--r-- | src/bin/pg_rewind/RewindTest.pm | 216 |
1 files changed, 73 insertions, 143 deletions
diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm index a4c17371dcf..c1c7d1fa19f 100644 --- a/src/bin/pg_rewind/RewindTest.pm +++ b/src/bin/pg_rewind/RewindTest.pm @@ -9,22 +9,20 @@ package RewindTest; # To run a test, the test script (in t/ subdirectory) calls the functions # in this module. These functions should be called in this sequence: # -# 1. init_rewind_test - sets up log file etc. +# 1. setup_cluster - creates a PostgreSQL cluster that runs as the master # -# 2. setup_cluster - creates a PostgreSQL cluster that runs as the master +# 2. start_master - starts the master server # -# 3. start_master - starts the master server -# -# 4. create_standby - runs pg_basebackup to initialize a standby server, and +# 3. create_standby - runs pg_basebackup to initialize a standby server, and # sets it up to follow the master. # -# 5. promote_standby - runs "pg_ctl promote" to promote the standby server. +# 4. promote_standby - runs "pg_ctl promote" to promote the standby server. # The old master keeps running. # -# 6. run_pg_rewind - stops the old master (if it's still running) and runs +# 5. run_pg_rewind - stops the old master (if it's still running) and runs # pg_rewind to synchronize it with the now-promoted standby server. # -# 7. clean_rewind_test - stops both servers used in the test, if they're +# 6. clean_rewind_test - stops both servers used in the test, if they're # still running. # # The test script can use the helper functions master_psql and standby_psql @@ -37,27 +35,23 @@ package RewindTest; use strict; use warnings; -use TestLib; -use Test::More; - use Config; +use Exporter 'import'; use File::Copy; use File::Path qw(rmtree); -use IPC::Run qw(run start); +use IPC::Run qw(run); +use PostgresNode; +use TestLib; +use Test::More; -use Exporter 'import'; our @EXPORT = qw( - $connstr_master - $connstr_standby - $test_master_datadir - $test_standby_datadir + $node_master + $node_standby - append_to_file master_psql standby_psql check_query - init_rewind_test setup_cluster start_master create_standby @@ -66,32 +60,24 @@ our @EXPORT = qw( clean_rewind_test ); -our $test_master_datadir = "$tmp_check/data_master"; -our $test_standby_datadir = "$tmp_check/data_standby"; - -# Define non-conflicting ports for both nodes. -my $port_master = $ENV{PGPORT}; -my $port_standby = $port_master + 1; - -my $connstr_master = "port=$port_master"; -my $connstr_standby = "port=$port_standby"; - -$ENV{PGDATABASE} = "postgres"; +# Our nodes. +our $node_master; +our $node_standby; sub master_psql { my $cmd = shift; - system_or_bail 'psql', '-q', '--no-psqlrc', '-d', $connstr_master, - '-c', "$cmd"; + system_or_bail 'psql', '-q', '--no-psqlrc', '-d', + $node_master->connstr('postgres'), '-c', "$cmd"; } sub standby_psql { my $cmd = shift; - system_or_bail 'psql', '-q', '--no-psqlrc', '-d', $connstr_standby, - '-c', "$cmd"; + system_or_bail 'psql', '-q', '--no-psqlrc', '-d', + $node_standby->connstr('postgres'), '-c', "$cmd"; } # Run a query against the master, and check that the output matches what's @@ -103,8 +89,9 @@ sub check_query # we want just the output, no formatting my $result = run [ - 'psql', '-q', '-A', '-t', '--no-psqlrc', '-d', - $connstr_master, '-c', $query ], + 'psql', '-q', '-A', '-t', '--no-psqlrc', '-d', + $node_master->connstr('postgres'), + '-c', $query ], '>', \$stdout, '2>', \$stderr; # We don't use ok() for the exit code and stderr, because we want this @@ -125,56 +112,16 @@ sub check_query } } -# Run a query once a second, until it returns 't' (i.e. SQL boolean true). -sub poll_query_until -{ - my ($query, $connstr) = @_; - - my $max_attempts = 30; - my $attempts = 0; - my ($stdout, $stderr); - - while ($attempts < $max_attempts) - { - my $cmd = [ 'psql', '-At', '-c', "$query", '-d', "$connstr" ]; - my $result = run $cmd, '>', \$stdout, '2>', \$stderr; - - chomp($stdout); - $stdout =~ s/\r//g if $Config{osname} eq 'msys'; - if ($stdout eq "t") - { - return 1; - } - - # Wait a second before retrying. - sleep 1; - $attempts++; - } - - # The query result didn't change in 30 seconds. Give up. Print the stderr - # from the last attempt, hopefully that's useful for debugging. - diag $stderr; - return 0; -} - -sub append_to_file -{ - my ($filename, $str) = @_; - - open my $fh, ">>", $filename or die "could not open file $filename"; - print $fh $str; - close $fh; -} - sub setup_cluster { + # Initialize master, data checksums are mandatory - rmtree($test_master_datadir); - standard_initdb($test_master_datadir); + $node_master = get_new_node(); + $node_master->init; # Custom parameters for master's postgresql.conf - append_to_file( - "$test_master_datadir/postgresql.conf", qq( + $node_master->append_conf( + "postgresql.conf", qq( wal_level = hot_standby max_wal_senders = 2 wal_keep_segments = 20 @@ -185,17 +132,11 @@ hot_standby = on autovacuum = off max_connections = 10 )); - - # Accept replication connections on master - configure_hba_for_replication $test_master_datadir; } sub start_master { - system_or_bail('pg_ctl' , '-w', - '-D' , $test_master_datadir, - '-l', "$log_path/master.log", - "-o", "-p $port_master", 'start'); + $node_master->start; #### Now run the test-specific parts to initialize the master before setting # up standby @@ -203,24 +144,20 @@ sub start_master sub create_standby { + $node_standby = get_new_node(); + $node_master->backup('my_backup'); + $node_standby->init_from_backup($node_master, 'my_backup'); + my $connstr_master = $node_master->connstr('postgres'); - # Set up standby with necessary parameter - rmtree $test_standby_datadir; - - # Base backup is taken with xlog files included - system_or_bail('pg_basebackup', '-D', $test_standby_datadir, - '-p', $port_master, '-x'); - append_to_file( - "$test_standby_datadir/recovery.conf", qq( + $node_standby->append_conf( + "recovery.conf", qq( primary_conninfo='$connstr_master application_name=rewind_standby' standby_mode=on recovery_target_timeline='latest' )); # Start standby - system_or_bail('pg_ctl', '-w', '-D', $test_standby_datadir, - '-l', "$log_path/standby.log", - '-o', "-p $port_standby", 'start'); + $node_standby->start; # The standby may have WAL to apply before it matches the primary. That # is fine, because no test examines the standby before promotion. @@ -234,14 +171,15 @@ sub promote_standby # Wait for the standby to receive and write all WAL. my $wal_received_query = "SELECT pg_current_xlog_location() = write_location FROM pg_stat_replication WHERE application_name = 'rewind_standby';"; - poll_query_until($wal_received_query, $connstr_master) + $node_master->poll_query_until('postgres', $wal_received_query) or die "Timed out while waiting for standby to receive and write WAL"; # Now promote slave and insert some new data on master, this will put # the master out-of-sync with the standby. Wait until the standby is # out of recovery mode, and is ready to accept read-write connections. - system_or_bail('pg_ctl', '-w', '-D', $test_standby_datadir, 'promote'); - poll_query_until("SELECT NOT pg_is_in_recovery()", $connstr_standby) + system_or_bail('pg_ctl', '-w', '-D', $node_standby->data_dir, 'promote'); + $node_standby->poll_query_until('postgres', + "SELECT NOT pg_is_in_recovery()") or die "Timed out while waiting for promotion of standby"; # Force a checkpoint after the promotion. pg_rewind looks at the control @@ -255,10 +193,14 @@ sub promote_standby sub run_pg_rewind { - my $test_mode = shift; + my $test_mode = shift; + my $master_pgdata = $node_master->data_dir; + my $standby_pgdata = $node_standby->data_dir; + my $standby_connstr = $node_standby->connstr('postgres'); + my $tmp_folder = TestLib::tempdir; # Stop the master and be ready to perform the rewind - system_or_bail('pg_ctl', '-D', $test_master_datadir, '-m', 'fast', 'stop'); + $node_master->stop; # At this point, the rewind processing is ready to run. # We now have a very simple scenario with a few diverged WAL record. @@ -267,31 +209,33 @@ sub run_pg_rewind # Keep a temporary postgresql.conf for master node or it would be # overwritten during the rewind. - copy("$test_master_datadir/postgresql.conf", - "$tmp_check/master-postgresql.conf.tmp"); + copy( + "$master_pgdata/postgresql.conf", + "$tmp_folder/master-postgresql.conf.tmp"); # Now run pg_rewind if ($test_mode eq "local") { + # Do rewind using a local pgdata as source # Stop the master and be ready to perform the rewind - system_or_bail('pg_ctl', '-D', $test_standby_datadir, - '-m', 'fast', 'stop'); - command_ok(['pg_rewind', - "--debug", - "--source-pgdata=$test_standby_datadir", - "--target-pgdata=$test_master_datadir"], - 'pg_rewind local'); + $node_standby->stop; + command_ok( + [ 'pg_rewind', + "--debug", + "--source-pgdata=$standby_pgdata", + "--target-pgdata=$master_pgdata" ], + 'pg_rewind local'); } elsif ($test_mode eq "remote") { + # Do rewind using a remote connection as source - command_ok(['pg_rewind', - "--debug", - "--source-server", - "port=$port_standby dbname=postgres", - "--target-pgdata=$test_master_datadir"], - 'pg_rewind remote'); + command_ok( + [ 'pg_rewind', "--debug", + "--source-server", $standby_connstr, + "--target-pgdata=$master_pgdata" ], + 'pg_rewind remote'); } else { @@ -301,21 +245,21 @@ sub run_pg_rewind } # Now move back postgresql.conf with old settings - move("$tmp_check/master-postgresql.conf.tmp", - "$test_master_datadir/postgresql.conf"); + move( + "$tmp_folder/master-postgresql.conf.tmp", + "$master_pgdata/postgresql.conf"); # Plug-in rewound node to the now-promoted standby node - append_to_file( - "$test_master_datadir/recovery.conf", qq( + my $port_standby = $node_standby->port; + $node_master->append_conf( + 'recovery.conf', qq( primary_conninfo='port=$port_standby' standby_mode=on recovery_target_timeline='latest' )); # Restart the master to check that rewind went correctly - system_or_bail('pg_ctl', '-w', '-D', $test_master_datadir, - '-l', "$log_path/master.log", - '-o', "-p $port_master", 'start'); + $node_master->start; #### Now run the test-specific parts to check the result } @@ -323,22 +267,8 @@ recovery_target_timeline='latest' # Clean up after the test. Stop both servers, if they're still running. sub clean_rewind_test { - if ($test_master_datadir) - { - system - 'pg_ctl', '-D', $test_master_datadir, '-m', 'immediate', 'stop'; - } - if ($test_standby_datadir) - { - system - 'pg_ctl', '-D', $test_standby_datadir, '-m', 'immediate', 'stop'; - } + $node_master->teardown_node if defined $node_master; + $node_standby->teardown_node if defined $node_standby; } -# Stop the test servers, just in case they're still running. -END -{ - my $save_rc = $?; - clean_rewind_test(); - $? = $save_rc; -} +1; |