* XLogReadBufferForRedoExtended * Like XLogReadBufferForRedo, but with extra options. * * In RBM_ZERO_* modes, if the page doesn't exist, the relation is extended * with all-zeroes pages up to the referenced block number. In * RBM_ZERO_AND_LOCK and RBM_ZERO_AND_CLEANUP_LOCK modes, the return value * is always BLK_NEEDS_REDO. * * (The RBM_ZERO_AND_CLEANUP_LOCK mode is redundant with the g
| 329 | * using LockBufferForCleanup(), instead of a regular exclusive lock. |
| 330 | */ |
| 331 | XLogRedoAction |
| 332 | XLogReadBufferForRedoExtended(XLogReaderState *record, |
| 333 | uint8 block_id, |
| 334 | ReadBufferMode mode, bool get_cleanup_lock, |
| 335 | Buffer *buf) |
| 336 | { |
| 337 | XLogRecPtr lsn = record->EndRecPtr; |
| 338 | RelFileNode rnode; |
| 339 | ForkNumber forknum; |
| 340 | BlockNumber blkno; |
| 341 | Page page; |
| 342 | bool zeromode; |
| 343 | bool willinit; |
| 344 | |
| 345 | if (!XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blkno)) |
| 346 | { |
| 347 | /* Caller specified a bogus block_id */ |
| 348 | elog(PANIC, "failed to locate backup block with ID %d", block_id); |
| 349 | } |
| 350 | |
| 351 | /* |
| 352 | * If a WAL redo function calls XLogReadBufferForRedoExtended() for a page that has a full-page |
| 353 | * image, it always succeeds. However, if redo process is only concerned about replaying changes |
| 354 | * to a singe page, so replaying any changes for other pages is a waste of cycles. We have modified |
| 355 | * XLogReadBufferForRedoExtended() to return BLK_DONE for all other pages, to avoid the overhead. |
| 356 | */ |
| 357 | if (redo_read_buffer_filter && redo_read_buffer_filter(record, block_id)) |
| 358 | { |
| 359 | if (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK) |
| 360 | { |
| 361 | *buf = ReadBufferWithoutRelcache(rnode, forknum, |
| 362 | blkno, mode, NULL); |
| 363 | return BLK_DONE; |
| 364 | } |
| 365 | else |
| 366 | { |
| 367 | *buf = InvalidBuffer; |
| 368 | return BLK_DONE; |
| 369 | } |
| 370 | } |
| 371 | |
| 372 | /* |
| 373 | * Make sure that if the block is marked with WILL_INIT, the caller is |
| 374 | * going to initialize it. And vice versa. |
| 375 | */ |
| 376 | zeromode = (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK); |
| 377 | willinit = (record->blocks[block_id].flags & BKPBLOCK_WILL_INIT) != 0; |
| 378 | if (willinit && !zeromode) |
| 379 | elog(PANIC, "block with WILL_INIT flag in WAL record must be zeroed by redo routine"); |
| 380 | if (!willinit && zeromode) |
| 381 | elog(PANIC, "block to be initialized in redo routine must be marked with WILL_INIT flag in the WAL record"); |
| 382 | |
| 383 | /* If it has a full-page image and it should be restored, do it. */ |
| 384 | if (XLogRecBlockImageApply(record, block_id)) |
| 385 | { |
| 386 | Assert(XLogRecHasBlockImage(record, block_id)); |
| 387 | *buf = XLogReadBufferExtended(rnode, forknum, blkno, |
| 388 | get_cleanup_lock ? RBM_ZERO_AND_CLEANUP_LOCK : RBM_ZERO_AND_LOCK); |
no test coverage detected