From 4ded292fbfb661b6f20e5c0d44dcb67fc9ace2bf Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Thu, 5 Mar 2026 16:51:28 +0100 Subject: [PATCH v13 02/19] Use GetXLogInsertEndRecPtr in XLogGetFakeLSN 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(). This is a long-standing bug in gistGetFakeLSN(), probably introduced by c6b92041d38. The fake LSN approach was generalized to other index types, inheriting the same bug. Discussion: https://postgr.es/m/vf4hbwrotvhbgcnknrqmfbqlu75oyjkmausvy66ic7x7vuhafx@e4rvwavtjswo --- src/include/access/xlog.h | 1 + src/backend/access/transam/xlog.c | 16 ++++++++++++++++ src/backend/access/transam/xloginsert.c | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 553d6fc9c..dcc12eb8c 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); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 92e44a501..2b6e61201 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -9623,6 +9623,22 @@ GetXLogInsertRecPtr(void) return XLogBytePosToRecPtr(current_bytepos); } +/* + * Get latest WAL insert 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/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 4e049982f..14a55c7ad 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -598,7 +598,7 @@ XLogGetFakeLSN(Relation rel) * last call. */ static XLogRecPtr lastlsn = InvalidXLogRecPtr; - XLogRecPtr currlsn = GetXLogInsertRecPtr(); + XLogRecPtr currlsn = GetXLogInsertEndRecPtr(); Assert(!RelationNeedsWAL(rel)); Assert(RelationIsPermanent(rel)); -- 2.53.0