Hello, PFA version 2 of the TAP test. I removed the non-deterministic sleep and introduced retries until the WAL segment is archived and promotion is complete. Some additional tidying up too.
Regards, Soumyadeep (VMware)
diff --git a/src/test/recovery/t/022_pitr_prepared_xact.pl b/src/test/recovery/t/022_pitr_prepared_xact.pl new file mode 100644 index 00000000000..8738fa39d4d --- /dev/null +++ b/src/test/recovery/t/022_pitr_prepared_xact.pl @@ -0,0 +1,83 @@ +# Test for point-in-time-recovery (PITR) with prepared transactions +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 2; +use File::Compare; + +# Initialize and start primary node with WAL archiving +my $node_primary = get_new_node('primary'); +$node_primary->init(has_archiving => 1); +$node_primary->append_conf('postgresql.conf', "max_wal_senders = 10"); +$node_primary->append_conf('postgresql.conf', "wal_level = 'replica'"); +$node_primary->append_conf('postgresql.conf', + "max_prepared_transactions = 10"); +$node_primary->start; + +# Take backup +my $backup_name = 'my_backup'; +$node_primary->backup($backup_name); + +# Initialize node for PITR targeting a specific restore point +my $node_pitr = get_new_node('node_pitr'); +$node_pitr->init_from_backup( + $node_primary, $backup_name, + standby => 0, + has_restoring => 1); +$node_pitr->append_conf('postgresql.conf', "max_prepared_transactions = 10"); +$node_pitr->append_conf('postgresql.conf', "recovery_target_name = 'rp'"); +$node_pitr->append_conf('postgresql.conf', + "recovery_target_action = 'promote'"); + +# Workload with a prepared transaction and the target restore point +$node_primary->psql( + 'postgres', qq{ +CREATE TABLE foo(i int); +BEGIN; +INSERT INTO foo VALUES(1); +PREPARE TRANSACTION 'fooinsert'; +SELECT pg_create_restore_point('rp'); +INSERT INTO foo VALUES(2); +}); + +# Find next WAL segment to be archived +my $walfile_to_be_archived = $node_primary->safe_psql('postgres', + "SELECT pg_walfile_name(pg_current_wal_lsn());"); + +# Make WAL segment eligible for archival +$node_primary->safe_psql('postgres', 'SELECT pg_switch_wal()'); + +# Wait until the WAL segment has been archived +my $archive_wait_query = + "SELECT '$walfile_to_be_archived' <= last_archived_wal FROM pg_stat_archiver;"; +$node_primary->poll_query_until('postgres', $archive_wait_query) + or die "Timed out while waiting for WAL segment to be archived"; +my $last_archived_wal_file = $walfile_to_be_archived; + +# Now start the PITR node +$node_pitr->start; + +# Wait until the PITR node exits recovery +$node_pitr->poll_query_until('postgres', "SELECT pg_is_in_recovery() = 'f';") + or die "Timed out while waiting for PITR promotion"; + +# Ensure that we didn't write to the older timeline during PITR promotion by +# checking that the last archived WAL segment was not overwritten during recovery +my $archive_dir = $node_primary->archive_dir; +my $archive_wal_file_path = "$archive_dir/$last_archived_wal_file"; +my $node_pitr_data = $node_pitr->data_dir; +my $local_wal_file_path = "$node_pitr_data/pg_wal/$last_archived_wal_file"; +is(compare($archive_wal_file_path, $local_wal_file_path), + qq(0), "check if the last archived WAL file was overwritten"); + +# Commit the prepared transaction in the latest timeline and check the result. +# There should only be one row (from the prepared transaction). The row from +# the INSERT after the restore point should not show up, since our recovery +# target preceded said INSERT +$node_pitr->psql( + 'postgres', qq{ +COMMIT PREPARED 'fooinsert'; +}); +my $result = $node_pitr->safe_psql('postgres', "SELECT * FROM foo;"); +is($result, qq(1), "check table contents after COMMIT PREPARED");