Skip to content

Commit 87ac09a

Browse files
alterego655Commitfest Bot
authored andcommitted
Use WAIT FOR LSN in PostgreSQL::Test::Cluster::wait_for_catchup()
Replace polling-based catchup waiting with WAIT FOR LSN command when running on a standby server. This is more efficient than repeatedly querying pg_stat_replication as the WAIT FOR command uses the latch- based wakeup mechanism. The optimization applies when: - The node is in recovery (standby server) - The mode is 'replay', 'write', or 'flush' (not 'sent') For 'sent' mode or when running on a primary, the function falls back to the original polling approach since WAIT FOR LSN is only available during recovery.
1 parent 488388a commit 87ac09a

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

src/test/perl/PostgreSQL/Test/Cluster.pm

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3335,6 +3335,9 @@ sub wait_for_catchup
33353335
$mode = defined($mode) ? $mode : 'replay';
33363336
my %valid_modes =
33373337
('sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1);
3338+
my $isrecovery =
3339+
$self->safe_psql('postgres', "SELECT pg_is_in_recovery()");
3340+
chomp($isrecovery);
33383341
croak "unknown mode $mode for 'wait_for_catchup', valid modes are "
33393342
. join(', ', keys(%valid_modes))
33403343
unless exists($valid_modes{$mode});
@@ -3347,9 +3350,6 @@ sub wait_for_catchup
33473350
}
33483351
if (!defined($target_lsn))
33493352
{
3350-
my $isrecovery =
3351-
$self->safe_psql('postgres', "SELECT pg_is_in_recovery()");
3352-
chomp($isrecovery);
33533353
if ($isrecovery eq 't')
33543354
{
33553355
$target_lsn = $self->lsn('replay');
@@ -3367,6 +3367,35 @@ sub wait_for_catchup
33673367
. $self->name . "\n";
33683368
# Before release 12 walreceiver just set the application name to
33693369
# "walreceiver"
3370+
3371+
# Use WAIT FOR LSN when in recovery for supported modes (replay, write, flush)
3372+
# This is more efficient than polling pg_stat_replication
3373+
if (($mode ne 'sent') && ($isrecovery eq 't'))
3374+
{
3375+
my $timeout = $PostgreSQL::Test::Utils::timeout_default;
3376+
# Map mode names to WAIT FOR LSN MODE values (uppercase)
3377+
my $wait_mode = uc($mode);
3378+
my $query =
3379+
qq[WAIT FOR LSN '${target_lsn}' MODE ${wait_mode} WITH (timeout '${timeout}s', no_throw);];
3380+
my $output = $self->safe_psql('postgres', $query);
3381+
chomp($output);
3382+
3383+
if ($output ne 'success')
3384+
{
3385+
# Fetch additional detail for debugging purposes
3386+
$query = qq[SELECT * FROM pg_catalog.pg_stat_replication];
3387+
my $details = $self->safe_psql('postgres', $query);
3388+
diag qq(WAIT FOR LSN failed with status:
3389+
${output});
3390+
diag qq(Last pg_stat_replication contents:
3391+
${details});
3392+
croak "failed waiting for catchup";
3393+
}
3394+
print "done\n";
3395+
return;
3396+
}
3397+
3398+
# Polling for 'sent' mode or when not in recovery (WAIT FOR LSN not applicable)
33703399
my $query = qq[SELECT '$target_lsn' <= ${mode}_lsn AND state = 'streaming'
33713400
FROM pg_catalog.pg_stat_replication
33723401
WHERE application_name IN ('$standby_name', 'walreceiver')];

0 commit comments

Comments
 (0)