Skip to content

Commit d1166af

Browse files
committed
Fix WAL format incompatibility introduced by backpatching of 52ac6cd
52ac6cd added new field to ginxlogDeletePage and was backpatched to 9.4. That led to problems when patched postgres instance applies WAL records generated by non-patched one. WAL records generated by non-patched instance don't contain new field, which patched one is expecting to see. Thankfully, we can distinguish patched and non-patched WAL records by their data size. If we see that WAL record is generated by non-patched instance, we skip processing of new field. This commit comes with some assertions. In particular, if it appears that on some platform struct data size didn't change then static assertion will trigger. Reported-by: Simon Riggs Discussion: https://postgr.es/m/CANP8%2Bj%2BK4whxf7ET7%2BgO%2BG-baC3-WxqqH%3DnV4X2CgfEPA3Yu3g%40mail.gmail.com Author: Alexander Korotkov Reviewed-by: Simon Riggs, Alvaro Herrera Backpatch-through: 9.4
1 parent 432356a commit d1166af

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

src/backend/access/gin/ginxlog.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,12 +720,30 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
720720
else
721721
{
722722
dbuffer = XLogReadBuffer(data->node, data->blkno, false);
723+
724+
/*
725+
* deleteXid field of ginxlogDeletePage was added during backpatching.
726+
* But, non-backpatched instances will continue generate WAL without
727+
* this field. We should be able to correctly apply that. We can
728+
* distinguish new WAL records by size their data, because
729+
* ginxlogDeletePage changes its size on both 32-bit and 64-bit
730+
* platforms.
731+
*/
732+
StaticAssertStmt(sizeof(ginxlogDeletePage) !=
733+
sizeof(ginxlogDeletePageOld),
734+
"ginxlogDeletePage size should be changed "
735+
"with addition of deleteXid field");
736+
Assert(record->xl_len == sizeof(ginxlogDeletePage) ||
737+
record->xl_len == sizeof(ginxlogDeletePageOld));
738+
723739
if (BufferIsValid(dbuffer))
724740
{
725741
page = BufferGetPage(dbuffer);
726742
if (lsn > PageGetLSN(page))
727743
{
728744
Assert(GinPageIsData(page));
745+
if (record->xl_len == sizeof(ginxlogDeletePage))
746+
GinPageSetDeleteXid(page, data->deleteXid);
729747
GinPageGetOpaque(page)->flags = GIN_DELETED;
730748
PageSetLSN(page, lsn);
731749
MarkBufferDirty(dbuffer);

src/include/access/gin_private.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,20 @@ typedef struct ginxlogDeletePage
586586
TransactionId deleteXid; /* last Xid which could see this page in scan */
587587
} ginxlogDeletePage;
588588

589+
/*
590+
* Previous version of ginxlogDeletePage struct, which didn't have deleteXid
591+
* field. Used for size comparison (see ginRedoDeletePage()).
592+
*/
593+
typedef struct ginxlogDeletePageOld
594+
{
595+
RelFileNode node;
596+
BlockNumber blkno;
597+
BlockNumber parentBlkno;
598+
OffsetNumber parentOffset;
599+
BlockNumber leftBlkno;
600+
BlockNumber rightLink;
601+
} ginxlogDeletePageOld;
602+
589603
#define XLOG_GIN_UPDATE_META_PAGE 0x60
590604

591605
typedef struct ginxlogUpdateMeta

0 commit comments

Comments
 (0)