1 2# Copyright (c) 2021, PostgreSQL Global Development Group 3 4# Testing streaming replication where standby is promoted and a new cascading 5# standby (without WAL) is connected to the promoted standby. Both archiving 6# and streaming are enabled, but only the history file is available from the 7# archive, so the WAL files all have to be streamed. Test that the cascading 8# standby can follow the new primary (promoted standby). 9use strict; 10use warnings; 11use PostgresNode; 12use TestLib; 13 14use File::Basename; 15use FindBin; 16use Test::More tests => 1; 17 18# Initialize primary node 19my $node_primary = get_new_node('primary'); 20 21# Set up an archive command that will copy the history file but not the WAL 22# files. No real archive command should behave this way; the point is to 23# simulate a race condition where the new cascading standby starts up after 24# the timeline history file reaches the archive but before any of the WAL files 25# get there. 26$node_primary->init(allows_streaming => 1, has_archiving => 1); 27 28# Note: consistent use of forward slashes here avoids any escaping problems 29# that arise from use of backslashes. That means we need to double-quote all 30# the paths in the archive_command 31my $perlbin = TestLib::perl2host($^X); 32$perlbin =~ s!\\!/!g if $TestLib::windows_os; 33my $archivedir_primary = $node_primary->archive_dir; 34$archivedir_primary =~ s!\\!/!g if $TestLib::windows_os; 35$node_primary->append_conf('postgresql.conf', qq( 36archive_command = '"$perlbin" "$FindBin::RealBin/cp_history_files" "%p" "$archivedir_primary/%f"' 37wal_keep_segments=8 38)); 39# Make sure that Msys perl doesn't complain about difficulty in setting locale 40# when called from the archive_command. 41local $ENV{PERL_BADLANG}=0; 42$node_primary->start; 43 44# Take backup from primary 45my $backup_name = 'my_backup'; 46$node_primary->backup($backup_name); 47 48# Create streaming standby linking to primary 49my $node_standby = get_new_node('standby'); 50$node_standby->init_from_backup($node_primary, $backup_name, 51 allows_streaming => 1, has_streaming => 1, has_archiving => 1); 52$node_standby->start; 53 54# Take backup of standby, use -Xnone so that pg_wal is empty. 55$node_standby->backup($backup_name, backup_options => ['-Xnone']); 56 57# Create cascading standby but don't start it yet. 58# Must set up both streaming and archiving. 59my $node_cascade = get_new_node('cascade'); 60$node_cascade->init_from_backup($node_standby, $backup_name, 61 has_streaming => 1); 62$node_cascade->enable_restoring($node_primary); 63$node_cascade->append_conf('recovery.conf', qq( 64recovery_target_timeline='latest' 65)); 66 67# Promote the standby. 68$node_standby->promote; 69 70# Wait for promotion to complete 71$node_standby->poll_query_until('postgres', 72 "SELECT NOT pg_is_in_recovery();") 73 or die "Timed out while waiting for promotion"; 74 75# Find next WAL segment to be archived 76my $walfile_to_be_archived = $node_standby->safe_psql('postgres', 77 "SELECT pg_walfile_name(pg_current_wal_lsn());"); 78 79# Make WAL segment eligible for archival 80$node_standby->safe_psql('postgres', 'SELECT pg_switch_wal()'); 81 82# Wait until the WAL segment has been archived. 83# Since the history file gets created on promotion and is archived before any 84# WAL segment, this is enough to guarantee that the history file was 85# archived. 86my $archive_wait_query = 87 "SELECT '$walfile_to_be_archived' <= last_archived_wal FROM pg_stat_archiver"; 88$node_standby->poll_query_until('postgres', $archive_wait_query) 89 or die "Timed out while waiting for WAL segment to be archived"; 90my $last_archived_wal_file = $walfile_to_be_archived; 91 92# Start cascade node 93$node_cascade->start; 94 95# Create some content on promoted standby and check its presence on the 96# cascading standby. 97$node_standby->safe_psql('postgres', "CREATE TABLE tab_int AS SELECT 1 AS a"); 98 99# Wait for the replication to catch up 100$node_standby->wait_for_catchup($node_cascade, 'replay', 101 $node_standby->lsn('insert')); 102 103# Check that cascading standby has the new content 104my $result = 105 $node_cascade->safe_psql('postgres', "SELECT count(*) FROM tab_int"); 106print "cascade: $result\n"; 107is($result, 1, 'check streamed content on cascade standby'); 108