From 92537befabccbbd8e5e16f14f7cf3f25b4562399 Mon Sep 17 00:00:00 2001 From: Zhijie Hou Date: Wed, 27 May 2026 15:58:05 +0800 Subject: [PATCH v5] Add TAP test for WAL recycling during REPACK CONCURRENTLY Following 45b0298 which allows old WAL recycling during REPACK CONCURRENTLY, this commit adds a TAP test to verify the intended behavior and helps prevent future regressions in WAL retention during long-running REPACK CONCURRENTLY operations. --- .../recovery/t/046_checkpoint_logical_slot.pl | 83 +++++++++++++++++++ 1 file changed, 83 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..778bdf42406 100644 --- a/src/test/recovery/t/046_checkpoint_logical_slot.pl +++ b/src/test/recovery/t/046_checkpoint_logical_slot.pl @@ -226,4 +226,87 @@ is( $standby->safe_psql( "t", 'logical slot is not invalidated'); +# Clean up old replication slots that might interfere with later WAL removal +# tests. +$standby->stop; +$primary->safe_psql('postgres', + q{SELECT pg_drop_replication_slot('slot_logical'); + SELECT pg_drop_replication_slot('slot_physical'); + SELECT pg_drop_replication_slot('failover_slot'); + SELECT pg_drop_replication_slot('phys_slot');}); + +# 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