postgres.git / summary / log / commit / refs

commit    91f932cf47fd0e0825b2ec92a06d24648d1ff128
Author:   Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date:     Wed Mar 12 07:59:49 2014 +0000
First released in: 9.4.0, 8.4.21, 9.0.17, 9.1.13, 9.2.8, 9.3.4

    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.


src/backend/access/gin/ginxlog.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 4536c9c63dc..bd4b0427f50 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -513,18 +513,20 @@ ginRedoUpdateMetapage(XLogRecPtr lsn, XLogRecord *record) Page metapage; Buffer buffer; + /* + * Restore the metapage. This is essentially the same as a full-page image, + * so restore the metapage unconditionally without looking at the LSN, to + * avoid torn page hazards. + */ metabuffer = XLogReadBuffer(data->node, GIN_METAPAGE_BLKNO, false); if (!BufferIsValid(metabuffer)) return; /* assume index was deleted, nothing to do */ metapage = BufferGetPage(metabuffer); - if (!XLByteLE(lsn, PageGetLSN(metapage))) - { - memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData)); - PageSetLSN(metapage, lsn); - PageSetTLI(metapage, ThisTimeLineID); - MarkBufferDirty(metabuffer); - } + memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData)); + PageSetLSN(metapage, lsn); + PageSetTLI(metapage, ThisTimeLineID); + MarkBufferDirty(metabuffer); if (data->ntuples > 0) { @@ -677,13 +679,10 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record) return; /* assume index was deleted, nothing to do */ metapage = BufferGetPage(metabuffer); - if (!XLByteLE(lsn, PageGetLSN(metapage))) - { - memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData)); - PageSetLSN(metapage, lsn); - PageSetTLI(metapage, ThisTimeLineID); - MarkBufferDirty(metabuffer); - } + memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData)); + PageSetLSN(metapage, lsn); + PageSetTLI(metapage, ThisTimeLineID); + MarkBufferDirty(metabuffer); /* * In normal operation, shiftList() takes exclusive lock on all the [parent: b315b767f7a3]