From d97df7c2ecf815907b7e14322f6f8fde09951b9b Mon Sep 17 00:00:00 2001 From: Zhijie Hou Date: Wed, 27 May 2026 15:58:05 +0800 Subject: [PATCH v3 2/2] Add a test for repack concurrently --- .../recovery/t/046_checkpoint_logical_slot.pl | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/test/recovery/t/046_checkpoint_logical_slot.pl b/src/test/recovery/t/046_checkpoint_logical_slot.pl index 66761bf56c1..aa32859dd15 100644 --- a/src/test/recovery/t/046_checkpoint_logical_slot.pl +++ b/src/test/recovery/t/046_checkpoint_logical_slot.pl @@ -226,4 +226,78 @@ is( $standby->safe_psql( "t", 'logical slot is not invalidated'); +# Verify that the REPACK slot's restart_lsn can advance while REPACK +# CONCURRENTLY is still running, allowing WAL files to be recycled during this +# period. + +# Create the table to be repacked and populate it with some data. +$node->safe_psql( + 'postgres', + q{ +CREATE TABLE repack_test(i int PRIMARY KEY, t text); +INSERT INTO repack_test +SELECT g, md5(g::text) +FROM generate_series(1, 100) g; +}); + +# Pause the REPACK command in the middle of its execution so that the decoding +# worker continues running, allowing us to test slot restart_lsn advancement +# later. +$node->safe_psql('postgres', + q(select injection_points_attach('repack-concurrently-before-lock','wait')) +); + +my $repack = $node->background_psql('postgres'); +$repack->query_until( + qr/repack_started/, + q( +\echo repack_started +REPACK (CONCURRENTLY) repack_test; +\q +)); + +# Wait until REPACK reaches the injection point. +$node->wait_for_event('client backend', 'repack-concurrently-before-lock'); + +my $restart_lsn_before = $node->safe_psql('postgres', + "SELECT restart_lsn FROM pg_replication_slots WHERE slot_name ~ '^repack_[0-9]+' AND slot_type = 'logical' AND temporary;"); + +# Verify that the replication slot created by the subscription exists and has a +# valid restart_lsn. +ok(defined($restart_lsn_before) && $restart_lsn_before ne '', + 'REPACK slot has restart_lsn'); + +my $segment_before = $node->safe_psql('postgres', + "SELECT pg_walfile_name('$restart_lsn_before')"); +my $segment_before_path = $node->data_dir . "/pg_wal/$segment_before"; +ok(-f $segment_before_path, + "segment for initial restart_lsn exists: $segment_before"); + +# Switch WAL file on the primary while REPACK is still running and then force +# WAL removal/recycling with a checkpoint. +$node->advance_wal(1); + +# Wait until the REPACK slot's restart_lsn advances +ok( $node->poll_query_until( + 'postgres', qq[ + SELECT count(*) > 0 + FROM pg_replication_slots + WHERE slot_name ~ '^repack_[0-9]+' + AND slot_type = 'logical' + AND temporary + AND restart_lsn IS NOT NULL + AND restart_lsn <> '$restart_lsn_before'::pg_lsn]), + 'REPACK slot restart_lsn advances while command is still running'); + +$node->safe_psql('postgres', 'CHECKPOINT'); + +# Test that the old WAL segment was recycled +ok(!-f $segment_before_path, + 'old WAL segment was recycled while REPACK CONCURRENTLY was running'); + +$node->safe_psql('postgres', + "SELECT injection_points_wakeup('repack-concurrently-before-lock')"); + +$repack->quit; + done_testing(); -- 2.43.0