v4-0002-Add-a-tap-test-using-injection-point.patch
application/octet-stream
Filename: v4-0002-Add-a-tap-test-using-injection-point.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v4-0002
Subject: Add a tap-test using injection point
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlog.c | 3 | 0 |
| src/test/recovery/t/046_checkpoint_logical_slot.pl | 79 | 2 |
From a18656a6059d5605a62ffd729b10e8f2856a7df8 Mon Sep 17 00:00:00 2001
From: Zhijie Hou <houzj.fnst@fujitsu.com>
Date: Wed, 19 Nov 2025 18:25:48 +0800
Subject: [PATCH v4 2/2] Add a tap-test using injection point
---
src/backend/access/transam/xlog.c | 3 +
.../recovery/t/046_checkpoint_logical_slot.pl | 81 ++++++++++++++++++-
2 files changed, 82 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 17324259cff..56c69574238 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7838,6 +7838,9 @@ CreateRestartPoint(int flags)
replayPtr = GetXLogReplayRecPtr(&replayTLI);
endptr = (receivePtr < replayPtr) ? replayPtr : receivePtr;
KeepLogSeg(endptr, &_logSegNo);
+
+ INJECTION_POINT("restartpoint-before-slot-invalidation", NULL);
+
if (InvalidateObsoleteReplicationSlots(RS_INVAL_WAL_REMOVED | RS_INVAL_IDLE_TIMEOUT,
_logSegNo, InvalidOid,
InvalidTransactionId))
diff --git a/src/test/recovery/t/046_checkpoint_logical_slot.pl b/src/test/recovery/t/046_checkpoint_logical_slot.pl
index 0242a1573ca..339289c0b59 100644
--- a/src/test/recovery/t/046_checkpoint_logical_slot.pl
+++ b/src/test/recovery/t/046_checkpoint_logical_slot.pl
@@ -20,8 +20,7 @@ if ($ENV{enable_injection_points} ne 'yes')
my ($node, $result);
$node = PostgreSQL::Test::Cluster->new('mike');
-$node->init;
-$node->append_conf('postgresql.conf', "wal_level = 'logical'");
+$node->init(allows_streaming => 'logical');
$node->start;
# Check if the extension injection_points is available, as it may be
@@ -139,4 +138,82 @@ eval {
};
is($@, '', "Logical slot still valid");
+# Verify that while syncing a slot to the standby server, if the WAL before the
+# remote restart_lsn is at risk of being removed by a checkpoint, the slot
+# cannot be synced. Otherwise, even if the slot syncing succeeds, it may be
+# immediately invalidated by the checkpoint.
+my $primary = $node;
+
+$primary->append_conf('postgresql.conf', "autovacuum = off");
+$primary->reload;
+
+my $backup_name = 'backup';
+
+$primary->backup($backup_name);
+
+# Create a standby
+my $standby = PostgreSQL::Test::Cluster->new('standby');
+$standby->init_from_backup(
+ $primary, $backup_name,
+ has_streaming => 1,
+ has_restoring => 1);
+
+# Increase the log_min_messages setting to DEBUG2 on both the standby and
+# primary to debug test failures, if any.
+my $connstr_1 = $primary->connstr;
+$standby->append_conf(
+ 'postgresql.conf', qq(
+hot_standby_feedback = on
+primary_slot_name = 'phys_slot'
+primary_conninfo = '$connstr_1 dbname=postgres'
+log_min_messages = 'debug2'
+));
+
+$primary->psql('postgres',
+ q{SELECT pg_create_logical_replication_slot('failover_slot', 'test_decoding', false, false, true);
+ SELECT pg_create_physical_replication_slot('phys_slot');}
+);
+
+$standby->start;
+
+# Generate some activity and switch WAL file on the primary
+$primary->advance_wal(1);
+$primary->psql('postgres', "CHECKPOINT");
+$primary->wait_for_replay_catchup($standby);
+
+# checkpoint on the standby and make it wait on the injection point so that the
+# checkpoint stops right before invalidating replication slots.
+note('starting checkpoint');
+
+$checkpoint = $standby->background_psql('postgres');
+$checkpoint->query_safe(
+ q(select injection_points_attach('restartpoint-before-slot-invalidation','wait'))
+);
+$checkpoint->query_until(
+ qr/starting_checkpoint/,
+ q(\echo starting_checkpoint
+checkpoint;
+\q
+));
+
+# Wait until the checkpoint stops right before invalidating slots
+note('waiting for injection_point');
+$standby->wait_for_event('checkpointer', 'restartpoint-before-slot-invalidation');
+note('injection_point is reached');
+
+# Synchronize the failover slot to the standby
+$standby->safe_psql('postgres', "SELECT pg_sync_replication_slots();");
+
+# Confirm that the logical slot is not synced
+is( $standby->safe_psql(
+ 'postgres',
+ q{SELECT count(*) = 0 FROM pg_replication_slots WHERE slot_name = 'failover_slot';}
+ ),
+ "t",
+ 'logical slot is not synced because the required WALs could be potentially removed');
+
+$standby->safe_psql('postgres',
+ q{select injection_points_wakeup('restartpoint-before-slot-invalidation');
+ select injection_points_detach('restartpoint-before-slot-invalidation')});
+
done_testing();
--
2.51.1.windows.1