summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-03-12 09:59:49 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-03-12 10:10:04 +0200
commite2bccdfccd13e191c28084d05347ba0d1208cf5e (patch)
tree8df5a2555be861318bd7a054ec1c1cd5f6ae6ba0
parentd411d6eff1b7e91de0fecece08acc6b6eca04d6d (diff)
downloadpostgresql-e2bccdfccd13e191c28084d05347ba0d1208cf5e.tar.gz
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.
-rw-r--r--src/backend/access/gin/ginxlog.c27
1 files changed, 13 insertions, 14 deletions
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index c9f611d936..f66938a130 100644
--- a/src/backend/access/gin/ginxlog.c
+++ b/src/backend/access/gin/ginxlog.c
@@ -487,18 +487,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)
{
@@ -637,13 +639,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);
for (i = 0; i < data->ndeleted; i++)
{