aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlogutils.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/transam/xlogutils.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/transam/xlogutils.c')
-rw-r--r--src/backend/access/transam/xlogutils.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index b7829ff4c6d..ef827dbc404 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -242,6 +242,87 @@ XLogCheckInvalidPages(void)
invalid_page_tab = NULL;
}
+
+/*
+ * XLogReadBufferForRedo
+ * Read a page during XLOG replay
+ *
+ * Reads a block referenced by a WAL record into shared buffer cache, and
+ * determines what needs to be done to redo the changes to it. If the WAL
+ * record includes a full-page image of the page, it is restored.
+ *
+ * 'lsn' is the LSN of the record being replayed. It is compared with the
+ * page's LSN to determine if the record has already been replayed.
+ * 'rnode' and 'blkno' point to the block being replayed (main fork number
+ * is implied, use XLogReadBufferForRedoExtended for other forks).
+ * 'block_index' identifies the backup block in the record for the page.
+ *
+ * Returns one of the following:
+ *
+ * BLK_NEEDS_REDO - changes from the WAL record need to be applied
+ * BLK_DONE - block doesn't need replaying
+ * BLK_RESTORED - block was restored from a full-page image included in
+ * the record
+ * BLK_NOTFOUND - block was not found (because it was truncated away by
+ * an operation later in the WAL stream)
+ *
+ * On return, the buffer is locked in exclusive-mode, and returned in *buf.
+ * Note that the buffer is locked and returned even if it doesn't need
+ * replaying. (Getting the buffer lock is not really necessary during
+ * single-process crash recovery, but some subroutines such as MarkBufferDirty
+ * will complain if we don't have the lock. In hot standby mode it's
+ * definitely necessary.)
+ */
+XLogRedoAction
+XLogReadBufferForRedo(XLogRecPtr lsn, XLogRecord *record, int block_index,
+ RelFileNode rnode, BlockNumber blkno,
+ Buffer *buf)
+{
+ return XLogReadBufferForRedoExtended(lsn, record, block_index,
+ rnode, MAIN_FORKNUM, blkno,
+ RBM_NORMAL, false, buf);
+}
+
+/*
+ * XLogReadBufferForRedoExtended
+ * Like XLogReadBufferForRedo, but with extra options.
+ *
+ * If mode is RBM_ZERO or RBM_ZERO_ON_ERROR, if the page doesn't exist, the
+ * relation is extended with all-zeroes pages up to the referenced block
+ * number. In RBM_ZERO mode, the return value is always BLK_NEEDS_REDO.
+ *
+ * If 'get_cleanup_lock' is true, a "cleanup lock" is acquired on the buffer
+ * using LockBufferForCleanup(), instead of a regular exclusive lock.
+ */
+XLogRedoAction
+XLogReadBufferForRedoExtended(XLogRecPtr lsn, XLogRecord *record,
+ int block_index, RelFileNode rnode,
+ ForkNumber forkno, BlockNumber blkno,
+ ReadBufferMode mode, bool get_cleanup_lock,
+ Buffer *buf)
+{
+ if (record->xl_info & XLR_BKP_BLOCK(block_index))
+ {
+ *buf = RestoreBackupBlock(lsn, record, block_index,
+ get_cleanup_lock, true);
+ return BLK_RESTORED;
+ }
+ else
+ {
+ *buf = XLogReadBufferExtended(rnode, forkno, blkno, mode);
+ if (BufferIsValid(*buf))
+ {
+ LockBuffer(*buf, BUFFER_LOCK_EXCLUSIVE);
+ if (lsn <= PageGetLSN(BufferGetPage(*buf)))
+ return BLK_DONE;
+ else
+ return BLK_NEEDS_REDO;
+ }
+ else
+ return BLK_NOTFOUND;
+ }
+}
+
/*
* XLogReadBuffer
* Read a page during XLOG replay.