From 92637401c5e77a9dcb0ad4dc6a50963aef1e6909 Mon Sep 17 00:00:00 2001 From: Hayato Kuroda Date: Fri, 3 Oct 2025 19:45:25 +0900 Subject: [PATCH] Reproduce the slot invalidation on standby --- src/test/recovery/meson.build | 3 +- .../t/050_invalidate_new_slot_on_standby.pl | 102 ++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/test/recovery/t/050_invalidate_new_slot_on_standby.pl diff --git a/src/test/recovery/meson.build b/src/test/recovery/meson.build index 9f01d71dc3b..63439cafc25 100644 --- a/src/test/recovery/meson.build +++ b/src/test/recovery/meson.build @@ -55,7 +55,8 @@ tests += { 't/045_archive_restartpoint.pl', 't/046_checkpoint_logical_slot.pl', 't/047_checkpoint_physical_slot.pl', - 't/048_vacuum_horizon_floor.pl' + 't/048_vacuum_horizon_floor.pl', + 't/050_invalidate_new_slot_on_standby.pl' ], }, } diff --git a/src/test/recovery/t/050_invalidate_new_slot_on_standby.pl b/src/test/recovery/t/050_invalidate_new_slot_on_standby.pl new file mode 100644 index 00000000000..bd72d948f39 --- /dev/null +++ b/src/test/recovery/t/050_invalidate_new_slot_on_standby.pl @@ -0,0 +1,102 @@ +# This test checks that the new logical slot maybe invalidated on standby +# +# In this test some WAL segments are generated in-between the restart_lsn of +# the slot is set and instance started to protect it. +# Here we enure that checkpointer does not recycle segments needed by the slot. + +use strict; +use warnings FATAL => 'all'; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + + +if ($ENV{enable_injection_points} ne 'yes') +{ + plan skip_all => 'Injection points not supported by this build'; +} + +# Setup primary node +my $primary = PostgreSQL::Test::Cluster->new('primary'); +$primary->init(allows_streaming => 1); +$primary->append_conf( + 'postgresql.conf', qq( + wal_level = logical + log_checkpoints = on +)); +$primary->start; + +# Check if the extension injection_points is available, as it may be +# possible that this script is run with installcheck, where the module +# would not be installed by default. +my $result = $primary->safe_psql('postgres', + "SELECT count(*) > 0 FROM pg_available_extensions WHERE name = 'injection_points';" +); +if ($result eq 'f') +{ + plan skip_all => 'Extension injection_points not installed'; +} +my $backup_name = 'my_backup'; +$primary->backup($backup_name); + +# Create streaming standby linking to primary +my $standby = PostgreSQL::Test::Cluster->new('standby'); +$standby->init_from_backup($primary, $backup_name, has_streaming => 1); +$standby->start; + +# Dummy table for the upcoming tests. +$primary->safe_psql('postgres', 'checkpoint'); +$primary->safe_psql('postgres', 'CREATE TABLE prim_tab (a int);'); + +# Install the injection_points on instances +$primary->safe_psql('postgres', 'CREATE EXTENSION injection_points'); +$primary->wait_for_replay_catchup($standby); + +# Attach an injection points on standby +$result = $standby->safe_psql('postgres', + "select injection_points_attach('delay_slot_reserve_wal', 'wait')"); + +# Create a logical slot on standby. It would stop while determining the +# startpoint of logical decoding +my $createslot = $standby->background_psql('postgres', on_error_stop => 0); +$createslot->query_until( + qr/slot_create/, q( + \echo slot_create +SELECT pg_create_logical_replication_slot('logical_slot', 'test_decoding'); +\q +)); + +# Log the standby snapshot. If everthing goes well slot can be created faster +$primary->log_standby_snapshot($standby, 'logical_slot'); + +# Ensure the slot creation stops +note('waiting for injection_point'); +$standby->wait_for_event('client backend', 'delay_slot_reserve_wal'); +note('injection_point is reached'); + +$primary->advance_wal(3); + +# Do checkpoint on primary to replicate the REDO record to standby +$primary->safe_psql('postgres', 'CHECKPOINT'); +$primary->wait_for_replay_catchup($standby); + +# And do restartpoint +my $logstart = -s $standby->logfile; +$standby->safe_psql('postgres', 'CHECKPOINT'); + +# Confirs we go the restart point but the slot invalidation has not happened +ok($standby->log_contains("restartpoint starting:", $logstart), + "restartpoint has started"); + +ok( !$standby->log_contains( + "terminating process .* to release replication slot \"logical_slot\"", + $logstart), + "restartpoint invalidated the logical slot"); + +# Verify the slot is valid +$result = $standby->safe_psql('postgres', + "SELECT slot_name, invalidation_reason FROM pg_replication_slots"); +is($result, q(logical_slot|), "slot has not been invalidated"); + +done_testing(); -- 2.47.3