v1-0001-Fix-flushing-record-ending-at-page-boundary.patch
application/octet-stream
Filename: v1-0001-Fix-flushing-record-ending-at-page-boundary.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v1-0001
Subject: Fix flushing record ending at page boundary
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlog.c | 18 | 0 |
| src/backend/replication/logical/syncutils.c | 1 | 1 |
| src/backend/replication/walsender.c | 1 | 1 |
| src/include/access/xlog.h | 1 | 0 |
From 5cfdb02ef6d0697e5670356345fc89af78d1eeb9 Mon Sep 17 00:00:00 2001
From: Anthonin Bonnefoy <anthonin.bonnefoy@datadoghq.com>
Date: Thu, 12 Mar 2026 14:29:21 +0100
Subject: Fix flushing record ending at page boundary
In 6eedb2a5fd, a call to XLogFlush(GetXLogInsertRecPtr()) has been added
to allow walsender to flush the latest WAL record. However, if the last
record is at the end of a page, GetXLogInsertRecPtr() will return the
start position for the next record, which will be located in the next
page, after the page header.
XLogInsert will complain with a 'xlog flush request 0/03604018 is not
satisfied --- flushed only to 0/03604000' error, as the flush request
tries to write WAL that hasn't been reserved yet.
This patch fixes the issue by introducing and using a
GetXLogInsertEndRecPtr() which stops at the page boundary, instead of
the beginning of the next page.
---
src/backend/access/transam/xlog.c | 18 ++++++++++++++++++
src/backend/replication/logical/syncutils.c | 2 +-
src/backend/replication/walsender.c | 2 +-
src/include/access/xlog.h | 1 +
4 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index b9b678f3722..9fd90636ee1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -9595,6 +9595,24 @@ GetXLogInsertRecPtr(void)
return XLogBytePosToRecPtr(current_bytepos);
}
+/*
+ * Like GetXLogInsertRecPtr, but if the position is at a page boundary, returns
+ * a pointer to the beginning of the page (ie. before page header), not to where
+ * the first xlog record on that page would go to.
+ */
+XLogRecPtr
+GetXLogInsertEndRecPtr(void)
+{
+ XLogCtlInsert *Insert = &XLogCtl->Insert;
+ uint64 current_bytepos;
+
+ SpinLockAcquire(&Insert->insertpos_lck);
+ current_bytepos = Insert->CurrBytePos;
+ SpinLockRelease(&Insert->insertpos_lck);
+
+ return XLogBytePosToEndRecPtr(current_bytepos);
+}
+
/*
* Get latest WAL write pointer
*/
diff --git a/src/backend/replication/logical/syncutils.c b/src/backend/replication/logical/syncutils.c
index ef61ca0437d..8c5da44d42e 100644
--- a/src/backend/replication/logical/syncutils.c
+++ b/src/backend/replication/logical/syncutils.c
@@ -62,7 +62,7 @@ FinishSyncWorker(void)
}
/* And flush all writes. */
- XLogFlush(GetXLogWriteRecPtr());
+ XLogFlush(GetXLogInsertEndRecPtr());
if (am_sequencesync_worker())
{
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index 79fc192b171..dd46de7bcd6 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1887,7 +1887,7 @@ WalSndWaitForWal(XLogRecPtr loc)
* written, because walwriter has shut down already.
*/
if (got_STOPPING && !RecoveryInProgress())
- XLogFlush(GetXLogInsertRecPtr());
+ XLogFlush(GetXLogInsertEndRecPtr());
/*
* To avoid the scenario where standbys need to catch up to a newer
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index fdfb572467b..958f39edda4 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -238,6 +238,7 @@ extern bool RecoveryInProgress(void);
extern RecoveryState GetRecoveryState(void);
extern bool XLogInsertAllowed(void);
extern XLogRecPtr GetXLogInsertRecPtr(void);
+extern XLogRecPtr GetXLogInsertEndRecPtr(void);
extern XLogRecPtr GetXLogWriteRecPtr(void);
extern uint64 GetSystemIdentifier(void);
--
2.53.0