}
}
+# Run a query once a second, until it returns 't' (i.e. SQL boolean true).
+sub poll_query_until
+{
+ my ($query, $connstr) = @_;
+
+ my $max_attempts = 30;
+ my $attempts = 0;
+ my ($stdout, $stderr);
+
+ while ($attempts < $max_attempts)
+ {
+ my $cmd = ['psql', '-At', '-c', "$query", '-d', "$connstr" ];
+ my $result = run $cmd, '>', \$stdout, '2>', \$stderr;
+
+ chomp($stdout);
+ if ($stdout eq "t")
+ {
+ return 1;
+ }
+
+ # Wait a second before retrying.
+ sleep 1;
+ $attempts++;
+ }
+
+ # The query result didn't change in 30 seconds. Give up. Print the stderr
+ # from the last attempt, hopefully that's useful for debugging.
+ diag $stderr;
+ return 0;
+}
+
sub append_to_file
{
my($filename, $str) = @_;
# Base backup is taken with xlog files included
system_or_bail("pg_basebackup -D $test_standby_datadir -p $port_master -x >>$log_path 2>&1");
append_to_file("$test_standby_datadir/recovery.conf", qq(
-primary_conninfo='$connstr_master'
+primary_conninfo='$connstr_master application_name=rewind_standby'
standby_mode=on
recovery_target_timeline='latest'
));
# Start standby
system_or_bail("pg_ctl -w -D $test_standby_datadir -o \"-k $tempdir_short --listen-addresses='' -p $port_standby\" start >>$log_path 2>&1");
- # sleep a bit to make sure the standby has caught up.
- sleep 1;
+ # Wait until the standby has caught up with the primary, by polling
+ # pg_stat_replication.
+ my $caughtup_query = "SELECT pg_current_xlog_location() = replay_location FROM pg_stat_replication WHERE application_name = 'rewind_standby';";
+ poll_query_until($caughtup_query, $connstr_master)
+ or die "Timed out while waiting for standby to catch up";
}
sub promote_standby
# up standby
# Now promote slave and insert some new data on master, this will put
- # the master out-of-sync with the standby.
+ # the master out-of-sync with the standby. Wait until the standby is
+ # out of recovery mode, and is ready to accept read-write connections.
system_or_bail("pg_ctl -w -D $test_standby_datadir promote >>$log_path 2>&1");
- sleep 2;
+ poll_query_until("SELECT NOT pg_is_in_recovery()", $connstr_standby)
+ or die "Timed out while waiting for promotion of standby";
}
sub run_pg_rewind