v1-0001-Fix-premature-xmin-advancement-during-fast-forwar.patch
application/octet-stream
Filename: v1-0001-Fix-premature-xmin-advancement-during-fast-forwar.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v1-0001
Subject: Fix premature xmin advancement during fast forward decoding
| File | + | − |
|---|---|---|
| src/backend/replication/logical/decode.c | 25 | 12 |
From 5327186830024769c2d893fba5859ebbdc04af29 Mon Sep 17 00:00:00 2001
From: Zhijie Hou <houzj.fnst@cn.fujitsu.com>
Date: Tue, 22 Apr 2025 10:58:35 +0800
Subject: [PATCH v1 1/2] Fix premature xmin advancement during fast forward
decoding
Fast forward decoding could lead to premature advancement of catalog_xmin,
resulting in required catalog data being removed by vacuum. The issue arise
because we do not build a base snapshot when decoding changes during fast
forward mode, preventing reference to the minimum transaction ID that remains
visible in the snapshot when determining the candidate for catalog_xmin. As a
result, catalog_xmin was directly advanced to the oldest running transaction ID
found in the latest running_xacts record.
To resolve this, the commit allows the base snapshot to be built during fast
forward decoding.
---
src/backend/replication/logical/decode.c | 37 ++++++++++++++++--------
1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/src/backend/replication/logical/decode.c b/src/backend/replication/logical/decode.c
index 78f9a0a11c4..8dc467a8bb3 100644
--- a/src/backend/replication/logical/decode.c
+++ b/src/backend/replication/logical/decode.c
@@ -412,19 +412,24 @@ heap2_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
/*
* If we don't have snapshot or we are just fast-forwarding, there is no
- * point in decoding changes.
+ * point in decoding data changes. However, it's crucial to build the base
+ * snapshot during fast-forward mode (as done in SnapBuildProcessChange())
+ * because the snapshot's minimum visible transaction ID (xmin) must be
+ * referenced when determining the candidate catalog_xmin for the
+ * replication slot.
*/
- if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT ||
- ctx->fast_forward)
+ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT)
return;
switch (info)
{
case XLOG_HEAP2_MULTI_INSERT:
- if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
DecodeMultiInsert(ctx, buf);
break;
case XLOG_HEAP2_NEW_CID:
+ if (!ctx->fast_forward)
{
xl_heap_new_cid *xlrec;
@@ -471,16 +476,20 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
/*
* If we don't have snapshot or we are just fast-forwarding, there is no
- * point in decoding data changes.
+ * point in decoding data changes. However, it's crucial to build the base
+ * snapshot during fast-forward mode (as done in SnapBuildProcessChange())
+ * because the snapshot's minimum visible transaction ID (xmin) must be
+ * referenced when determining the candidate catalog_xmin for the
+ * replication slot.
*/
- if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT ||
- ctx->fast_forward)
+ if (SnapBuildCurrentState(builder) < SNAPBUILD_FULL_SNAPSHOT)
return;
switch (info)
{
case XLOG_HEAP_INSERT:
- if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
DecodeInsert(ctx, buf);
break;
@@ -491,17 +500,20 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
*/
case XLOG_HEAP_HOT_UPDATE:
case XLOG_HEAP_UPDATE:
- if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
DecodeUpdate(ctx, buf);
break;
case XLOG_HEAP_DELETE:
- if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
DecodeDelete(ctx, buf);
break;
case XLOG_HEAP_TRUNCATE:
- if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
DecodeTruncate(ctx, buf);
break;
@@ -525,7 +537,8 @@ heap_decode(LogicalDecodingContext *ctx, XLogRecordBuffer *buf)
break;
case XLOG_HEAP_CONFIRM:
- if (SnapBuildProcessChange(builder, xid, buf->origptr))
+ if (SnapBuildProcessChange(builder, xid, buf->origptr) &&
+ !ctx->fast_forward)
DecodeSpecConfirm(ctx, buf);
break;
--
2.30.0.windows.2