*** a/src/backend/access/transam/rmgr.c --- b/src/backend/access/transam/rmgr.c *************** *** 16,21 **** --- 16,22 ---- #include "access/nbtree.h" #include "access/xact.h" #include "access/xlog_internal.h" + #include "access/xlogutils.h" #include "catalog/storage.h" #include "commands/dbcommands.h" #include "commands/sequence.h" *************** *** 25,31 **** const RmgrData RmgrTable[RM_MAX_ID + 1] = { ! {"XLOG", xlog_redo, xlog_desc, NULL, NULL, NULL}, {"Transaction", xact_redo, xact_desc, NULL, NULL, NULL}, {"Storage", smgr_redo, smgr_desc, NULL, NULL, NULL}, {"CLOG", clog_redo, clog_desc, NULL, NULL, NULL}, --- 26,32 ---- const RmgrData RmgrTable[RM_MAX_ID + 1] = { ! {"XLOG", xlog_redo, xlog_desc, NULL, NULL, xlog_safe_restartpoint}, {"Transaction", xact_redo, xact_desc, NULL, NULL, NULL}, {"Storage", smgr_redo, smgr_desc, NULL, NULL, NULL}, {"CLOG", clog_redo, clog_desc, NULL, NULL, NULL}, *** a/src/backend/access/transam/xlog.c --- b/src/backend/access/transam/xlog.c *************** *** 557,563 **** static TimeLineID lastPageTLI = 0; static XLogRecPtr minRecoveryPoint; /* local copy of * ControlFile->minRecoveryPoint */ static bool updateMinRecoveryPoint = true; ! static bool reachedMinRecoveryPoint = false; static bool InRedo = false; --- 557,563 ---- static XLogRecPtr minRecoveryPoint; /* local copy of * ControlFile->minRecoveryPoint */ static bool updateMinRecoveryPoint = true; ! bool reachedMinRecoveryPoint = false; static bool InRedo = false; *************** *** 6840,6851 **** StartupXLOG(void) LocalXLogInsertAllowed = -1; /* - * Check to see if the XLOG sequence contained any unresolved - * references to uninitialized pages. - */ - XLogCheckInvalidPages(); - - /* * Perform a checkpoint to update all our recovery activity to disk. * * Note that we write a shutdown checkpoint rather than an on-line --- 6840,6845 ---- *************** *** 6982,6987 **** CheckRecoveryConsistency(void) --- 6976,6987 ---- XLByteLE(minRecoveryPoint, EndRecPtr) && XLogRecPtrIsInvalid(ControlFile->backupStartPoint)) { + /* + * Check to see if the XLOG sequence contained any unresolved + * references to uninitialized pages. + */ + XLogCheckInvalidPages(); + reachedMinRecoveryPoint = true; ereport(LOG, (errmsg("consistent recovery state reached at %X/%X", *** a/src/backend/access/transam/xlogutils.c --- b/src/backend/access/transam/xlogutils.c *************** *** 52,57 **** typedef struct xl_invalid_page --- 52,73 ---- static HTAB *invalid_page_tab = NULL; + /* Report a reference to an invalid page */ + static void + report_invalid_page(int elevel, RelFileNode node, ForkNumber forkno, + BlockNumber blkno, bool present) + { + char *path = relpathperm(node, forkno); + + if (present) + elog(elevel, "page %u of relation %s is uninitialized", + blkno, path); + else + elog(elevel, "page %u of relation %s does not exist", + blkno, path); + pfree(path); + } + /* Log a reference to an invalid page */ static void log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, *************** *** 62,83 **** log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, bool found; /* * Log references to invalid pages at DEBUG1 level. This allows some * tracing of the cause (note the elog context mechanism will tell us * something about the XLOG record that generated the reference). */ if (log_min_messages <= DEBUG1 || client_min_messages <= DEBUG1) ! { ! char *path = relpathperm(node, forkno); ! ! if (present) ! elog(DEBUG1, "page %u of relation %s is uninitialized", ! blkno, path); ! else ! elog(DEBUG1, "page %u of relation %s does not exist", ! blkno, path); ! pfree(path); ! } if (invalid_page_tab == NULL) { --- 78,101 ---- bool found; /* + * Once recovery has reached a consistent state, the invalid-page + * table should be empty and remain so. If a reference to an invalid + * page is found after consistency is reached, emit PANIC immediately + * instead of adding the entry in the invalid-page table. + */ + if (reachedMinRecoveryPoint) + { + report_invalid_page(WARNING, node, forkno, blkno, present); + elog(PANIC, "WAL contains references to invalid pages"); + } + + /* * Log references to invalid pages at DEBUG1 level. This allows some * tracing of the cause (note the elog context mechanism will tell us * something about the XLOG record that generated the reference). */ if (log_min_messages <= DEBUG1 || client_min_messages <= DEBUG1) ! report_invalid_page(DEBUG1, node, forkno, blkno, present); if (invalid_page_tab == NULL) { *************** *** 200,214 **** XLogCheckInvalidPages(void) */ while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL) { ! char *path = relpathperm(hentry->key.node, hentry->key.forkno); ! ! if (hentry->present) ! elog(WARNING, "page %u of relation %s was uninitialized", ! hentry->key.blkno, path); ! else ! elog(WARNING, "page %u of relation %s did not exist", ! hentry->key.blkno, path); ! pfree(path); foundone = true; } --- 218,225 ---- */ while ((hentry = (xl_invalid_page *) hash_seq_search(&status)) != NULL) { ! report_invalid_page(WARNING, hentry->key.node, hentry->key.forkno, ! hentry->key.blkno, hentry->present); foundone = true; } *************** *** 449,451 **** XLogTruncateRelation(RelFileNode rnode, ForkNumber forkNum, --- 460,471 ---- { forget_invalid_pages(rnode, forkNum, nblocks); } + + bool + xlog_safe_restartpoint(void) + { + if (invalid_page_tab != NULL && + hash_get_num_entries(invalid_page_tab) > 0) + return false; + return true; + } *** a/src/include/access/xlog.h --- b/src/include/access/xlog.h *************** *** 189,194 **** typedef enum --- 189,196 ---- extern XLogRecPtr XactLastRecEnd; + extern bool reachedMinRecoveryPoint; + /* these variables are GUC parameters related to XLOG */ extern int CheckPointSegments; extern int wal_keep_segments; *** a/src/include/access/xlogutils.h --- b/src/include/access/xlogutils.h *************** *** 28,31 **** extern Buffer XLogReadBufferExtended(RelFileNode rnode, ForkNumber forknum, --- 28,33 ---- extern Relation CreateFakeRelcacheEntry(RelFileNode rnode); extern void FreeFakeRelcacheEntry(Relation fakerel); + extern bool xlog_safe_restartpoint(void); + #endif