mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +03:00 
			
		
		
		
	Additional tests for subtransactions in recovery
Tests for normal and prepared transactions Author: Nikhil Sontakke, placed in new test file by me
This commit is contained in:
		@@ -4,7 +4,7 @@ use warnings;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use PostgresNode;
 | 
					use PostgresNode;
 | 
				
			||||||
use TestLib;
 | 
					use TestLib;
 | 
				
			||||||
use Test::More tests => 13;
 | 
					use Test::More tests => 12;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Setup master node
 | 
					# Setup master node
 | 
				
			||||||
my $node_master = get_new_node("master");
 | 
					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",
 | 
					$node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts",
 | 
				
			||||||
	  stdout => \$psql_out);
 | 
						  stdout => \$psql_out);
 | 
				
			||||||
is($psql_out, '0', "Replay prepared transaction with DDL");
 | 
					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");
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										197
									
								
								src/test/recovery/t/012_subtransactions.pl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/test/recovery/t/012_subtransactions.pl
									
									
									
									
									
										Normal file
									
								
							@@ -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");
 | 
				
			||||||
		Reference in New Issue
	
	Block a user