PostgreSQL Source Code  git master
xlogutils.h File Reference
#include "access/xlogreader.h"
#include "storage/bufmgr.h"
Include dependency graph for xlogutils.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Enumerations

enum  XLogRedoAction { BLK_NEEDS_REDO, BLK_DONE, BLK_RESTORED, BLK_NOTFOUND }
 

Functions

bool XLogHaveInvalidPages (void)
 
void XLogCheckInvalidPages (void)
 
void XLogDropRelation (RelFileNode rnode, ForkNumber forknum)
 
void XLogDropDatabase (Oid dbid)
 
void XLogTruncateRelation (RelFileNode rnode, ForkNumber forkNum, BlockNumber nblocks)
 
XLogRedoAction XLogReadBufferForRedo (XLogReaderState *record, uint8 buffer_id, Buffer *buf)
 
Buffer XLogInitBufferForRedo (XLogReaderState *record, uint8 block_id)
 
XLogRedoAction XLogReadBufferForRedoExtended (XLogReaderState *record, uint8 buffer_id, ReadBufferMode mode, bool get_cleanup_lock, Buffer *buf)
 
Buffer XLogReadBufferExtended (RelFileNode rnode, ForkNumber forknum, BlockNumber blkno, ReadBufferMode mode)
 
Relation CreateFakeRelcacheEntry (RelFileNode rnode)
 
void FreeFakeRelcacheEntry (Relation fakerel)
 
int read_local_xlog_page (XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page, TimeLineID *pageTLI)
 
void XLogReadDetermineTimeline (XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
 

Enumeration Type Documentation

◆ XLogRedoAction

Enumerator
BLK_NEEDS_REDO 
BLK_DONE 
BLK_RESTORED 
BLK_NOTFOUND 

Definition at line 27 of file xlogutils.h.

28 {
29  BLK_NEEDS_REDO, /* changes from WAL record need to be applied */
30  BLK_DONE, /* block is already up-to-date */
31  BLK_RESTORED, /* block was restored from a full-page image */
32  BLK_NOTFOUND /* block was not found (and hence does not
33  * need to be replayed) */
XLogRedoAction
Definition: xlogutils.h:27

Function Documentation

◆ CreateFakeRelcacheEntry()

Relation CreateFakeRelcacheEntry ( RelFileNode  rnode)

Definition at line 550 of file xlogutils.c.

References Assert, LockRelId::dbId, RelFileNode::dbNode, InRecovery, InvalidBackendId, LockInfoData::lockRelId, palloc0(), FakeRelCacheEntryData::pgc, RelationData::rd_backend, RelationData::rd_lockInfo, RelationData::rd_node, RelationData::rd_rel, RelationData::rd_smgr, RelationGetRelationName, LockRelId::relId, and RelFileNode::relNode.

Referenced by heap_xlog_delete(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_update(), heap_xlog_visible(), and smgr_redo().

551 {
552  FakeRelCacheEntry fakeentry;
553  Relation rel;
554 
556 
557  /* Allocate the Relation struct and all related space in one block. */
558  fakeentry = palloc0(sizeof(FakeRelCacheEntryData));
559  rel = (Relation) fakeentry;
560 
561  rel->rd_rel = &fakeentry->pgc;
562  rel->rd_node = rnode;
563  /* We will never be working with temp rels during recovery */
565 
566  /* It must be a permanent table if we're in recovery. */
567  rel->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
568 
569  /* We don't know the name of the relation; use relfilenode instead */
570  sprintf(RelationGetRelationName(rel), "%u", rnode.relNode);
571 
572  /*
573  * We set up the lockRelId in case anything tries to lock the dummy
574  * relation. Note that this is fairly bogus since relNode may be
575  * different from the relation's OID. It shouldn't really matter though,
576  * since we are presumably running by ourselves and can't have any lock
577  * conflicts ...
578  */
579  rel->rd_lockInfo.lockRelId.dbId = rnode.dbNode;
580  rel->rd_lockInfo.lockRelId.relId = rnode.relNode;
581 
582  rel->rd_smgr = NULL;
583 
584  return rel;
585 }
LockRelId lockRelId
Definition: rel.h:44
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
bool InRecovery
Definition: xlog.c:194
Oid dbId
Definition: rel.h:39
Form_pg_class rd_rel
Definition: rel.h:84
struct RelationData * Relation
Definition: relcache.h:26
LockInfoData rd_lockInfo
Definition: rel.h:87
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:955
RelFileNode rd_node
Definition: rel.h:55
BackendId rd_backend
Definition: rel.h:59
#define Assert(condition)
Definition: c.h:699
FormData_pg_class pgc
Definition: xlogutils.c:532
Oid relId
Definition: rel.h:38

◆ FreeFakeRelcacheEntry()

void FreeFakeRelcacheEntry ( Relation  fakerel)

Definition at line 591 of file xlogutils.c.

References pfree(), RelationData::rd_smgr, and smgrclearowner().

Referenced by heap_xlog_delete(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_update(), heap_xlog_visible(), and smgr_redo().

592 {
593  /* make sure the fakerel is not referenced by the SmgrRelation anymore */
594  if (fakerel->rd_smgr != NULL)
595  smgrclearowner(&fakerel->rd_smgr, fakerel->rd_smgr);
596  pfree(fakerel);
597 }
void smgrclearowner(SMgrRelation *owner, SMgrRelation reln)
Definition: smgr.c:222
struct SMgrRelationData * rd_smgr
Definition: rel.h:57
void pfree(void *pointer)
Definition: mcxt.c:1031

◆ read_local_xlog_page()

int read_local_xlog_page ( XLogReaderState state,
XLogRecPtr  targetPagePtr,
int  reqLen,
XLogRecPtr  targetRecPtr,
char *  cur_page,
TimeLineID pageTLI 
)

Definition at line 909 of file xlogutils.c.

References CHECK_FOR_INTERRUPTS, XLogReaderState::currTLI, XLogReaderState::currTLIValidUntil, GetFlushRecPtr(), GetXLogReplayRecPtr(), pg_usleep(), RecoveryInProgress(), ThisTimeLineID, XLogReaderState::wal_segment_size, XLogRead(), and XLogReadDetermineTimeline().

Referenced by logical_read_local_xlog_page(), and XlogReadTwoPhaseData().

912 {
913  XLogRecPtr read_upto,
914  loc;
915  int count;
916 
917  loc = targetPagePtr + reqLen;
918 
919  /* Loop waiting for xlog to be available if necessary */
920  while (1)
921  {
922  /*
923  * Determine the limit of xlog we can currently read to, and what the
924  * most recent timeline is.
925  *
926  * RecoveryInProgress() will update ThisTimeLineID when it first
927  * notices recovery finishes, so we only have to maintain it for the
928  * local process until recovery ends.
929  */
930  if (!RecoveryInProgress())
931  read_upto = GetFlushRecPtr();
932  else
933  read_upto = GetXLogReplayRecPtr(&ThisTimeLineID);
934 
935  *pageTLI = ThisTimeLineID;
936 
937  /*
938  * Check which timeline to get the record from.
939  *
940  * We have to do it each time through the loop because if we're in
941  * recovery as a cascading standby, the current timeline might've
942  * become historical. We can't rely on RecoveryInProgress() because in
943  * a standby configuration like
944  *
945  * A => B => C
946  *
947  * if we're a logical decoding session on C, and B gets promoted, our
948  * timeline will change while we remain in recovery.
949  *
950  * We can't just keep reading from the old timeline as the last WAL
951  * archive in the timeline will get renamed to .partial by
952  * StartupXLOG().
953  *
954  * If that happens after our caller updated ThisTimeLineID but before
955  * we actually read the xlog page, we might still try to read from the
956  * old (now renamed) segment and fail. There's not much we can do
957  * about this, but it can only happen when we're a leaf of a cascading
958  * standby whose master gets promoted while we're decoding, so a
959  * one-off ERROR isn't too bad.
960  */
961  XLogReadDetermineTimeline(state, targetPagePtr, reqLen);
962 
963  if (state->currTLI == ThisTimeLineID)
964  {
965 
966  if (loc <= read_upto)
967  break;
968 
970  pg_usleep(1000L);
971  }
972  else
973  {
974  /*
975  * We're on a historical timeline, so limit reading to the switch
976  * point where we moved to the next timeline.
977  *
978  * We don't need to GetFlushRecPtr or GetXLogReplayRecPtr. We know
979  * about the new timeline, so we must've received past the end of
980  * it.
981  */
982  read_upto = state->currTLIValidUntil;
983 
984  /*
985  * Setting pageTLI to our wanted record's TLI is slightly wrong;
986  * the page might begin on an older timeline if it contains a
987  * timeline switch, since its xlog segment will have been copied
988  * from the prior timeline. This is pretty harmless though, as
989  * nothing cares so long as the timeline doesn't go backwards. We
990  * should read the page header instead; FIXME someday.
991  */
992  *pageTLI = state->currTLI;
993 
994  /* No need to wait on a historical timeline */
995  break;
996  }
997  }
998 
999  if (targetPagePtr + XLOG_BLCKSZ <= read_upto)
1000  {
1001  /*
1002  * more than one block available; read only that block, have caller
1003  * come back if they need more.
1004  */
1005  count = XLOG_BLCKSZ;
1006  }
1007  else if (targetPagePtr + reqLen > read_upto)
1008  {
1009  /* not enough data there */
1010  return -1;
1011  }
1012  else
1013  {
1014  /* enough bytes available to satisfy the request */
1015  count = read_upto - targetPagePtr;
1016  }
1017 
1018  /*
1019  * Even though we just determined how much of the page can be validly read
1020  * as 'count', read the whole page anyway. It's guaranteed to be
1021  * zero-padded up to the page boundary if it's incomplete.
1022  */
1023  XLogRead(cur_page, state->wal_segment_size, *pageTLI, targetPagePtr,
1024  XLOG_BLCKSZ);
1025 
1026  /* number of valid bytes in the buffer */
1027  return count;
1028 }
XLogRecPtr GetFlushRecPtr(void)
Definition: xlog.c:8271
bool RecoveryInProgress(void)
Definition: xlog.c:7939
void XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
Definition: xlogutils.c:801
void pg_usleep(long microsec)
Definition: signal.c:53
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)
Definition: xlog.c:11184
XLogRecPtr currTLIValidUntil
Definition: xlogreader.h:180
int wal_segment_size
Definition: xlogreader.h:79
TimeLineID ThisTimeLineID
Definition: xlog.c:181
TimeLineID currTLI
Definition: xlogreader.h:170
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:98
static void XLogRead(char *buf, int segsize, TimeLineID tli, XLogRecPtr startptr, Size count)
Definition: xlogutils.c:656

◆ XLogCheckInvalidPages()

void XLogCheckInvalidPages ( void  )

Definition at line 220 of file xlogutils.c.

References xl_invalid_page_key::blkno, elog, xl_invalid_page_key::forkno, hash_destroy(), hash_seq_init(), hash_seq_search(), xl_invalid_page::key, xl_invalid_page_key::node, PANIC, xl_invalid_page::present, report_invalid_page(), status(), and WARNING.

Referenced by CheckRecoveryConsistency().

221 {
223  xl_invalid_page *hentry;
224  bool foundone = false;
225 
226  if (invalid_page_tab == NULL)
227  return; /* nothing to do */
228 
230 
231  /*
232  * Our strategy is to emit WARNING messages for all remaining entries and
233  * only PANIC after we've dumped all the available info.
234  */
235  while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
236  {
237  report_invalid_page(WARNING, hentry->key.node, hentry->key.forkno,
238  hentry->key.blkno, hentry->present);
239  foundone = true;
240  }
241 
242  if (foundone)
243  elog(PANIC, "WAL contains references to invalid pages");
244 
246  invalid_page_tab = NULL;
247 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:814
ForkNumber forkno
Definition: xlogutils.c:47
#define PANIC
Definition: elog.h:53
RelFileNode node
Definition: xlogutils.c:46
static void report_invalid_page(int elevel, RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present)
Definition: xlogutils.c:62
BlockNumber blkno
Definition: xlogutils.c:48
xl_invalid_page_key key
Definition: xlogutils.c:53
#define WARNING
Definition: elog.h:40
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
static HTAB * invalid_page_tab
Definition: xlogutils.c:57
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ XLogDropDatabase()

void XLogDropDatabase ( Oid  dbid)

Definition at line 617 of file xlogutils.c.

References forget_invalid_pages_db(), and smgrcloseall().

Referenced by dbase_redo().

618 {
619  /*
620  * This is unnecessarily heavy-handed, as it will close SMgrRelation
621  * objects for other databases as well. DROP DATABASE occurs seldom enough
622  * that it's not worth introducing a variant of smgrclose for just this
623  * purpose. XXX: Or should we rather leave the smgr entries dangling?
624  */
625  smgrcloseall();
626 
628 }
static void forget_invalid_pages_db(Oid dbid)
Definition: xlogutils.c:177
void smgrcloseall(void)
Definition: smgr.c:326

◆ XLogDropRelation()

void XLogDropRelation ( RelFileNode  rnode,
ForkNumber  forknum 
)

Definition at line 606 of file xlogutils.c.

References forget_invalid_pages().

Referenced by xact_redo_abort(), and xact_redo_commit().

607 {
608  forget_invalid_pages(rnode, forknum, 0);
609 }
static void forget_invalid_pages(RelFileNode node, ForkNumber forkno, BlockNumber minblkno)
Definition: xlogutils.c:142

◆ XLogHaveInvalidPages()

bool XLogHaveInvalidPages ( void  )

Definition at line 210 of file xlogutils.c.

References hash_get_num_entries().

Referenced by RecoveryRestartPoint().

211 {
212  if (invalid_page_tab != NULL &&
214  return true;
215  return false;
216 }
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
static HTAB * invalid_page_tab
Definition: xlogutils.c:57

◆ XLogInitBufferForRedo()

◆ XLogReadBufferExtended()

Buffer XLogReadBufferExtended ( RelFileNode  rnode,
ForkNumber  forknum,
BlockNumber  blkno,
ReadBufferMode  mode 
)

Definition at line 437 of file xlogutils.c.

References Assert, buffer, BUFFER_LOCK_UNLOCK, BufferGetBlockNumber(), BufferGetPage, InRecovery, InvalidBackendId, InvalidBuffer, LockBuffer(), log_invalid_page(), P_NEW, PageIsNew, RBM_NORMAL, RBM_NORMAL_NO_LOG, RBM_ZERO_AND_CLEANUP_LOCK, RBM_ZERO_AND_LOCK, ReadBufferWithoutRelcache(), ReleaseBuffer(), smgrcreate(), smgrnblocks(), and smgropen().

Referenced by btree_xlog_delete_get_latestRemovedXid(), btree_xlog_vacuum(), checkXLogConsistency(), hash_xlog_vacuum_get_latestRemovedXid(), XLogReadBufferForRedoExtended(), and XLogRecordPageWithFreeSpace().

439 {
440  BlockNumber lastblock;
441  Buffer buffer;
442  SMgrRelation smgr;
443 
444  Assert(blkno != P_NEW);
445 
446  /* Open the relation at smgr level */
447  smgr = smgropen(rnode, InvalidBackendId);
448 
449  /*
450  * Create the target file if it doesn't already exist. This lets us cope
451  * if the replay sequence contains writes to a relation that is later
452  * deleted. (The original coding of this routine would instead suppress
453  * the writes, but that seems like it risks losing valuable data if the
454  * filesystem loses an inode during a crash. Better to write the data
455  * until we are actually told to delete the file.)
456  */
457  smgrcreate(smgr, forknum, true);
458 
459  lastblock = smgrnblocks(smgr, forknum);
460 
461  if (blkno < lastblock)
462  {
463  /* page exists in file */
464  buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno,
465  mode, NULL);
466  }
467  else
468  {
469  /* hm, page doesn't exist in file */
470  if (mode == RBM_NORMAL)
471  {
472  log_invalid_page(rnode, forknum, blkno, false);
473  return InvalidBuffer;
474  }
475  if (mode == RBM_NORMAL_NO_LOG)
476  return InvalidBuffer;
477  /* OK to extend the file */
478  /* we do this in recovery only - no rel-extension lock needed */
480  buffer = InvalidBuffer;
481  do
482  {
483  if (buffer != InvalidBuffer)
484  {
485  if (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK)
487  ReleaseBuffer(buffer);
488  }
489  buffer = ReadBufferWithoutRelcache(rnode, forknum,
490  P_NEW, mode, NULL);
491  }
492  while (BufferGetBlockNumber(buffer) < blkno);
493  /* Handle the corner case that P_NEW returns non-consecutive pages */
494  if (BufferGetBlockNumber(buffer) != blkno)
495  {
496  if (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK)
498  ReleaseBuffer(buffer);
499  buffer = ReadBufferWithoutRelcache(rnode, forknum, blkno,
500  mode, NULL);
501  }
502  }
503 
504  if (mode == RBM_NORMAL)
505  {
506  /* check that page has been initialized */
507  Page page = (Page) BufferGetPage(buffer);
508 
509  /*
510  * We assume that PageIsNew is safe without a lock. During recovery,
511  * there should be no other backends that could modify the buffer at
512  * the same time.
513  */
514  if (PageIsNew(page))
515  {
516  ReleaseBuffer(buffer);
517  log_invalid_page(rnode, forknum, blkno, true);
518  return InvalidBuffer;
519  }
520  }
521 
522  return buffer;
523 }
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:87
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:376
bool InRecovery
Definition: xlog.c:194
#define InvalidBuffer
Definition: buf.h:25
Buffer ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:682
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define P_NEW
Definition: bufmgr.h:82
static void log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present)
Definition: xlogutils.c:78
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:137
#define InvalidBackendId
Definition: backendid.h:23
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:672
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define PageIsNew(page)
Definition: bufpage.h:225
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ XLogReadBufferForRedo()

XLogRedoAction XLogReadBufferForRedo ( XLogReaderState record,
uint8  buffer_id,
Buffer buf 
)

Definition at line 289 of file xlogutils.c.

References RBM_NORMAL, and XLogReadBufferForRedoExtended().

Referenced by _bt_clear_incomplete_split(), brin_xlog_desummarize_page(), brin_xlog_insert_update(), brin_xlog_revmap_extend(), brin_xlog_samepage_update(), brin_xlog_update(), btree_xlog_delete(), btree_xlog_insert(), btree_xlog_mark_page_halfdead(), btree_xlog_split(), btree_xlog_unlink_page(), generic_redo(), ginRedoClearIncompleteSplit(), ginRedoDeletePage(), ginRedoInsert(), ginRedoSplit(), ginRedoUpdateMetapage(), ginRedoVacuumDataLeafPage(), ginRedoVacuumPage(), gistRedoClearFollowRight(), gistRedoPageUpdateRecord(), hash_xlog_add_ovfl_page(), hash_xlog_delete(), hash_xlog_init_bitmap_page(), hash_xlog_insert(), hash_xlog_move_page_contents(), hash_xlog_split_allocate_page(), hash_xlog_split_cleanup(), hash_xlog_split_complete(), hash_xlog_split_page(), hash_xlog_squeeze_page(), hash_xlog_update_meta_page(), hash_xlog_vacuum_one_page(), heap_xlog_confirm(), heap_xlog_delete(), heap_xlog_freeze_page(), heap_xlog_inplace(), heap_xlog_insert(), heap_xlog_lock(), heap_xlog_lock_updated(), heap_xlog_multi_insert(), heap_xlog_update(), heap_xlog_visible(), spgRedoAddLeaf(), spgRedoAddNode(), spgRedoMoveLeafs(), spgRedoPickSplit(), spgRedoSplitTuple(), spgRedoVacuumLeaf(), spgRedoVacuumRedirect(), spgRedoVacuumRoot(), and xlog_redo().

291 {
292  return XLogReadBufferForRedoExtended(record, block_id, RBM_NORMAL,
293  false, buf);
294 }
static char * buf
Definition: pg_test_fsync.c:67
XLogRedoAction XLogReadBufferForRedoExtended(XLogReaderState *record, uint8 block_id, ReadBufferMode mode, bool get_cleanup_lock, Buffer *buf)
Definition: xlogutils.c:326

◆ XLogReadBufferForRedoExtended()

XLogRedoAction XLogReadBufferForRedoExtended ( XLogReaderState record,
uint8  buffer_id,
ReadBufferMode  mode,
bool  get_cleanup_lock,
Buffer buf 
)

Definition at line 326 of file xlogutils.c.

References Assert, BKPBLOCK_WILL_INIT, BLK_DONE, BLK_NEEDS_REDO, BLK_NOTFOUND, BLK_RESTORED, xl_invalid_page_key::blkno, XLogReaderState::blocks, BUFFER_LOCK_EXCLUSIVE, BufferGetPage, BufferIsValid, elog, XLogReaderState::EndRecPtr, ERROR, DecodedBkpBlock::flags, FlushOneBuffer(), INIT_FORKNUM, LockBuffer(), LockBufferForCleanup(), MarkBufferDirty(), PageGetLSN, PageIsNew, PageSetLSN, PANIC, RBM_ZERO_AND_CLEANUP_LOCK, RBM_ZERO_AND_LOCK, RestoreBlockImage(), XLogReadBufferExtended(), XLogRecBlockImageApply, XLogRecGetBlockTag(), and XLogRecHasBlockImage.

Referenced by btree_xlog_vacuum(), hash_xlog_delete(), hash_xlog_move_page_contents(), hash_xlog_split_allocate_page(), hash_xlog_squeeze_page(), hash_xlog_vacuum_one_page(), heap_xlog_clean(), heap_xlog_visible(), XLogInitBufferForRedo(), and XLogReadBufferForRedo().

330 {
331  XLogRecPtr lsn = record->EndRecPtr;
332  RelFileNode rnode;
333  ForkNumber forknum;
334  BlockNumber blkno;
335  Page page;
336  bool zeromode;
337  bool willinit;
338 
339  if (!XLogRecGetBlockTag(record, block_id, &rnode, &forknum, &blkno))
340  {
341  /* Caller specified a bogus block_id */
342  elog(PANIC, "failed to locate backup block with ID %d", block_id);
343  }
344 
345  /*
346  * Make sure that if the block is marked with WILL_INIT, the caller is
347  * going to initialize it. And vice versa.
348  */
349  zeromode = (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK);
350  willinit = (record->blocks[block_id].flags & BKPBLOCK_WILL_INIT) != 0;
351  if (willinit && !zeromode)
352  elog(PANIC, "block with WILL_INIT flag in WAL record must be zeroed by redo routine");
353  if (!willinit && zeromode)
354  elog(PANIC, "block to be initialized in redo routine must be marked with WILL_INIT flag in the WAL record");
355 
356  /* If it has a full-page image and it should be restored, do it. */
357  if (XLogRecBlockImageApply(record, block_id))
358  {
359  Assert(XLogRecHasBlockImage(record, block_id));
360  *buf = XLogReadBufferExtended(rnode, forknum, blkno,
361  get_cleanup_lock ? RBM_ZERO_AND_CLEANUP_LOCK : RBM_ZERO_AND_LOCK);
362  page = BufferGetPage(*buf);
363  if (!RestoreBlockImage(record, block_id, page))
364  elog(ERROR, "failed to restore block image");
365 
366  /*
367  * The page may be uninitialized. If so, we can't set the LSN because
368  * that would corrupt the page.
369  */
370  if (!PageIsNew(page))
371  {
372  PageSetLSN(page, lsn);
373  }
374 
376 
377  /*
378  * At the end of crash recovery the init forks of unlogged relations
379  * are copied, without going through shared buffers. So we need to
380  * force the on-disk state of init forks to always be in sync with the
381  * state in shared buffers.
382  */
383  if (forknum == INIT_FORKNUM)
385 
386  return BLK_RESTORED;
387  }
388  else
389  {
390  *buf = XLogReadBufferExtended(rnode, forknum, blkno, mode);
391  if (BufferIsValid(*buf))
392  {
393  if (mode != RBM_ZERO_AND_LOCK && mode != RBM_ZERO_AND_CLEANUP_LOCK)
394  {
395  if (get_cleanup_lock)
397  else
399  }
400  if (lsn <= PageGetLSN(BufferGetPage(*buf)))
401  return BLK_DONE;
402  else
403  return BLK_NEEDS_REDO;
404  }
405  else
406  return BLK_NOTFOUND;
407  }
408 }
void LockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3603
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:231
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
Buffer XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum, BlockNumber blkno, ReadBufferMode mode)
Definition: xlogutils.c:437
uint32 BlockNumber
Definition: block.h:31
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:89
#define PANIC
Definition: elog.h:53
XLogRecPtr EndRecPtr
Definition: xlogreader.h:120
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define BKPBLOCK_WILL_INIT
Definition: xlogrecord.h:183
ForkNumber
Definition: relpath.h:40
bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1330
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
void FlushOneBuffer(Buffer buffer)
Definition: bufmgr.c:3289
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
Definition: xlogreader.c:1383
#define PageGetLSN(page)
Definition: bufpage.h:362
#define PageIsNew(page)
Definition: bufpage.h:225
#define elog
Definition: elog.h:219
#define XLogRecBlockImageApply(decoder, block_id)
Definition: xlogreader.h:233
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
Pointer Page
Definition: bufpage.h:74
DecodedBkpBlock blocks[XLR_MAX_BLOCK_ID+1]
Definition: xlogreader.h:139

◆ XLogReadDetermineTimeline()

void XLogReadDetermineTimeline ( XLogReaderState state,
XLogRecPtr  wantPage,
uint32  wantLength 
)

Definition at line 801 of file xlogutils.c.

References Assert, XLogReaderState::currTLI, XLogReaderState::currTLIValidUntil, DEBUG3, elog, InvalidXLogRecPtr, list_free_deep(), Min, XLogReaderState::nextTLI, XLogReaderState::readLen, XLogReaderState::readOff, XLogReaderState::readSegNo, readTimeLineHistory(), ThisTimeLineID, tliOfPointInHistory(), tliSwitchPoint(), and XLogReaderState::wal_segment_size.

Referenced by logical_read_xlog_page(), and read_local_xlog_page().

802 {
803  const XLogRecPtr lastReadPage = state->readSegNo *
804  state->wal_segment_size + state->readOff;
805 
806  Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
807  Assert(wantLength <= XLOG_BLCKSZ);
808  Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
809 
810  /*
811  * If the desired page is currently read in and valid, we have nothing to
812  * do.
813  *
814  * The caller should've ensured that it didn't previously advance readOff
815  * past the valid limit of this timeline, so it doesn't matter if the
816  * current TLI has since become historical.
817  */
818  if (lastReadPage == wantPage &&
819  state->readLen != 0 &&
820  lastReadPage + state->readLen >= wantPage + Min(wantLength, XLOG_BLCKSZ - 1))
821  return;
822 
823  /*
824  * If we're reading from the current timeline, it hasn't become historical
825  * and the page we're reading is after the last page read, we can again
826  * just carry on. (Seeking backwards requires a check to make sure the
827  * older page isn't on a prior timeline).
828  *
829  * ThisTimeLineID might've become historical since we last looked, but the
830  * caller is required not to read past the flush limit it saw at the time
831  * it looked up the timeline. There's nothing we can do about it if
832  * StartupXLOG() renames it to .partial concurrently.
833  */
834  if (state->currTLI == ThisTimeLineID && wantPage >= lastReadPage)
835  {
837  return;
838  }
839 
840  /*
841  * If we're just reading pages from a previously validated historical
842  * timeline and the timeline we're reading from is valid until the end of
843  * the current segment we can just keep reading.
844  */
845  if (state->currTLIValidUntil != InvalidXLogRecPtr &&
846  state->currTLI != ThisTimeLineID &&
847  state->currTLI != 0 &&
848  ((wantPage + wantLength) / state->wal_segment_size) <
849  (state->currTLIValidUntil / state->wal_segment_size))
850  return;
851 
852  /*
853  * If we reach this point we're either looking up a page for random
854  * access, the current timeline just became historical, or we're reading
855  * from a new segment containing a timeline switch. In all cases we need
856  * to determine the newest timeline on the segment.
857  *
858  * If it's the current timeline we can just keep reading from here unless
859  * we detect a timeline switch that makes the current timeline historical.
860  * If it's a historical timeline we can read all the segment on the newest
861  * timeline because it contains all the old timelines' data too. So only
862  * one switch check is required.
863  */
864  {
865  /*
866  * We need to re-read the timeline history in case it's been changed
867  * by a promotion or replay from a cascaded replica.
868  */
869  List *timelineHistory = readTimeLineHistory(ThisTimeLineID);
870 
871  XLogRecPtr endOfSegment = (((wantPage / state->wal_segment_size) + 1)
872  * state->wal_segment_size) - 1;
873 
874  Assert(wantPage / state->wal_segment_size ==
875  endOfSegment / state->wal_segment_size);
876 
877  /*
878  * Find the timeline of the last LSN on the segment containing
879  * wantPage.
880  */
881  state->currTLI = tliOfPointInHistory(endOfSegment, timelineHistory);
882  state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
883  &state->nextTLI);
884 
886  wantPage + wantLength < state->currTLIValidUntil);
887 
888  list_free_deep(timelineHistory);
889 
890  elog(DEBUG3, "switched to timeline %u valid until %X/%X",
891  state->currTLI,
892  (uint32) (state->currTLIValidUntil >> 32),
893  (uint32) (state->currTLIValidUntil));
894  }
895 }
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition: timeline.c:533
#define DEBUG3
Definition: elog.h:23
#define Min(x, y)
Definition: c.h:857
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:75
void list_free_deep(List *list)
Definition: list.c:1147
XLogRecPtr currTLIValidUntil
Definition: xlogreader.h:180
unsigned int uint32
Definition: c.h:325
int wal_segment_size
Definition: xlogreader.h:79
TimeLineID nextTLI
Definition: xlogreader.h:186
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition: timeline.c:561
TimeLineID ThisTimeLineID
Definition: xlog.c:181
TimeLineID currTLI
Definition: xlogreader.h:170
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
XLogSegNo readSegNo
Definition: xlogreader.h:156
#define elog
Definition: elog.h:219
Definition: pg_list.h:45

◆ XLogTruncateRelation()

void XLogTruncateRelation ( RelFileNode  rnode,
ForkNumber  forkNum,
BlockNumber  nblocks 
)

Definition at line 636 of file xlogutils.c.

References forget_invalid_pages().

Referenced by smgr_redo().

638 {
639  forget_invalid_pages(rnode, forkNum, nblocks);
640 }
static void forget_invalid_pages(RelFileNode node, ForkNumber forkno, BlockNumber minblkno)
Definition: xlogutils.c:142