aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginxlog.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-05-08 14:43:04 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-05-08 14:50:22 +0300
commit4f7bb4b2a36facc94a1d6b821ec6733093aa9bc6 (patch)
tree71645d9fe72a3b438d34bea1f9bf811f64f331e8 /src/backend/access/gin/ginxlog.c
parent02c9a938057ecb811c65999577d32c5f5e9c99dc (diff)
downloadpostgresql-4f7bb4b2a36facc94a1d6b821ec6733093aa9bc6.tar.gz
postgresql-4f7bb4b2a36facc94a1d6b821ec6733093aa9bc6.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.
Diffstat (limited to 'src/backend/access/gin/ginxlog.c')
-rw-r--r--src/backend/access/gin/ginxlog.c26
1 files changed, 13 insertions, 13 deletions
diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c
index a8a917a9d0e..7f93ce6526f 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);
-
- if (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);
- MarkBufferDirty(buffer);
- }
+ PageSetLSN(page, lsn);
+ MarkBufferDirty(buffer);
- UnlockReleaseBuffer(buffer);
- }
+ UnlockReleaseBuffer(buffer);
}
UnlockReleaseBuffer(metabuffer);
}