PostgreSQL Source Code  git master
xlogutils.c File Reference
#include "postgres.h"
#include <unistd.h>
#include "access/timeline.h"
#include "access/xlog.h"
#include "access/xlog_internal.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/smgr.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/rel.h"
Include dependency graph for xlogutils.c:

Go to the source code of this file.

Data Structures

struct  xl_invalid_page_key
 
struct  xl_invalid_page
 
struct  FakeRelCacheEntryData
 

Typedefs

typedef struct xl_invalid_page_key xl_invalid_page_key
 
typedef struct xl_invalid_page xl_invalid_page
 
typedef FakeRelCacheEntryDataFakeRelCacheEntry
 

Functions

static void report_invalid_page (int elevel, RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present)
 
static void log_invalid_page (RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present)
 
static void forget_invalid_pages (RelFileNode node, ForkNumber forkno, BlockNumber minblkno)
 
static void forget_invalid_pages_db (Oid dbid)
 
bool XLogHaveInvalidPages (void)
 
void XLogCheckInvalidPages (void)
 
XLogRedoAction XLogReadBufferForRedo (XLogReaderState *record, uint8 block_id, Buffer *buf)
 
Buffer XLogInitBufferForRedo (XLogReaderState *record, uint8 block_id)
 
XLogRedoAction XLogReadBufferForRedoExtended (XLogReaderState *record, uint8 block_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)
 
void XLogDropRelation (RelFileNode rnode, ForkNumber forknum)
 
void XLogDropDatabase (Oid dbid)
 
void XLogTruncateRelation (RelFileNode rnode, ForkNumber forkNum, BlockNumber nblocks)
 
void XLogReadDetermineTimeline (XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
 
static int wal_segment_open (XLogSegNo nextSegNo, WALSegmentContext *segcxt, TimeLineID *tli_p)
 
int read_local_xlog_page (XLogReaderState *state, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *cur_page)
 
void WALReadRaiseError (WALReadError *errinfo)
 

Variables

static HTABinvalid_page_tab = NULL
 

Typedef Documentation

◆ FakeRelCacheEntry

Definition at line 535 of file xlogutils.c.

◆ xl_invalid_page

◆ xl_invalid_page_key

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, RelFileNode::relNode, and sprintf.

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:43
struct SMgrRelationData * rd_smgr
Definition: rel.h:56
bool InRecovery
Definition: xlog.c:200
Oid dbId
Definition: rel.h:38
Form_pg_class rd_rel
Definition: rel.h:83
#define sprintf
Definition: port.h:194
struct RelationData * Relation
Definition: relcache.h:26
LockInfoData rd_lockInfo
Definition: rel.h:86
#define RelationGetRelationName(relation)
Definition: rel.h:456
#define InvalidBackendId
Definition: backendid.h:23
void * palloc0(Size size)
Definition: mcxt.c:980
RelFileNode rd_node
Definition: rel.h:54
BackendId rd_backend
Definition: rel.h:58
#define Assert(condition)
Definition: c.h:739
FormData_pg_class pgc
Definition: xlogutils.c:532
Oid relId
Definition: rel.h:37

◆ forget_invalid_pages()

static void forget_invalid_pages ( RelFileNode  node,
ForkNumber  forkno,
BlockNumber  minblkno 
)
static

Definition at line 142 of file xlogutils.c.

References xl_invalid_page_key::blkno, client_min_messages, DEBUG2, elog, ERROR, xl_invalid_page_key::forkno, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), xl_invalid_page::key, log_min_messages, xl_invalid_page_key::node, pfree(), RelFileNodeEquals, relpathperm, and status().

Referenced by XLogDropRelation(), and XLogTruncateRelation().

143 {
145  xl_invalid_page *hentry;
146 
147  if (invalid_page_tab == NULL)
148  return; /* nothing to do */
149 
151 
152  while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
153  {
154  if (RelFileNodeEquals(hentry->key.node, node) &&
155  hentry->key.forkno == forkno &&
156  hentry->key.blkno >= minblkno)
157  {
159  {
160  char *path = relpathperm(hentry->key.node, forkno);
161 
162  elog(DEBUG2, "page %u of relation %s has been dropped",
163  hentry->key.blkno, path);
164  pfree(path);
165  }
166 
168  (void *) &hentry->key,
169  HASH_REMOVE, NULL) == NULL)
170  elog(ERROR, "hash table corrupted");
171  }
172  }
173 }
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
ForkNumber forkno
Definition: xlogutils.c:47
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
RelFileNode node
Definition: xlogutils.c:46
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
#define DEBUG2
Definition: elog.h:24
BlockNumber blkno
Definition: xlogutils.c:48
xl_invalid_page_key key
Definition: xlogutils.c:53
int log_min_messages
Definition: guc.c:514
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
#define elog(elevel,...)
Definition: elog.h:228
static HTAB * invalid_page_tab
Definition: xlogutils.c:57
int client_min_messages
Definition: guc.c:515
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226
#define RelFileNodeEquals(node1, node2)
Definition: relfilenode.h:88

◆ forget_invalid_pages_db()

static void forget_invalid_pages_db ( Oid  dbid)
static

Definition at line 177 of file xlogutils.c.

References xl_invalid_page_key::blkno, client_min_messages, RelFileNode::dbNode, DEBUG2, elog, ERROR, xl_invalid_page_key::forkno, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), xl_invalid_page::key, log_min_messages, xl_invalid_page_key::node, pfree(), relpathperm, and status().

Referenced by XLogDropDatabase().

178 {
180  xl_invalid_page *hentry;
181 
182  if (invalid_page_tab == NULL)
183  return; /* nothing to do */
184 
186 
187  while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL)
188  {
189  if (hentry->key.node.dbNode == dbid)
190  {
192  {
193  char *path = relpathperm(hentry->key.node, hentry->key.forkno);
194 
195  elog(DEBUG2, "page %u of relation %s has been dropped",
196  hentry->key.blkno, path);
197  pfree(path);
198  }
199 
201  (void *) &hentry->key,
202  HASH_REMOVE, NULL) == NULL)
203  elog(ERROR, "hash table corrupted");
204  }
205  }
206 }
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
ForkNumber forkno
Definition: xlogutils.c:47
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
RelFileNode node
Definition: xlogutils.c:46
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
#define DEBUG2
Definition: elog.h:24
BlockNumber blkno
Definition: xlogutils.c:48
xl_invalid_page_key key
Definition: xlogutils.c:53
int log_min_messages
Definition: guc.c:514
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
#define elog(elevel,...)
Definition: elog.h:228
static HTAB * invalid_page_tab
Definition: xlogutils.c:57
int client_min_messages
Definition: guc.c:515
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226

◆ 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:227
struct SMgrRelationData * rd_smgr
Definition: rel.h:56
void pfree(void *pointer)
Definition: mcxt.c:1056

◆ log_invalid_page()

static void log_invalid_page ( RelFileNode  node,
ForkNumber  forkno,
BlockNumber  blkno,
bool  present 
)
static

Definition at line 78 of file xlogutils.c.

References xl_invalid_page_key::blkno, client_min_messages, DEBUG1, elog, HASHCTL::entrysize, xl_invalid_page_key::forkno, HASH_BLOBS, hash_create(), HASH_ELEM, HASH_ENTER, hash_search(), sort-test::key, HASHCTL::keysize, log_min_messages, xl_invalid_page_key::node, PANIC, xl_invalid_page::present, reachedConsistency, report_invalid_page(), and WARNING.

Referenced by XLogReadBufferExtended().

80 {
82  xl_invalid_page *hentry;
83  bool found;
84 
85  /*
86  * Once recovery has reached a consistent state, the invalid-page table
87  * should be empty and remain so. If a reference to an invalid page is
88  * found after consistency is reached, PANIC immediately. This might seem
89  * aggressive, but it's better than letting the invalid reference linger
90  * in the hash table until the end of recovery and PANIC there, which
91  * might come only much later if this is a standby server.
92  */
94  {
95  report_invalid_page(WARNING, node, forkno, blkno, present);
96  elog(PANIC, "WAL contains references to invalid pages");
97  }
98 
99  /*
100  * Log references to invalid pages at DEBUG1 level. This allows some
101  * tracing of the cause (note the elog context mechanism will tell us
102  * something about the XLOG record that generated the reference).
103  */
105  report_invalid_page(DEBUG1, node, forkno, blkno, present);
106 
107  if (invalid_page_tab == NULL)
108  {
109  /* create hash table when first needed */
110  HASHCTL ctl;
111 
112  memset(&ctl, 0, sizeof(ctl));
113  ctl.keysize = sizeof(xl_invalid_page_key);
114  ctl.entrysize = sizeof(xl_invalid_page);
115 
116  invalid_page_tab = hash_create("XLOG invalid-page table",
117  100,
118  &ctl,
120  }
121 
122  /* we currently assume xl_invalid_page_key contains no padding */
123  key.node = node;
124  key.forkno = forkno;
125  key.blkno = blkno;
126  hentry = (xl_invalid_page *)
127  hash_search(invalid_page_tab, (void *) &key, HASH_ENTER, &found);
128 
129  if (!found)
130  {
131  /* hash_search already filled in the key */
132  hentry->present = present;
133  }
134  else
135  {
136  /* repeat reference ... leave "present" as it was */
137  }
138 }
#define DEBUG1
Definition: elog.h:25
struct xl_invalid_page xl_invalid_page
#define HASH_ELEM
Definition: hsearch.h:87
Size entrysize
Definition: hsearch.h:73
struct xl_invalid_page_key xl_invalid_page_key
ForkNumber forkno
Definition: xlogutils.c:47
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
#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
#define WARNING
Definition: elog.h:40
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
int log_min_messages
Definition: guc.c:514
bool reachedConsistency
Definition: xlog.c:844
#define elog(elevel,...)
Definition: elog.h:228
static HTAB * invalid_page_tab
Definition: xlogutils.c:57
int client_min_messages
Definition: guc.c:515

◆ read_local_xlog_page()

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

Definition at line 817 of file xlogutils.c.

References CHECK_FOR_INTERRUPTS, XLogReaderState::currTLI, XLogReaderState::currTLIValidUntil, GetFlushRecPtr(), GetXLogReplayRecPtr(), pg_usleep(), RecoveryInProgress(), XLogReaderState::seg, XLogReaderState::segcxt, ThisTimeLineID, wal_segment_open(), WALRead(), WALReadRaiseError(), and XLogReadDetermineTimeline().

Referenced by logical_read_local_xlog_page(), and XlogReadTwoPhaseData().

819 {
820  XLogRecPtr read_upto,
821  loc;
822  TimeLineID tli;
823  int count;
824  WALReadError errinfo;
825 
826  loc = targetPagePtr + reqLen;
827 
828  /* Loop waiting for xlog to be available if necessary */
829  while (1)
830  {
831  /*
832  * Determine the limit of xlog we can currently read to, and what the
833  * most recent timeline is.
834  *
835  * RecoveryInProgress() will update ThisTimeLineID when it first
836  * notices recovery finishes, so we only have to maintain it for the
837  * local process until recovery ends.
838  */
839  if (!RecoveryInProgress())
840  read_upto = GetFlushRecPtr();
841  else
842  read_upto = GetXLogReplayRecPtr(&ThisTimeLineID);
843  tli = ThisTimeLineID;
844 
845  /*
846  * Check which timeline to get the record from.
847  *
848  * We have to do it each time through the loop because if we're in
849  * recovery as a cascading standby, the current timeline might've
850  * become historical. We can't rely on RecoveryInProgress() because in
851  * a standby configuration like
852  *
853  * A => B => C
854  *
855  * if we're a logical decoding session on C, and B gets promoted, our
856  * timeline will change while we remain in recovery.
857  *
858  * We can't just keep reading from the old timeline as the last WAL
859  * archive in the timeline will get renamed to .partial by
860  * StartupXLOG().
861  *
862  * If that happens after our caller updated ThisTimeLineID but before
863  * we actually read the xlog page, we might still try to read from the
864  * old (now renamed) segment and fail. There's not much we can do
865  * about this, but it can only happen when we're a leaf of a cascading
866  * standby whose master gets promoted while we're decoding, so a
867  * one-off ERROR isn't too bad.
868  */
869  XLogReadDetermineTimeline(state, targetPagePtr, reqLen);
870 
871  if (state->currTLI == ThisTimeLineID)
872  {
873 
874  if (loc <= read_upto)
875  break;
876 
878  pg_usleep(1000L);
879  }
880  else
881  {
882  /*
883  * We're on a historical timeline, so limit reading to the switch
884  * point where we moved to the next timeline.
885  *
886  * We don't need to GetFlushRecPtr or GetXLogReplayRecPtr. We know
887  * about the new timeline, so we must've received past the end of
888  * it.
889  */
890  read_upto = state->currTLIValidUntil;
891 
892  /*
893  * Setting tli to our wanted record's TLI is slightly wrong; the
894  * page might begin on an older timeline if it contains a timeline
895  * switch, since its xlog segment will have been copied from the
896  * prior timeline. This is pretty harmless though, as nothing
897  * cares so long as the timeline doesn't go backwards. We should
898  * read the page header instead; FIXME someday.
899  */
900  tli = state->currTLI;
901 
902  /* No need to wait on a historical timeline */
903  break;
904  }
905  }
906 
907  if (targetPagePtr + XLOG_BLCKSZ <= read_upto)
908  {
909  /*
910  * more than one block available; read only that block, have caller
911  * come back if they need more.
912  */
913  count = XLOG_BLCKSZ;
914  }
915  else if (targetPagePtr + reqLen > read_upto)
916  {
917  /* not enough data there */
918  return -1;
919  }
920  else
921  {
922  /* enough bytes available to satisfy the request */
923  count = read_upto - targetPagePtr;
924  }
925 
926  /*
927  * Even though we just determined how much of the page can be validly read
928  * as 'count', read the whole page anyway. It's guaranteed to be
929  * zero-padded up to the page boundary if it's incomplete.
930  */
931  if (!WALRead(cur_page, targetPagePtr, XLOG_BLCKSZ, tli, &state->seg,
932  &state->segcxt, wal_segment_open, &errinfo))
933  WALReadRaiseError(&errinfo);
934 
935  /* number of valid bytes in the buffer */
936  return count;
937 }
uint32 TimeLineID
Definition: xlogdefs.h:52
void WALReadRaiseError(WALReadError *errinfo)
Definition: xlogutils.c:944
XLogRecPtr GetFlushRecPtr(void)
Definition: xlog.c:8267
bool RecoveryInProgress(void)
Definition: xlog.c:7935
void XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wantLength)
Definition: xlogutils.c:681
WALOpenSegment seg
Definition: xlogreader.h:169
void pg_usleep(long microsec)
Definition: signal.c:53
XLogRecPtr GetXLogReplayRecPtr(TimeLineID *replayTLI)
Definition: xlog.c:11172
bool WALRead(char *buf, XLogRecPtr startptr, Size count, TimeLineID tli, WALOpenSegment *seg, WALSegmentContext *segcxt, WALSegmentOpen openSegment, WALReadError *errinfo)
Definition: xlogreader.c:1033
XLogRecPtr currTLIValidUntil
Definition: xlogreader.h:192
TimeLineID ThisTimeLineID
Definition: xlog.c:187
TimeLineID currTLI
Definition: xlogreader.h:182
uint64 XLogRecPtr
Definition: xlogdefs.h:21
static int wal_segment_open(XLogSegNo nextSegNo, WALSegmentContext *segcxt, TimeLineID *tli_p)
Definition: xlogutils.c:779
WALSegmentContext segcxt
Definition: xlogreader.h:168
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99

◆ report_invalid_page()

static void report_invalid_page ( int  elevel,
RelFileNode  node,
ForkNumber  forkno,
BlockNumber  blkno,
bool  present 
)
static

Definition at line 62 of file xlogutils.c.

References elog, pfree(), and relpathperm.

Referenced by log_invalid_page(), and XLogCheckInvalidPages().

64 {
65  char *path = relpathperm(node, forkno);
66 
67  if (present)
68  elog(elevel, "page %u of relation %s is uninitialized",
69  blkno, path);
70  else
71  elog(elevel, "page %u of relation %s does not exist",
72  blkno, path);
73  pfree(path);
74 }
#define relpathperm(rnode, forknum)
Definition: relpath.h:83
void pfree(void *pointer)
Definition: mcxt.c:1056
static int elevel
Definition: vacuumlazy.c:143
#define elog(elevel,...)
Definition: elog.h:228

◆ wal_segment_open()

static int wal_segment_open ( XLogSegNo  nextSegNo,
WALSegmentContext segcxt,
TimeLineID tli_p 
)
static

Definition at line 779 of file xlogutils.c.

References BasicOpenFile(), ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), MAXPGPATH, PG_BINARY, WALSegmentContext::ws_segsize, and XLogFilePath.

Referenced by read_local_xlog_page().

781 {
782  TimeLineID tli = *tli_p;
783  char path[MAXPGPATH];
784  int fd;
785 
786  XLogFilePath(path, tli, nextSegNo, segcxt->ws_segsize);
787  fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
788  if (fd >= 0)
789  return fd;
790 
791  if (errno == ENOENT)
792  ereport(ERROR,
794  errmsg("requested WAL segment %s has already been removed",
795  path)));
796  else
797  ereport(ERROR,
799  errmsg("could not open file \"%s\": %m",
800  path)));
801 
802  return -1; /* keep compiler quiet */
803 }
uint32 TimeLineID
Definition: xlogdefs.h:52
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1222
#define ERROR
Definition: elog.h:43
#define MAXPGPATH
int errcode_for_file_access(void)
Definition: elog.c:631
#define ereport(elevel, rest)
Definition: elog.h:141
int BasicOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:981
#define XLogFilePath(path, tli, logSegNo, wal_segsz_bytes)
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ WALReadRaiseError()

void WALReadRaiseError ( WALReadError errinfo)

Definition at line 944 of file xlogutils.c.

References ereport, errcode(), ERRCODE_DATA_CORRUPTED, errcode_for_file_access(), errmsg(), ERROR, MAXFNAMELEN, wal_segment_size, WALReadError::wre_errno, WALReadError::wre_off, WALReadError::wre_read, WALReadError::wre_req, WALReadError::wre_seg, WALOpenSegment::ws_segno, WALOpenSegment::ws_tli, and XLogFileName.

Referenced by logical_read_xlog_page(), read_local_xlog_page(), and XLogSendPhysical().

945 {
946  WALOpenSegment *seg = &errinfo->wre_seg;
947  char fname[MAXFNAMELEN];
948 
949  XLogFileName(fname, seg->ws_tli, seg->ws_segno, wal_segment_size);
950 
951  if (errinfo->wre_read < 0)
952  {
953  errno = errinfo->wre_errno;
954  ereport(ERROR,
956  errmsg("could not read from log segment %s, offset %u: %m",
957  fname, errinfo->wre_off)));
958  }
959  else if (errinfo->wre_read == 0)
960  {
961  ereport(ERROR,
963  errmsg("could not read from log segment %s, offset %u: read %d of %zu",
964  fname, errinfo->wre_off, errinfo->wre_read,
965  (Size) errinfo->wre_req)));
966  }
967 }
WALOpenSegment wre_seg
Definition: xlogreader.h:264
int wal_segment_size
Definition: xlog.c:112
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
XLogSegNo ws_segno
Definition: xlogreader.h:38
int errcode_for_file_access(void)
Definition: elog.c:631
#define ereport(elevel, rest)
Definition: elog.h:141
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:45
#define MAXFNAMELEN
size_t Size
Definition: c.h:467
#define XLogFileName(fname, tli, logSegNo, wal_segsz_bytes)
TimeLineID ws_tli
Definition: xlogreader.h:39
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ 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
#define elog(elevel,...)
Definition: elog.h:228
static HTAB * invalid_page_tab
Definition: xlogutils.c:57
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:226

◆ 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:286

◆ XLogDropRelation()

void XLogDropRelation ( RelFileNode  rnode,
ForkNumber  forknum 
)

Definition at line 606 of file xlogutils.c.

References forget_invalid_pages().

Referenced by DropRelationFiles().

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_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_vacuum(), checkXLogConsistency(), 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  {
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  {
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 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
#define BUFFER_LOCK_UNLOCK
Definition: bufmgr.h:86
void smgrcreate(SMgrRelation reln, ForkNumber forknum, bool isRedo)
Definition: smgr.c:333
bool InRecovery
Definition: xlog.c:200
#define InvalidBuffer
Definition: buf.h:25
Buffer ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum, BlockNumber blockNum, ReadBufferMode mode, BufferAccessStrategy strategy)
Definition: bufmgr.c:684
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
#define P_NEW
Definition: bufmgr.h:81
static void log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool present)
Definition: xlogutils.c:78
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
SMgrRelation smgropen(RelFileNode rnode, BackendId backend)
Definition: smgr.c:145
#define InvalidBackendId
Definition: backendid.h:23
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
BlockNumber smgrnblocks(SMgrRelation reln, ForkNumber forknum)
Definition: smgr.c:555
#define Assert(condition)
Definition: c.h:739
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2613
#define PageIsNew(page)
Definition: bufpage.h:229
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ XLogReadBufferForRedo()

XLogRedoAction XLogReadBufferForRedo ( XLogReaderState record,
uint8  block_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(), gistRedoDeleteRecord(), gistRedoPageDelete(), 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  block_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  */
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  {
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 }
static PgChecksumMode mode
Definition: pg_checksums.c:61
void LockBufferForCleanup(Buffer buffer)
Definition: bufmgr.c:3659
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:288
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
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:88
#define PANIC
Definition: elog.h:53
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define BKPBLOCK_WILL_INIT
Definition: xlogrecord.h:182
ForkNumber
Definition: relpath.h:40
bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1460
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:739
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
void FlushOneBuffer(Buffer buffer)
Definition: bufmgr.c:3345
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
Definition: xlogreader.c:1513
#define PageGetLSN(page)
Definition: bufpage.h:366
#define PageIsNew(page)
Definition: bufpage.h:229
#define elog(elevel,...)
Definition: elog.h:228
#define XLogRecBlockImageApply(decoder, block_id)
Definition: xlogreader.h:290
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
Pointer Page
Definition: bufpage.h:78
DecodedBkpBlock blocks[XLR_MAX_BLOCK_ID+1]
Definition: xlogreader.h:151

◆ XLogReadDetermineTimeline()

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

Definition at line 681 of file xlogutils.c.

References Assert, XLogReaderState::currTLI, XLogReaderState::currTLIValidUntil, DEBUG3, elog, InvalidXLogRecPtr, list_free_deep(), Min, XLogReaderState::nextTLI, XLogReaderState::readLen, readTimeLineHistory(), XLogReaderState::seg, XLogReaderState::segcxt, XLogReaderState::segoff, ThisTimeLineID, tliOfPointInHistory(), tliSwitchPoint(), WALOpenSegment::ws_segno, and WALSegmentContext::ws_segsize.

Referenced by logical_read_xlog_page(), and read_local_xlog_page().

682 {
683  const XLogRecPtr lastReadPage = (state->seg.ws_segno *
684  state->segcxt.ws_segsize + state->segoff);
685 
686  Assert(wantPage != InvalidXLogRecPtr && wantPage % XLOG_BLCKSZ == 0);
687  Assert(wantLength <= XLOG_BLCKSZ);
688  Assert(state->readLen == 0 || state->readLen <= XLOG_BLCKSZ);
689 
690  /*
691  * If the desired page is currently read in and valid, we have nothing to
692  * do.
693  *
694  * The caller should've ensured that it didn't previously advance readOff
695  * past the valid limit of this timeline, so it doesn't matter if the
696  * current TLI has since become historical.
697  */
698  if (lastReadPage == wantPage &&
699  state->readLen != 0 &&
700  lastReadPage + state->readLen >= wantPage + Min(wantLength, XLOG_BLCKSZ - 1))
701  return;
702 
703  /*
704  * If we're reading from the current timeline, it hasn't become historical
705  * and the page we're reading is after the last page read, we can again
706  * just carry on. (Seeking backwards requires a check to make sure the
707  * older page isn't on a prior timeline).
708  *
709  * ThisTimeLineID might've become historical since we last looked, but the
710  * caller is required not to read past the flush limit it saw at the time
711  * it looked up the timeline. There's nothing we can do about it if
712  * StartupXLOG() renames it to .partial concurrently.
713  */
714  if (state->currTLI == ThisTimeLineID && wantPage >= lastReadPage)
715  {
717  return;
718  }
719 
720  /*
721  * If we're just reading pages from a previously validated historical
722  * timeline and the timeline we're reading from is valid until the end of
723  * the current segment we can just keep reading.
724  */
725  if (state->currTLIValidUntil != InvalidXLogRecPtr &&
726  state->currTLI != ThisTimeLineID &&
727  state->currTLI != 0 &&
728  ((wantPage + wantLength) / state->segcxt.ws_segsize) <
729  (state->currTLIValidUntil / state->segcxt.ws_segsize))
730  return;
731 
732  /*
733  * If we reach this point we're either looking up a page for random
734  * access, the current timeline just became historical, or we're reading
735  * from a new segment containing a timeline switch. In all cases we need
736  * to determine the newest timeline on the segment.
737  *
738  * If it's the current timeline we can just keep reading from here unless
739  * we detect a timeline switch that makes the current timeline historical.
740  * If it's a historical timeline we can read all the segment on the newest
741  * timeline because it contains all the old timelines' data too. So only
742  * one switch check is required.
743  */
744  {
745  /*
746  * We need to re-read the timeline history in case it's been changed
747  * by a promotion or replay from a cascaded replica.
748  */
749  List *timelineHistory = readTimeLineHistory(ThisTimeLineID);
750  XLogRecPtr endOfSegment;
751 
752  endOfSegment = ((wantPage / state->segcxt.ws_segsize) + 1) *
753  state->segcxt.ws_segsize - 1;
754  Assert(wantPage / state->segcxt.ws_segsize ==
755  endOfSegment / state->segcxt.ws_segsize);
756 
757  /*
758  * Find the timeline of the last LSN on the segment containing
759  * wantPage.
760  */
761  state->currTLI = tliOfPointInHistory(endOfSegment, timelineHistory);
762  state->currTLIValidUntil = tliSwitchPoint(state->currTLI, timelineHistory,
763  &state->nextTLI);
764 
766  wantPage + wantLength < state->currTLIValidUntil);
767 
768  list_free_deep(timelineHistory);
769 
770  elog(DEBUG3, "switched to timeline %u valid until %X/%X",
771  state->currTLI,
772  (uint32) (state->currTLIValidUntil >> 32),
773  (uint32) (state->currTLIValidUntil));
774  }
775 }
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition: timeline.c:535
#define DEBUG3
Definition: elog.h:23
#define Min(x, y)
Definition: c.h:911
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:75
void list_free_deep(List *list)
Definition: list.c:1391
WALOpenSegment seg
Definition: xlogreader.h:169
XLogSegNo ws_segno
Definition: xlogreader.h:38
XLogRecPtr currTLIValidUntil
Definition: xlogreader.h:192
unsigned int uint32
Definition: c.h:359
TimeLineID nextTLI
Definition: xlogreader.h:198
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition: timeline.c:563
TimeLineID ThisTimeLineID
Definition: xlog.c:187
TimeLineID currTLI
Definition: xlogreader.h:182
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:739
#define elog(elevel,...)
Definition: elog.h:228
WALSegmentContext segcxt
Definition: xlogreader.h:168
Definition: pg_list.h:50

◆ 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

Variable Documentation

◆ invalid_page_tab

HTAB* invalid_page_tab = NULL
static

Definition at line 57 of file xlogutils.c.