From 0352c15e5ab4f70c3ab2ac1d48d9f38a5dd11786 Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Thu, 27 Apr 2017 14:26:57 +0200 Subject: [PATCH] Additional tests for subtransactions in recovery Tests for normal and prepared transactions Author: Nikhil Sontakke, placed in new test file by me --- src/test/recovery/t/009_twophase.pl | 39 +--- src/test/recovery/t/012_subtransactions.pl | 197 +++++++++++++++++++++ 2 files changed, 198 insertions(+), 38 deletions(-) create mode 100644 src/test/recovery/t/012_subtransactions.pl diff --git a/src/test/recovery/t/009_twophase.pl b/src/test/recovery/t/009_twophase.pl index be7f00b5e3..73103252a7 100644 --- a/src/test/recovery/t/009_twophase.pl +++ b/src/test/recovery/t/009_twophase.pl @@ -4,7 +4,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 13; +use Test::More tests => 12; # Setup master node my $node_master = get_new_node("master"); @@ -283,40 +283,3 @@ $node_master->psql('postgres', " $node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts", stdout => \$psql_out); is($psql_out, '0', "Replay prepared transaction with DDL"); - - -############################################################################### -# Check that replay will correctly set SUBTRANS and properly advance nextXid -# so that it won't conflict with savepoint xids. -############################################################################### - -$node_master->psql('postgres', " - BEGIN; - DELETE FROM t_009_tbl; - INSERT INTO t_009_tbl VALUES (43); - SAVEPOINT s1; - INSERT INTO t_009_tbl VALUES (43); - SAVEPOINT s2; - INSERT INTO t_009_tbl VALUES (43); - SAVEPOINT s3; - INSERT INTO t_009_tbl VALUES (43); - SAVEPOINT s4; - INSERT INTO t_009_tbl VALUES (43); - SAVEPOINT s5; - INSERT INTO t_009_tbl VALUES (43); - PREPARE TRANSACTION 'xact_009_1'; - CHECKPOINT;"); - -$node_master->stop; -$node_master->start; -$node_master->psql('postgres', " - -- here we can get xid of previous savepoint if nextXid - -- wasn't properly advanced - BEGIN; - INSERT INTO t_009_tbl VALUES (142); - ROLLBACK; - COMMIT PREPARED 'xact_009_1';"); - -$node_master->psql('postgres', "SELECT count(*) FROM t_009_tbl", - stdout => \$psql_out); -is($psql_out, '6', "Check nextXid handling for prepared subtransactions"); diff --git a/src/test/recovery/t/012_subtransactions.pl b/src/test/recovery/t/012_subtransactions.pl new file mode 100644 index 0000000000..5e02c28cb8 --- /dev/null +++ b/src/test/recovery/t/012_subtransactions.pl @@ -0,0 +1,197 @@ +# Tests dedicated to subtransactions in recovery +use strict; +use warnings; + +use PostgresNode; +use TestLib; +use Test::More tests => 12; + +# Setup master node +my $node_master = get_new_node("master"); +$node_master->init(allows_streaming => 1); +$node_master->append_conf('postgresql.conf', qq( + max_prepared_transactions = 10 + log_checkpoints = true +)); +$node_master->start; +$node_master->backup('master_backup'); +$node_master->psql('postgres', "CREATE TABLE t_012_tbl (id int)"); + +# Setup slave node +my $node_slave = get_new_node('slave'); +$node_slave->init_from_backup($node_master, 'master_backup', has_streaming => 1); +$node_slave->start; + +# Switch to synchronous replication +$node_master->append_conf('postgresql.conf', qq( + synchronous_standby_names = '*' +)); +$node_master->psql('postgres', "SELECT pg_reload_conf()"); + +my $psql_out = ''; +my $psql_rc = ''; + +############################################################################### +# Check that replay will correctly set SUBTRANS and properly advance nextXid +# so that it won't conflict with savepoint xids. +############################################################################### + +$node_master->psql('postgres', " + BEGIN; + DELETE FROM t_012_tbl; + INSERT INTO t_012_tbl VALUES (43); + SAVEPOINT s1; + INSERT INTO t_012_tbl VALUES (43); + SAVEPOINT s2; + INSERT INTO t_012_tbl VALUES (43); + SAVEPOINT s3; + INSERT INTO t_012_tbl VALUES (43); + SAVEPOINT s4; + INSERT INTO t_012_tbl VALUES (43); + SAVEPOINT s5; + INSERT INTO t_012_tbl VALUES (43); + PREPARE TRANSACTION 'xact_012_1'; + CHECKPOINT;"); + +$node_master->stop; +$node_master->start; +$node_master->psql('postgres', " + -- here we can get xid of previous savepoint if nextXid + -- wasn't properly advanced + BEGIN; + INSERT INTO t_012_tbl VALUES (142); + ROLLBACK; + COMMIT PREPARED 'xact_012_1';"); + +$node_master->psql('postgres', "SELECT count(*) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '6', "Check nextXid handling for prepared subtransactions"); + +############################################################################### +# Check that replay will correctly set 2PC with more than +# PGPROC_MAX_CACHED_SUBXIDS subtransations and also show data properly +# on promotion +############################################################################### +$node_master->psql('postgres', "DELETE FROM t_012_tbl"); + +# Function borrowed from src/test/regress/sql/hs_primary_extremes.sql +$node_master->psql('postgres', " + CREATE OR REPLACE FUNCTION hs_subxids (n integer) + RETURNS void + LANGUAGE plpgsql + AS \$\$ + BEGIN + IF n <= 0 THEN RETURN; END IF; + INSERT INTO t_012_tbl VALUES (n); + PERFORM hs_subxids(n - 1); + RETURN; + EXCEPTION WHEN raise_exception THEN NULL; END; + \$\$;"); +$node_master->psql('postgres', " + BEGIN; + SELECT hs_subxids(127); + COMMIT;"); +$node_master->wait_for_catchup($node_slave, 'replay', $node_master->lsn('insert')); +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '8128', "Visible"); +$node_master->stop; +$node_slave->promote; +$node_slave->poll_query_until('postgres', + "SELECT NOT pg_is_in_recovery()") + or die "Timed out while waiting for promotion of standby"; + +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '8128', "Visible"); + +# restore state +($node_master, $node_slave) = ($node_slave, $node_master); +$node_slave->enable_streaming($node_master); +$node_slave->append_conf('recovery.conf', qq( +recovery_target_timeline='latest' +)); +$node_slave->start; +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '8128', "Visible"); + +$node_master->psql('postgres', "DELETE FROM t_012_tbl"); + +# Function borrowed from src/test/regress/sql/hs_primary_extremes.sql +$node_master->psql('postgres', " + CREATE OR REPLACE FUNCTION hs_subxids (n integer) + RETURNS void + LANGUAGE plpgsql + AS \$\$ + BEGIN + IF n <= 0 THEN RETURN; END IF; + INSERT INTO t_012_tbl VALUES (n); + PERFORM hs_subxids(n - 1); + RETURN; + EXCEPTION WHEN raise_exception THEN NULL; END; + \$\$;"); +$node_master->psql('postgres', " + BEGIN; + SELECT hs_subxids(127); + PREPARE TRANSACTION 'xact_012_1';"); +$node_master->wait_for_catchup($node_slave, 'replay', $node_master->lsn('insert')); +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '-1', "Not visible"); +$node_master->stop; +$node_slave->promote; +$node_slave->poll_query_until('postgres', + "SELECT NOT pg_is_in_recovery()") + or die "Timed out while waiting for promotion of standby"; + +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '-1', "Not visible"); + +# restore state +($node_master, $node_slave) = ($node_slave, $node_master); +$node_slave->enable_streaming($node_master); +$node_slave->append_conf('recovery.conf', qq( +recovery_target_timeline='latest' +)); +$node_slave->start; +$psql_rc = $node_master->psql('postgres', "COMMIT PREPARED 'xact_012_1'"); +is($psql_rc, '0', "Restore of PGPROC_MAX_CACHED_SUBXIDS+ prepared transaction on promoted slave"); + +$node_master->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '8128', "Visible"); + +$node_master->psql('postgres', "DELETE FROM t_012_tbl"); +$node_master->psql('postgres', " + BEGIN; + SELECT hs_subxids(201); + PREPARE TRANSACTION 'xact_012_1';"); +$node_master->wait_for_catchup($node_slave, 'replay', $node_master->lsn('insert')); +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '-1', "Not visible"); +$node_master->stop; +$node_slave->promote; +$node_slave->poll_query_until('postgres', + "SELECT NOT pg_is_in_recovery()") + or die "Timed out while waiting for promotion of standby"; + +$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '-1', "Not visible"); + +# restore state +($node_master, $node_slave) = ($node_slave, $node_master); +$node_slave->enable_streaming($node_master); +$node_slave->append_conf('recovery.conf', qq( +recovery_target_timeline='latest' +)); +$node_slave->start; +$psql_rc = $node_master->psql('postgres', "ROLLBACK PREPARED 'xact_012_1'"); +is($psql_rc, '0', "Rollback of PGPROC_MAX_CACHED_SUBXIDS+ prepared transaction on promoted slave"); + +$node_master->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", + stdout => \$psql_out); +is($psql_out, '-1', "Not visible");