Skip to content

Commit 63e59c2

Browse files
committed
In WAL replay, restore GIN metapage unconditionally to avoid torn page.
We don't take a full-page image of the GIN metapage; instead, the WAL record contains all the information required to reconstruct it from scratch. But to avoid torn page hazards, we must re-initialize it from the WAL record every time, even if it already has a greater LSN, similar to how normal full page images are restored. This was highly unlikely to cause any problems in practice, because the GIN metapage is small. We rely on an update smaller than a 512 byte disk sector to be atomic elsewhere, at least in pg_control. But better safe than sorry, and this would be easy to overlook if more fields are added to the metapage so that it's no longer small. Reported by Noah Misch. Backpatch to all supported versions.
1 parent 080ad91 commit 63e59c2

File tree

1 file changed

+13
-14
lines changed

1 file changed

+13
-14
lines changed

src/backend/access/gin/ginxlog.c

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -514,18 +514,20 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record)
514514
Page metapage;
515515
Buffer buffer;
516516

517+
/*
518+
* Restore the metapage. This is essentially the same as a full-page image,
519+
* so restore the metapage unconditionally without looking at the LSN, to
520+
* avoid torn page hazards.
521+
*/
517522
metabuffer = XLogReadBuffer(data->node, GIN_METAPAGE_BLKNO, false);
518523
if (!BufferIsValid(metabuffer))
519524
return; /* assume index was deleted, nothing to do */
520525
metapage = BufferGetPage(metabuffer);
521526

522-
if (!XLByteLE(lsn, PageGetLSN(metapage)))
523-
{
524-
memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
525-
PageSetLSN(metapage, lsn);
526-
PageSetTLI(metapage, ThisTimeLineID);
527-
MarkBufferDirty(metabuffer);
528-
}
527+
memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
528+
PageSetLSN(metapage, lsn);
529+
PageSetTLI(metapage, ThisTimeLineID);
530+
MarkBufferDirty(metabuffer);
529531

530532
if (data->ntuples > 0)
531533
{
@@ -678,13 +680,10 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record)
678680
return; /* assume index was deleted, nothing to do */
679681
metapage = BufferGetPage(metabuffer);
680682

681-
if (!XLByteLE(lsn, PageGetLSN(metapage)))
682-
{
683-
memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
684-
PageSetLSN(metapage, lsn);
685-
PageSetTLI(metapage, ThisTimeLineID);
686-
MarkBufferDirty(metabuffer);
687-
}
683+
memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
684+
PageSetLSN(metapage, lsn);
685+
PageSetTLI(metapage, ThisTimeLineID);
686+
MarkBufferDirty(metabuffer);
688687

689688
/*
690689
* In normal operation, shiftList() takes exclusive lock on all the

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy