From: Heikki Linnakangas Date: Thu, 8 May 2014 11:43:04 +0000 (+0300) Subject: Protect against torn pages when deleting GIN list pages. X-Git-Tag: REL8_4_22~33 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=be7830596f333b70243661b70e09a783ed57b497;p=postgresql Protect against torn pages when deleting GIN list pages. To-be-deleted list pages contain no useful information, as they are being deleted, but we must still protect the writes from being torn by a crash after a partial write. To do that, re-initialize the pages on WAL replay. Jeff Janes caught this with a test program to test partial writes. Backpatch to all supported versions. --- diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 2344ec25bc..de0a2ed796 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -650,25 +650,24 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record) PageSetTLI(metapage, ThisTimeLineID); MarkBufferDirty(metabuffer); + /* + * No full-page images are taken of the deleted pages. Instead, they are + * re-initialized as empty, deleted pages. + */ for (i = 0; i < data->ndeleted; i++) { - Buffer buffer = XLogReadBuffer(data->node, data->toDelete[i], false); + Buffer buffer; + Page page; - if (BufferIsValid(buffer)) - { - Page page = BufferGetPage(buffer); - - if (!XLByteLE(lsn, PageGetLSN(page))) - { - GinPageGetOpaque(page)->flags = GIN_DELETED; + buffer = XLogReadBuffer(data->node, data->toDelete[i], true); + page = BufferGetPage(buffer); + GinInitBuffer(buffer, GIN_DELETED); - PageSetLSN(page, lsn); - PageSetTLI(page, ThisTimeLineID); - MarkBufferDirty(buffer); - } + PageSetLSN(page, lsn); + PageSetTLI(page, ThisTimeLineID); + MarkBufferDirty(buffer); - UnlockReleaseBuffer(buffer); - } + UnlockReleaseBuffer(buffer); } UnlockReleaseBuffer(metabuffer); }