From 6ef36bb358842e0f3a2de0cbf622c67c808706cf Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Fri, 13 Mar 2026 22:42:29 +0100 Subject: [PATCH] Use GetXLogInsertEndRecPtr in gistGetFakeLSN The function used GetXLogInsertRecPtr() to generate the fake LSN. Most of the time this is the same as what XLogInsert() would return, and so it works fine with the XLogFlush() call. But if the last record ends at a page boundary, GetXLogInsertRecPtr() returns LSN pointing after the page header. In such case XLogFlush() fails with errors like this: ERROR: xlog flush request 0/01BD2018 is not satisfied --- flushed only to 0/01BD2000 Such failures are very hard to trigger, particularly outside aggressive test scenarios. Fixed by introducing GetXLogInsertEndRecPtr(), returning the correct LSN without skipping the header. This is the same as GetXLogInsertRecPtr(), except that it calls XLogBytePosToEndRecPtr(). Initial investigation by me, root cause identified by Andres Freund. This is a long-standing bug in gistGetFakeLSN(), probably introduced by c6b92041d38 in PG13. Backpatch to all supported versions. Reported-by: Peter Geoghegan Reviewed-by: Andres Freund Reviewed-by: Noah Misch Discussion: https://postgr.es/m/vf4hbwrotvhbgcnknrqmfbqlu75oyjkmausvy66ic7x7vuhafx@e4rvwavtjswo Backpatch-through: 14 --- src/backend/access/gist/gistutil.c | 2 +- src/backend/access/transam/xlog.c | 16 ++++++++++++++++ src/include/access/xlog.h | 1 + 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 7844c6074fe..382154d5d48 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -1033,7 +1033,7 @@ gistGetFakeLSN(Relation rel) * last call. */ static XLogRecPtr lastlsn = InvalidXLogRecPtr; - XLogRecPtr currlsn = GetXLogInsertRecPtr(); + XLogRecPtr currlsn = GetXLogInsertEndRecPtr(); /* Shouldn't be called for WAL-logging relations */ Assert(!RelationNeedsWAL(rel)); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 948cb1fc703..745276908d2 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9500,6 +9500,22 @@ GetXLogInsertRecPtr(void) return XLogBytePosToRecPtr(current_bytepos); } +/* + * Get latest WAL record end pointer + */ +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/include/access/xlog.h b/src/include/access/xlog.h index 3d8bc988861..30f5aa6f151 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -224,6 +224,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);