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
c6b92041d3 in PG13. Backpatch to all supported versions.

Reported-by: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Noah Misch <noah@leadboat.com>
Discussion: https://postgr.es/m/vf4hbwrotvhbgcnknrqmfbqlu75oyjkmausvy66ic7x7vuhafx@e4rvwavtjswo
Backpatch-through: 14
This commit is contained in:
Tomas Vondra 2026-03-13 22:42:29 +01:00
parent 311a851436
commit b1f14c9672
3 changed files with 18 additions and 1 deletions

View file

@ -1034,7 +1034,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));

View file

@ -9595,6 +9595,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
*/

View file

@ -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);