* XLogReadBufferExtended * Read a page during XLOG replay * * This is functionally comparable to ReadBufferExtended. There's some * differences in the behavior wrt. the "mode" argument: * * In RBM_NORMAL mode, if the page doesn't exist, or contains all-zeroes, we * return InvalidBuffer. In this case the caller should silently skip the * update on this page. (In this situation, we expect t
| 460 | * they will be invisible to tools that need to know which pages are modified. |
| 461 | */ |
| 462 | Buffer |
| 463 | XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum, |
| 464 | BlockNumber blkno, ReadBufferMode mode) |
| 465 | { |
| 466 | BlockNumber lastblock; |
| 467 | Buffer buffer; |
| 468 | SMgrRelation smgr; |
| 469 | |
| 470 | Assert(blkno != P_NEW); |
| 471 | |
| 472 | /* |
| 473 | * Open the relation at smgr level. Relations using shared buffers need |
| 474 | * the default SMGR implementation. |
| 475 | */ |
| 476 | smgr = smgropen(rnode, InvalidBackendId, SMGR_MD, NULL); |
| 477 | |
| 478 | /* |
| 479 | * Create the target file if it doesn't already exist. This lets us cope |
| 480 | * if the replay sequence contains writes to a relation that is later |
| 481 | * deleted. (The original coding of this routine would instead suppress |
| 482 | * the writes, but that seems like it risks losing valuable data if the |
| 483 | * filesystem loses an inode during a crash. Better to write the data |
| 484 | * until we are actually told to delete the file.) |
| 485 | */ |
| 486 | smgrcreate(smgr, forknum, true); |
| 487 | |
| 488 | lastblock = smgrnblocks(smgr, forknum); |
| 489 | |
| 490 | if (blkno < lastblock) |
| 491 | { |
| 492 | /* page exists in file */ |
| 493 | buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno, |
| 494 | mode, NULL); |
| 495 | } |
| 496 | else |
| 497 | { |
| 498 | /* hm, page doesn't exist in file */ |
| 499 | if (mode == RBM_NORMAL) |
| 500 | { |
| 501 | log_invalid_page(rnode, forknum, blkno, false); |
| 502 | return InvalidBuffer; |
| 503 | } |
| 504 | if (mode == RBM_NORMAL_NO_LOG) |
| 505 | return InvalidBuffer; |
| 506 | /* OK to extend the file */ |
| 507 | /* we do this in recovery only - no rel-extension lock needed */ |
| 508 | Assert(InRecovery); |
| 509 | buffer = InvalidBuffer; |
| 510 | do |
| 511 | { |
| 512 | if (buffer != InvalidBuffer) |
| 513 | { |
| 514 | if (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK) |
| 515 | LockBuffer(buffer, BUFFER_LOCK_UNLOCK); |
| 516 | ReleaseBuffer(buffer); |
| 517 | } |
| 518 | buffer = ReadBufferWithoutRelcache(rnode, forknum, |
| 519 | P_NEW, mode, NULL); |
no test coverage detected