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.
This commit is contained in:
Heikki Linnakangas 2014-05-08 14:43:04 +03:00
parent 664ac3de7f
commit be7830596f

View File

@ -650,25 +650,24 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record)
PageSetTLI(metapage, ThisTimeLineID); PageSetTLI(metapage, ThisTimeLineID);
MarkBufferDirty(metabuffer); 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++) for (i = 0; i < data->ndeleted; i++)
{ {
Buffer buffer = XLogReadBuffer(data->node, data->toDelete[i], false); Buffer buffer;
Page page;
if (BufferIsValid(buffer)) buffer = XLogReadBuffer(data->node, data->toDelete[i], true);
{ page = BufferGetPage(buffer);
Page page = BufferGetPage(buffer); GinInitBuffer(buffer, GIN_DELETED);
if (!XLByteLE(lsn, PageGetLSN(page))) PageSetLSN(page, lsn);
{ PageSetTLI(page, ThisTimeLineID);
GinPageGetOpaque(page)->flags = GIN_DELETED; MarkBufferDirty(buffer);
PageSetLSN(page, lsn); UnlockReleaseBuffer(buffer);
PageSetTLI(page, ThisTimeLineID);
MarkBufferDirty(buffer);
}
UnlockReleaseBuffer(buffer);
}
} }
UnlockReleaseBuffer(metabuffer); UnlockReleaseBuffer(metabuffer);
} }