diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2014-05-08 14:43:04 +0300 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2014-05-08 14:43:58 +0300 |
commit | 686a7194ef1676e4735bbe1c0270dc25c6f33796 (patch) | |
tree | 89a7ad2e308492a73f9c52836221db6795a7f82c | |
parent | 5c5bfc0ac3653acad439495c27c78f129668d114 (diff) | |
download | postgresql-686a7194ef1676e4735bbe1c0270dc25c6f33796.tar.gz postgresql-686a7194ef1676e4735bbe1c0270dc25c6f33796.zip |
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.
-rw-r--r-- | src/backend/access/gin/ginxlog.c | 28 |
1 files changed, 14 insertions, 14 deletions
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 0d58d4830e6..2fc65e39c28 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -699,26 +699,26 @@ 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); - - 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); } |