From b548e865e5d0532a03416cbc8db923c1a2f2f01e Mon Sep 17 00:00:00 2001 From: Jehan-Guillaume de Rorthais Date: Fri, 10 Jul 2020 02:00:38 +0200 Subject: [PATCH 2/2] Add various tests related to demote and promote actions * demote/promote with a standby replicating from the node * make sure 2PC survive a demote/promote cycle * commit 2PC and check the result * swap roles between primary and standby * commit a 2PC on the new primary --- src/test/perl/PostgresNode.pm | 25 +++++ src/test/recovery/t/021_promote-demote.pl | 129 ++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/test/recovery/t/021_promote-demote.pl diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index 8c1b77376f..4488365ffc 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -906,6 +906,31 @@ sub promote =pod +=item $node->demote() + +Wrapper for pg_ctl demote + +=cut + +sub demote +{ + my ($self, $mode) = @_; + my $port = $self->port; + my $pgdata = $self->data_dir; + my $logfile = $self->logfile; + my $name = $self->name; + + $mode = 'fast' unless defined $mode; + + print "### Demoting node \"$name\" using mode $mode\n"; + + TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile, + '-m', $mode, 'demote'); + return; +} + +=pod + =item $node->logrotate() Wrapper for pg_ctl logrotate diff --git a/src/test/recovery/t/021_promote-demote.pl b/src/test/recovery/t/021_promote-demote.pl new file mode 100644 index 0000000000..04e2207470 --- /dev/null +++ b/src/test/recovery/t/021_promote-demote.pl @@ -0,0 +1,129 @@ +# Test demote/promote actions in various scenarios using two +# nodes alpha and beta. We check proper actions results, +# correct data replication accros multiple demote/promote, +# manual switchover. + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 13; + +$ENV{PGDATABASE} = 'postgres'; + +# Initialize node alpha +my $node_alpha = get_new_node('alpha'); +$node_alpha->init(allows_streaming => 1); +$node_alpha->append_conf( + 'postgresql.conf', qq( + max_prepared_transactions = 10 + log_checkpoints = true + log_replication_commands = true + +)); + +# Take backup +my $backup_name = 'alpha_backup'; +$node_alpha->start; +$node_alpha->backup($backup_name); + +# Create node beta from backup +my $node_beta = get_new_node('beta'); +$node_beta->init_from_backup($node_alpha, $backup_name); +$node_beta->enable_streaming($node_alpha); +$node_beta->start; + + +# Create some 2PC on alpha for futur tests +$node_alpha->safe_psql('postgres', q{ +CREATE TABLE ins AS SELECT 1 AS i; +BEGIN; +CREATE TABLE new AS SELECT generate_series(1,5) AS i; +PREPARE TRANSACTION 'pxact1'; +BEGIN; +INSERT INTO ins VALUES (2); +PREPARE TRANSACTION 'pxact2'; +}); + +# Demote alpha. beta should keep streaming from it as a +# cascaded standby. +$node_alpha->demote; + +is( $node_alpha->safe_psql( 'postgres', 'SELECT pg_is_in_recovery()'), + 't', 'node alpha demoted to standby' ); + +is( $node_alpha->safe_psql( + 'postgres', 'SELECT application_name FROM pg_stat_replication'), + $node_beta->name, 'beta is still replicating with alpha after demote' ); + +# Promote alpha back in production. +$node_alpha->promote; + +is( $node_alpha->safe_psql( 'postgres', 'SELECT pg_is_in_recovery()'), + 'f', "node alpha promoted" ); + +# Check all 2PC xact have been restored +is( $node_alpha->safe_psql( + 'postgres', + "SELECT string_agg(gid, ',' order by gid asc) FROM pg_prepared_xacts"), + 'pxact1,pxact2', "prepared transactions 'pxact1' and 'pxact2' exists" ); + +# Commit one 2PC and check it on alpha and beta +$node_alpha->safe_psql( 'postgres', "commit prepared 'pxact1'"); + +is( $node_alpha->safe_psql( + 'postgres', "SELECT string_agg(i::text, ',' order by i asc) FROM new"), + '1,2,3,4,5', "prepared transaction 'pxact1' commited" ); + +$node_alpha->wait_for_catchup($node_beta); + +is( $node_beta->safe_psql( + 'postgres', "SELECT string_agg(i::text, ',' order by i asc) FROM new"), + '1,2,3,4,5', "prepared transaction 'pxact1' replicated to beta" ); + +# swap roles between alpha and beta +# demote and check alpha +$node_alpha->demote; +is( $node_alpha->safe_psql( 'postgres', 'SELECT pg_is_in_recovery()'), + 't', "node alpha demoted" ); + +# fetch the last REDO location from alpha and chek beta received everyting +my ($stdout, $stderr) = run_command([ 'pg_controldata', $node_alpha->data_dir ]); +$stdout =~ m{REDO location:\s+([0-9A-F]+/[0-9A-F]+)$}mg; +my $redo_loc = $1; + +is( $node_beta->safe_psql( + 'postgres', + "SELECT pg_wal_lsn_diff(pg_last_wal_receive_lsn(), '$redo_loc') > 0 "), + 't', "node beta received the demote checkpoint from alpha" ); + +# promote beta and check it +$node_beta->promote; +is( $node_beta->safe_psql( 'postgres', 'SELECT pg_is_in_recovery()'), + 'f', "node beta promoted" ); + +# Setup alpha to replicate from beta +$node_alpha->enable_streaming($node_beta); +$node_alpha->reload; + +# check alpha is replicating from it +$node_beta->wait_for_catchup($node_alpha); + +is( $node_beta->safe_psql( + 'postgres', 'SELECT application_name FROM pg_stat_replication'), + $node_alpha->name, 'alpha is replicating from beta' ); + +# make sure the second 2PC is still available on beta +is( $node_beta->safe_psql( + 'postgres', 'SELECT gid FROM pg_prepared_xacts'), + 'pxact2', "prepared transactions pxact2' exists" ); + +# commit the second 2PC and check its result on both nodes +$node_beta->safe_psql( 'postgres', "commit prepared 'pxact2'"); + +is( $node_beta->safe_psql( 'postgres', 'SELECT 1 FROM ins WHERE i=2'), + '1', "prepared transaction 'pxact2' commited" ); + +$node_beta->wait_for_catchup($node_alpha); +is( $node_alpha->safe_psql( 'postgres', 'SELECT 1 FROM ins WHERE i=2'), + '1', "prepared transaction 'pxact2' streamed to alpha" ); -- 2.20.1