mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Refactor per-page logic common to all redo routines to a new function.
Every redo routine uses the same idiom to determine what to do to a page: check if there's a backup block for it, and if not read, the buffer if the block exists, and check its LSN. Refactor that into a common function, XLogReadBufferForRedo, making all the redo routines shorter and more readable. This has no user-visible effect, and makes no changes to the WAL format. Reviewed by Andres Freund, Alvaro Herrera, Michael Paquier.
This commit is contained in:
@ -48,31 +48,26 @@ gistRedoClearFollowRight(XLogRecPtr lsn, XLogRecord *record, int block_index,
|
||||
{
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
|
||||
if (record->xl_info & XLR_BKP_BLOCK(block_index))
|
||||
buffer = RestoreBackupBlock(lsn, record, block_index, false, true);
|
||||
else
|
||||
{
|
||||
buffer = XLogReadBuffer(node, childblkno, false);
|
||||
if (!BufferIsValid(buffer))
|
||||
return; /* page was deleted, nothing to do */
|
||||
}
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
XLogRedoAction action;
|
||||
|
||||
/*
|
||||
* Note that we still update the page even if page LSN is equal to the LSN
|
||||
* of this record, because the updated NSN is not included in the full
|
||||
* page image.
|
||||
* Note that we still update the page even if it was restored from a full
|
||||
* page image, because the updated NSN is not included in the image.
|
||||
*/
|
||||
if (lsn >= PageGetLSN(page))
|
||||
action = XLogReadBufferForRedo(lsn, record, block_index, node, childblkno,
|
||||
&buffer);
|
||||
if (action == BLK_NEEDS_REDO || action == BLK_RESTORED)
|
||||
{
|
||||
page = BufferGetPage(buffer);
|
||||
|
||||
GistPageSetNSN(page, lsn);
|
||||
GistClearFollowRight(page);
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
MarkBufferDirty(buffer);
|
||||
}
|
||||
UnlockReleaseBuffer(buffer);
|
||||
if (BufferIsValid(buffer))
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -87,104 +82,86 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record)
|
||||
Page page;
|
||||
char *data;
|
||||
|
||||
/*
|
||||
* We need to acquire and hold lock on target page while updating the left
|
||||
* child page. If we have a full-page image of target page, getting the
|
||||
* lock is a side-effect of restoring that image. Note that even if the
|
||||
* target page no longer exists, we'll still attempt to replay the change
|
||||
* on the child page.
|
||||
*/
|
||||
if (record->xl_info & XLR_BKP_BLOCK(0))
|
||||
buffer = RestoreBackupBlock(lsn, record, 0, false, true);
|
||||
else
|
||||
buffer = XLogReadBuffer(xldata->node, xldata->blkno, false);
|
||||
if (XLogReadBufferForRedo(lsn, record, 0, xldata->node, xldata->blkno,
|
||||
&buffer) == BLK_NEEDS_REDO)
|
||||
{
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
/* Fix follow-right data on left child page */
|
||||
data = begin + sizeof(gistxlogPageUpdate);
|
||||
|
||||
/* Delete old tuples */
|
||||
if (xldata->ntodelete > 0)
|
||||
{
|
||||
int i;
|
||||
OffsetNumber *todelete = (OffsetNumber *) data;
|
||||
|
||||
data += sizeof(OffsetNumber) * xldata->ntodelete;
|
||||
|
||||
for (i = 0; i < xldata->ntodelete; i++)
|
||||
PageIndexTupleDelete(page, todelete[i]);
|
||||
if (GistPageIsLeaf(page))
|
||||
GistMarkTuplesDeleted(page);
|
||||
}
|
||||
|
||||
/* add tuples */
|
||||
if (data - begin < record->xl_len)
|
||||
{
|
||||
OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
|
||||
OffsetNumberNext(PageGetMaxOffsetNumber(page));
|
||||
|
||||
while (data - begin < record->xl_len)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) data;
|
||||
Size sz = IndexTupleSize(itup);
|
||||
OffsetNumber l;
|
||||
|
||||
data += sz;
|
||||
|
||||
l = PageAddItem(page, (Item) itup, sz, off, false, false);
|
||||
if (l == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to GiST index page, size %d bytes",
|
||||
(int) sz);
|
||||
off++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* special case: leafpage, nothing to insert, nothing to delete,
|
||||
* then vacuum marks page
|
||||
*/
|
||||
if (GistPageIsLeaf(page) && xldata->ntodelete == 0)
|
||||
GistClearTuplesDeleted(page);
|
||||
}
|
||||
|
||||
if (!GistPageIsLeaf(page) &&
|
||||
PageGetMaxOffsetNumber(page) == InvalidOffsetNumber &&
|
||||
xldata->blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
/*
|
||||
* all links on non-leaf root page was deleted by vacuum full, so
|
||||
* root page becomes a leaf
|
||||
*/
|
||||
GistPageSetLeaf(page);
|
||||
}
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
MarkBufferDirty(buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix follow-right data on left child page
|
||||
*
|
||||
* This must be done while still holding the lock on the target page. Note
|
||||
* that even if the target page no longer exists, we still attempt to
|
||||
* replay the change on the child page.
|
||||
*/
|
||||
if (BlockNumberIsValid(xldata->leftchild))
|
||||
gistRedoClearFollowRight(lsn, record, 1,
|
||||
xldata->node, xldata->leftchild);
|
||||
|
||||
/* Done if target page no longer exists */
|
||||
if (!BufferIsValid(buffer))
|
||||
return;
|
||||
|
||||
/* nothing more to do if page was backed up (and no info to do it with) */
|
||||
if (record->xl_info & XLR_BKP_BLOCK(0))
|
||||
{
|
||||
if (BufferIsValid(buffer))
|
||||
UnlockReleaseBuffer(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
||||
/* nothing more to do if change already applied */
|
||||
if (lsn <= PageGetLSN(page))
|
||||
{
|
||||
UnlockReleaseBuffer(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
data = begin + sizeof(gistxlogPageUpdate);
|
||||
|
||||
/* Delete old tuples */
|
||||
if (xldata->ntodelete > 0)
|
||||
{
|
||||
int i;
|
||||
OffsetNumber *todelete = (OffsetNumber *) data;
|
||||
|
||||
data += sizeof(OffsetNumber) * xldata->ntodelete;
|
||||
|
||||
for (i = 0; i < xldata->ntodelete; i++)
|
||||
PageIndexTupleDelete(page, todelete[i]);
|
||||
if (GistPageIsLeaf(page))
|
||||
GistMarkTuplesDeleted(page);
|
||||
}
|
||||
|
||||
/* add tuples */
|
||||
if (data - begin < record->xl_len)
|
||||
{
|
||||
OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
|
||||
OffsetNumberNext(PageGetMaxOffsetNumber(page));
|
||||
|
||||
while (data - begin < record->xl_len)
|
||||
{
|
||||
IndexTuple itup = (IndexTuple) data;
|
||||
Size sz = IndexTupleSize(itup);
|
||||
OffsetNumber l;
|
||||
|
||||
data += sz;
|
||||
|
||||
l = PageAddItem(page, (Item) itup, sz, off, false, false);
|
||||
if (l == InvalidOffsetNumber)
|
||||
elog(ERROR, "failed to add item to GiST index page, size %d bytes",
|
||||
(int) sz);
|
||||
off++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* special case: leafpage, nothing to insert, nothing to delete, then
|
||||
* vacuum marks page
|
||||
*/
|
||||
if (GistPageIsLeaf(page) && xldata->ntodelete == 0)
|
||||
GistClearTuplesDeleted(page);
|
||||
}
|
||||
|
||||
if (!GistPageIsLeaf(page) &&
|
||||
PageGetMaxOffsetNumber(page) == InvalidOffsetNumber &&
|
||||
xldata->blkno == GIST_ROOT_BLKNO)
|
||||
{
|
||||
/*
|
||||
* all links on non-leaf root page was deleted by vacuum full, so root
|
||||
* page becomes a leaf
|
||||
*/
|
||||
GistPageSetLeaf(page);
|
||||
}
|
||||
|
||||
PageSetLSN(page, lsn);
|
||||
MarkBufferDirty(buffer);
|
||||
UnlockReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Reference in New Issue
Block a user