]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Use GetXLogInsertEndRecPtr in gistGetFakeLSN
authorTomas Vondra <tomas.vondra@postgresql.org>
Fri, 13 Mar 2026 21:42:29 +0000 (22:42 +0100)
committerTomas Vondra <tomas.vondra@postgresql.org>
Fri, 13 Mar 2026 22:26:49 +0000 (23:26 +0100)
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 <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

src/backend/access/gist/gistutil.c
src/backend/access/transam/xlog.c
src/include/access/xlog.h

index 43ba03b6eb97cd523ccee974c5a93356fd5f1679..2a72bb7cb27354197415779bd05574308c951183 100644 (file)
@@ -1042,7 +1042,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));
index 3fb17ff69a91a5678b07c394fab857da6288d923..ec84c77ddfa43a84e8cffbe10e57b39ea8dffc90 100644 (file)
@@ -12166,6 +12166,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
  */
index a0706c06a79178279b1ce0f1ffe1cb8e2ca8dbd4..570b0e34558d7f42fee15efca6e54ac7699f5d04 100644 (file)
@@ -318,6 +318,7 @@ extern bool XLogInsertAllowed(void);
 extern void GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream);
 extern XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI);
 extern XLogRecPtr GetXLogInsertRecPtr(void);
+extern XLogRecPtr GetXLogInsertEndRecPtr(void);
 extern XLogRecPtr GetXLogWriteRecPtr(void);
 extern RecoveryPauseState GetRecoveryPauseState(void);
 extern void SetRecoveryPause(bool recoveryPause);