aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gist/gistxlog.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-08-13 15:39:08 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-09-02 15:10:28 +0300
commitf8f4227976a2cdb8ac7c611e49da03aa9e65e0d2 (patch)
tree92a7aa95ce72fbac48325761761821f8d7a742ed /src/backend/access/gist/gistxlog.c
parent26f8b99b248aae989e63ca0969a746f30b0c8c21 (diff)
downloadpostgresql-f8f4227976a2cdb8ac7c611e49da03aa9e65e0d2.tar.gz
postgresql-f8f4227976a2cdb8ac7c611e49da03aa9e65e0d2.zip
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.
Diffstat (limited to 'src/backend/access/gist/gistxlog.c')
-rw-r--r--src/backend/access/gist/gistxlog.c179
1 files changed, 78 insertions, 101 deletions
diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c
index 7d36b2ab6a3..ecc095671df 100644
--- a/src/backend/access/gist/gistxlog.c
+++ b/src/backend/access/gist/gistxlog.c
@@ -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);
-
- /* Fix follow-right data on left 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 (XLogReadBufferForRedo(lsn, record, 0, xldata->node, xldata->blkno,
+ &buffer) == BLK_NEEDS_REDO)
{
- 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);
+ page = (Page) BufferGetPage(buffer);
- /* Delete old tuples */
- if (xldata->ntodelete > 0)
- {
- int i;
- OffsetNumber *todelete = (OffsetNumber *) data;
+ data = begin + sizeof(gistxlogPageUpdate);
- data += sizeof(OffsetNumber) * xldata->ntodelete;
+ /* Delete old tuples */
+ if (xldata->ntodelete > 0)
+ {
+ int i;
+ OffsetNumber *todelete = (OffsetNumber *) data;
- for (i = 0; i < xldata->ntodelete; i++)
- PageIndexTupleDelete(page, todelete[i]);
- if (GistPageIsLeaf(page))
- GistMarkTuplesDeleted(page);
- }
+ data += sizeof(OffsetNumber) * xldata->ntodelete;
- /* add tuples */
- if (data - begin < record->xl_len)
- {
- OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
- OffsetNumberNext(PageGetMaxOffsetNumber(page));
+ for (i = 0; i < xldata->ntodelete; i++)
+ PageIndexTupleDelete(page, todelete[i]);
+ if (GistPageIsLeaf(page))
+ GistMarkTuplesDeleted(page);
+ }
- while (data - begin < record->xl_len)
+ /* add tuples */
+ if (data - begin < record->xl_len)
{
- IndexTuple itup = (IndexTuple) data;
- Size sz = IndexTupleSize(itup);
- OffsetNumber l;
-
- data += sz;
+ 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);
+ }
- 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++;
+ 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);
}
- }
- 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);
}
- PageSetLSN(page, lsn);
- MarkBufferDirty(buffer);
- UnlockReleaseBuffer(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);
+
+ if (BufferIsValid(buffer))
+ UnlockReleaseBuffer(buffer);
}
static void