From 4f7bb4b2a36facc94a1d6b821ec6733093aa9bc6 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Thu, 8 May 2014 14:43:04 +0300 Subject: [PATCH] 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. --- src/backend/access/gin/ginxlog.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index a8a917a9d0..7f93ce6526 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -884,25 +884,25 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record) * cannot get past a reader that is on, or due to visit, any page we are * going to delete. New incoming readers will block behind our metapage * lock and then see a fully updated page list. + * + * No full-page images are taken of the deleted pages. Instead, they are + * re-initialized as empty, deleted pages. Their right-links don't need to + * be preserved, because no new readers can see the pages, as explained + * above. */ 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); + buffer = XLogReadBuffer(data->node, data->toDelete[i], true); + page = BufferGetPage(buffer); + GinInitBuffer(buffer, GIN_DELETED); - if (lsn > PageGetLSN(page)) - { - GinPageGetOpaque(page)->flags = GIN_DELETED; + PageSetLSN(page, lsn); + MarkBufferDirty(buffer); - PageSetLSN(page, lsn); - MarkBufferDirty(buffer); - } - - UnlockReleaseBuffer(buffer); - } + UnlockReleaseBuffer(buffer); } UnlockReleaseBuffer(metabuffer); }