Persist slot invalidations before publishing them

From: Bertrand Drouvot <bertranddrouvot(dot)pg(at)gmail(dot)com>
To: pgsql-hackers(at)lists(dot)postgresql(dot)org
Cc: Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>
Subject: Persist slot invalidations before publishing them
Date: 2026-08-26 13:49:24
Message-ID: ao7u5I9OeIR72kGp@bdtpg
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi hackers,

while reviewing [1], I hit an issue due to the fact that an inactive replication
slot is marked invalid in shared memory before its new state is persisted.

If ReplicationSlotSave() errors before replacing the state file, the slot is
invalid in shared memory but still valid on disk. That sounds problematic as the
resource horizon computations could stop accounting for the slot, remove required
WAL or rows, and then an immediate restart would restore the old valid slot image.

The same issue exists in synchronize_one_slot(): it copies the invalidation from
the remote slot into the local synchronized slot before saving it. In that case,
a save error also prevents a direct retry because the next synchronization sees
the local slot as already invalid and skips it.

The InvalidatePossiblyObsoleteSlot() ordering seems to come from c6550776394e.
4ae08cd5fd19 later made those invalidations persistent but kept the same ordering.

PFA a patch series to $SUBJECT.

It introduces ReplicationSlotPersistInvalidation(), which creates an invalidated
copy of the acquired slot and writes it while the shared slot remains valid.

That means that a concurrent slot saver either writes the old valid state before
the invalidation operation, or waits and snapshots the invalid state after it has
been published. If the invalidated image can not be written, both the shared and
on disk states remain valid.

This is the same kind of idea used of effective_catalog_xmin and in 3741f2a09d52.

The patch series is organized that way:

0001: persist InvalidatePossiblyObsoleteSlot() invalidations before publishing
them.

Add ReplicationSlotPersistInvalidation(), which writes and fsyncs an invalidated
copy while the shared slot remains valid. Hold io_in_progress_lock until the
invalidation is published so checkpoints and other slot savers cannot persist
a stale image after publication.

It also adds an injection point and some tests.

0002: do the same for synchronize_one_slot().

It keeps the synchronized slot restart LSN when copying a WAL invalidation,
preserving the current behavior. It also recomputes the xmin and WAL horizons
once the invalidation is durable and visible.

It also adds some test.

Remarks:

1/ there is no new retry mechanism. A later checkpoint or synchronization
naturally retries because the shared slot remains valid after the error.

2/ the patches change neither the on disk slot format nor the ReplicationSlot
shared memory layout. It has been done that way to ease the back patching.

3/ I think 0001 should be backpatched down to 14. 14 and 15 would probably need
some adaptations though (I did not look in detail yet).

4/ 0002 should be backpatched down to 17, where failover slot synchronization was
introduced.

[1]: https://postgr.es/m/CALj2ACUi0LeqKzomuXNPFsekzuQ%2BXbWZ5RamnO6tDzG4i1-KLw%40mail.gmail.com

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachment Content-Type Size
v1-0001-Persist-slot-invalidations-before-publishing-them.patch text/x-diff 15.6 KB
v1-0002-Persist-synchronized-slot-invalidations-before-pu.patch text/x-diff 6.8 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Xuneng Zhou 2026-08-26 13:51:45 Re: timeout value overflow in wait for lsn
Previous Message Yuhang Qiu 2026-08-26 13:45:41 [PATCH] Use streaming read I/O in sample scans