v2-18-0001-Newly-created-replication-slot-may-be-invalidated-by.patch
text/x-patch
Filename: v2-18-0001-Newly-created-replication-slot-may-be-invalidated-by.patch
Type: text/x-patch
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 v2-0001
Subject: Newly created replication slot may be invalidated by checkpoint
| File | + | − |
|---|---|---|
| src/backend/replication/slot.c | 5 | 0 |
| src/test/recovery/t/049_invalidate_new_slot.pl | 76 | 0 |
From 7d2df5ee9681a614ca5c0c8cf8f1aa2468324657 Mon Sep 17 00:00:00 2001
From: "suyu.cmj" <mengjuan.cmj@alibaba-inc.com>
Date: Mon, 15 Sep 2025 08:44:17 +0000
Subject: [PATCH] Newly created replication slot may be invalidated by
checkpoint
Commit 2090edc6f32f652a2c995ca5f7e65748ae1e4c5d introduced a change
that the minimal restart_lsn is obtained at the start of checkpoint
creation. If a replication slot is created and performs a WAL
reservation concurrently, the WAL segment contains the new slot's
restart_lsn could be removed by the ongoing checkpoint. Add a perl
test to reproduce this scenario.
With some modification by v.davydov@postgrespro.ru
---
src/backend/replication/slot.c | 5 ++
.../recovery/t/049_invalidate_new_slot.pl | 76 +++++++++++++++++++
2 files changed, 81 insertions(+)
create mode 100644 src/test/recovery/t/049_invalidate_new_slot.pl
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 90fbe4fb837..6015b8b27c3 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -58,6 +58,7 @@
#include "utils/guc_hooks.h"
#include "utils/injection_point.h"
#include "utils/varlena.h"
+#include "utils/injection_point.h"
/*
* Replication slot on-disk data structure.
@@ -1538,6 +1539,10 @@ ReplicationSlotReserveWal(void)
slot->data.restart_lsn = restart_lsn;
SpinLockRelease(&slot->mutex);
+#ifdef USE_INJECTION_POINTS
+ INJECTION_POINT("delay_slot_reserve_wal", NULL);
+#endif
+
/* prevent WAL removal as fast as possible */
ReplicationSlotsComputeRequiredLSN();
diff --git a/src/test/recovery/t/049_invalidate_new_slot.pl b/src/test/recovery/t/049_invalidate_new_slot.pl
new file mode 100644
index 00000000000..93b09316e5f
--- /dev/null
+++ b/src/test/recovery/t/049_invalidate_new_slot.pl
@@ -0,0 +1,76 @@
+# This test checks that the new slot maybe invalidated by checkpoint
+#
+
+use strict;
+use warnings;
+use Config;
+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 $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init(allows_streaming => 1);
+
+$node->append_conf(
+ 'postgresql.conf', qq(
+ log_checkpoints = true
+ checkpoint_timeout = 3000
+));
+$node->start;
+
+my $res =
+ $node->safe_psql('postgres', "create extension injection_points;");
+
+$res = $node->safe_psql('postgres',
+ "select injection_points_attach('delay_slot_reserve_wal', 'wait')");
+
+my $createslot = $node->background_psql('postgres');
+
+$createslot->query_until(
+ qr/start-create-slot/,
+ q(\echo start-create-slot
+select pg_create_physical_replication_slot('standby1', true);
+));
+
+# Wait until the checkpoint stops right before removing WAL segments.
+note('waiting for injection_point');
+$node->wait_for_event('client backend', 'delay_slot_reserve_wal');
+note('injection_point is reached');
+
+$node->advance_wal(3);
+
+my $checkpoint = $node->background_psql('postgres');
+$checkpoint->query_safe(q{select injection_points_attach('checkpoint-before-old-wal-removal','wait')});
+$checkpoint->query_until(
+ qr/start-checkpoint/,
+ q(\echo start-checkpoint
+checkpoint;
+\q
+));
+
+# Wait until the checkpoint stops right before removing WAL segments.
+note('waiting for injection_point');
+$node->wait_for_event('checkpointer', 'checkpoint-before-old-wal-removal');
+note('injection_point is reached');
+
+# continue create slot command
+$node->safe_psql('postgres', q{select injection_points_wakeup('delay_slot_reserve_wal')});
+
+$createslot->quit();
+
+# continue checkpoint
+$node->safe_psql('postgres', q{select injection_points_wakeup('checkpoint-before-old-wal-removal')});
+
+# check if slot is invalidated
+$res = $node->safe_psql('postgres',
+ "select invalidation_reason from pg_replication_slots where slot_name='standby1'");
+print "res:$res\n";
+is($res, "wal_removed", "slot is invalidated by checkpoint");
+
+done_testing();
--
2.34.1