From: Heikki Linnakangas Date: Thu, 6 Nov 2014 13:45:00 +0000 (+0200) Subject: Clean up RestoreBackupBlock() and -Contents(). X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=faeb1041e98b7b8a1cc3ce1eaf108f94708d3bba;p=users%2Fheikki%2Fpostgres.git Clean up RestoreBackupBlock() and -Contents(). --- diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 2d371fbb11..749721f9b9 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -28,9 +28,7 @@ static Buffer RestoreBackupBlockContents(XLogRecPtr lsn, XLogRecordBlockData *bkpb, XLogRecordBlockImage *blk, - bool get_cleanup_lock, bool keep_buffer); -static Buffer RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record, - uint8 block_id, bool get_cleanup_lock, bool keep_buffer); + bool get_cleanup_lock); /* * During XLOG replay, we may see XLOG records for incremental updates of @@ -277,6 +275,15 @@ XLogCheckInvalidPages(void) * 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.) + * + * Note: when a backup block is available in XLOG, we restore it + * unconditionally, even if the page in the database appears newer. This is + * to protect ourselves against database pages that were partially or + * incorrectly written during a crash. We assume that the XLOG data must be + * good because it has passed a CRC check, while the database page might not + * be. This will force us to replay all subsequent modifications of the page + * that appear in XLOG, rather than possibly ignoring them as already + * applied, but that's not a huge drawback. */ XLogRedoAction XLogReadBufferForRedo(XLogRecPtr lsn, XLogRecord *record, uint8 block_id, @@ -303,17 +310,27 @@ XLogReadBufferForRedoExtended(XLogRecPtr lsn, XLogRecord *record, ReadBufferMode mode, bool get_cleanup_lock, Buffer *buf) { - struct XLogRecordBlockData *bkpb; + XLogRecordBlockData *bkpb; + char *blk; + + bkpb = XLogRecGetBlockRef(record, block_id, &blk); + if (!bkpb) + { + /* Caller specified a bogus block_id */ + elog(ERROR, "failed to locate backup block with ID %d", block_id); + } - *buf = RestoreBackupBlock(lsn, record, block_id, get_cleanup_lock, true); - if (*buf != InvalidBuffer) + /* If it's a full-page image, restore it. */ + if (bkpb->fork_flags & BKPBLOCK_HAS_IMAGE) + { + *buf = RestoreBackupBlockContents(lsn, bkpb, + (XLogRecordBlockImage *) blk, + get_cleanup_lock); + Assert(*buf != InvalidBuffer); return BLK_RESTORED; + } else { - bkpb = XLogRecGetBlockRef(record, block_id, NULL); - if (bkpb == NULL) - elog(ERROR, "failed to locate backup block with ID %d", block_id); - if ((bkpb->fork_flags & BKPBLOCK_WILL_INIT) != 0 && mode != RBM_ZERO) elog(PANIC, "block with WILL_INIT flag in WAL record must be zeroed by redo routine"); @@ -445,68 +462,12 @@ XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum, /* * Restore a full-page image from a backup block attached to an XLOG record. * - * lsn: LSN of the XLOG record being replayed - * record: the complete XLOG record - * block_id: which backup block to restore - * get_cleanup_lock: TRUE to get a cleanup rather than plain exclusive lock - * keep_buffer: TRUE to return the buffer still locked and pinned - * - * Returns the buffer number containing the page. Note this is not terribly - * useful unless keep_buffer is specified as TRUE. - * - * Note: when a backup block is available in XLOG, we restore it - * unconditionally, even if the page in the database appears newer. - * This is to protect ourselves against database pages that were partially - * or incorrectly written during a crash. We assume that the XLOG data - * must be good because it has passed a CRC check, while the database - * page might not be. This will force us to replay all subsequent - * modifications of the page that appear in XLOG, rather than possibly - * ignoring them as already applied, but that's not a huge drawback. - * - * If 'get_cleanup_lock' is true, a cleanup lock is obtained on the buffer, - * else a normal exclusive lock is used. During crash recovery, that's just - * pro forma because there can't be any regular backends in the system, but - * in hot standby mode the distinction is important. - * - * If 'keep_buffer' is true, return without releasing the buffer lock and pin; - * then caller is responsible for doing UnlockReleaseBuffer() later. This - * is needed in some cases when replaying XLOG records that touch multiple - * pages, to prevent inconsistent states from being visible to other backends. - * (Again, that's only important in hot standby mode.) - */ -static Buffer -RestoreBackupBlock(XLogRecPtr lsn, XLogRecord *record, uint8 block_id, - bool get_cleanup_lock, bool keep_buffer) -{ - XLogRecordBlockData *bkpb; - char *blk; - - bkpb = XLogRecGetBlockRef(record, block_id, &blk); - if (!bkpb) - { - /* Caller specified a bogus block_id */ - elog(PANIC, "failed to restore backup block with ID %d", block_id); - } - - if (!(bkpb->fork_flags & BKPBLOCK_HAS_IMAGE)) - return InvalidBuffer; - - /* Found it, apply the update */ - return RestoreBackupBlockContents(lsn, bkpb, - (XLogRecordBlockImage *) blk, - get_cleanup_lock, - keep_buffer); -} - -/* - * Workhorse for RestoreBackupBlock usable without an xlog record - * - * Restores a full-page image from BkpBlock and a data pointer. + * Returns the buffer number containing the page. */ static Buffer RestoreBackupBlockContents(XLogRecPtr lsn, XLogRecordBlockData *bkpb, XLogRecordBlockImage *blkimg, - bool get_cleanup_lock, bool keep_buffer) + bool get_cleanup_lock) { Buffer buffer; Page page; @@ -555,9 +516,6 @@ RestoreBackupBlockContents(XLogRecPtr lsn, XLogRecordBlockData *bkpb, } MarkBufferDirty(buffer); - if (!keep_buffer) - UnlockReleaseBuffer(buffer); - return buffer; }