Skip to content

Commit 3457292

Browse files
committed
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.
1 parent cd7df10 commit 3457292

File tree

1 file changed

+13
-13
lines changed

1 file changed

+13
-13
lines changed

src/backend/access/gin/ginxlog.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -682,25 +682,25 @@ ginRedoDeleteListPages(XLogRecPtr lsn, XLogRecord *record)
682682
* cannot get past a reader that is on, or due to visit, any page we are
683683
* going to delete. New incoming readers will block behind our metapage
684684
* lock and then see a fully updated page list.
685+
*
686+
* No full-page images are taken of the deleted pages. Instead, they are
687+
* re-initialized as empty, deleted pages. Their right-links don't need to
688+
* be preserved, because no new readers can see the pages, as explained
689+
* above.
685690
*/
686691
for (i = 0; i < data->ndeleted; i++)
687692
{
688-
Buffer buffer = XLogReadBuffer(data->node, data->toDelete[i], false);
693+
Buffer buffer;
694+
Page page;
689695

690-
if (BufferIsValid(buffer))
691-
{
692-
Page page = BufferGetPage(buffer);
693-
694-
if (lsn > PageGetLSN(page))
695-
{
696-
GinPageGetOpaque(page)->flags = GIN_DELETED;
696+
buffer = XLogReadBuffer(data->node, data->toDelete[i], true);
697+
page = BufferGetPage(buffer);
698+
GinInitBuffer(buffer, GIN_DELETED);
697699

698-
PageSetLSN(page, lsn);
699-
MarkBufferDirty(buffer);
700-
}
700+
PageSetLSN(page, lsn);
701+
MarkBufferDirty(buffer);
701702

702-
UnlockReleaseBuffer(buffer);
703-
}
703+
UnlockReleaseBuffer(buffer);
704704
}
705705
UnlockReleaseBuffer(metabuffer);
706706
}

0 commit comments

Comments
 (0)