aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/xlog.c32
-rw-r--r--src/backend/access/transam/xlogutils.c63
-rw-r--r--src/include/access/xlog.h2
-rw-r--r--src/include/access/xlogutils.h1
4 files changed, 70 insertions, 28 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 20c04240b70..9bec6609921 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -562,7 +562,7 @@ static TimeLineID lastPageTLI = 0;
static XLogRecPtr minRecoveryPoint; /* local copy of
* ControlFile->minRecoveryPoint */
static bool updateMinRecoveryPoint = true;
-static bool reachedMinRecoveryPoint = false;
+bool reachedMinRecoveryPoint = false;
static bool InRedo = false;
@@ -6759,12 +6759,6 @@ 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
@@ -6906,6 +6900,12 @@ CheckRecoveryConsistency(void)
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",
@@ -7907,7 +7907,7 @@ RecoveryRestartPoint(const CheckPoint *checkPoint)
volatile XLogCtlData *xlogctl = XLogCtl;
/*
- * Is it safe to checkpoint? We must ask each of the resource managers
+ * Is it safe to restartpoint? We must ask each of the resource managers
* whether they have any partial state information that might prevent a
* correct restart from this point. If so, we skip this opportunity, but
* return at the next checkpoint record for another try.
@@ -7927,6 +7927,22 @@ RecoveryRestartPoint(const CheckPoint *checkPoint)
}
/*
+ * Also refrain from creating a restartpoint if we have seen any references
+ * to non-existent pages. Restarting recovery from the restartpoint would
+ * not see the references, so we would lose the cross-check that the pages
+ * belonged to a relation that was dropped later.
+ */
+ if (XLogHaveInvalidPages())
+ {
+ elog(trace_recovery(DEBUG2),
+ "could not record restart point at %X/%X because there "
+ "are unresolved references to invalid pages",
+ checkPoint->redo.xlogid,
+ checkPoint->redo.xrecoff);
+ return;
+ }
+
+ /*
* Copy the checkpoint record to shared memory, so that checkpointer
* can work out the next time it wants to perform a restartpoint.
*/
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 803d3907727..350d434562a 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -52,6 +52,22 @@ typedef struct xl_invalid_page
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,22 +78,26 @@ log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno,
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, PANIC immediately. This might
+ * seem aggressive, but it's better than letting the invalid reference
+ * linger in the hash table until the end of recovery and PANIC there,
+ * which might come only much later if this is a standby server.
+ */
+ 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)
- {
- 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);
- }
+ report_invalid_page(DEBUG1, node, forkno, blkno, present);
if (invalid_page_tab == NULL)
{
@@ -181,6 +201,16 @@ forget_invalid_pages_db(Oid dbid)
}
}
+/* Are there any unresolved references to invalid pages? */
+bool
+XLogHaveInvalidPages(void)
+{
+ if (invalid_page_tab != NULL &&
+ hash_get_num_entries(invalid_page_tab) > 0)
+ return true;
+ return false;
+}
+
/* Complain about any remaining invalid-page entries */
void
XLogCheckInvalidPages(void)
@@ -200,15 +230,8 @@ 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);
+ report_invalid_page(WARNING, hentry->key.node, hentry->key.forkno,
+ hentry->key.blkno, hentry->present);
foundone = true;
}
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 6344a850dcd..1fb56cdfd54 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -190,6 +190,8 @@ typedef enum
extern XLogRecPtr XactLastRecEnd;
+extern bool reachedMinRecoveryPoint;
+
/* these variables are GUC parameters related to XLOG */
extern int CheckPointSegments;
extern int wal_keep_segments;
diff --git a/src/include/access/xlogutils.h b/src/include/access/xlogutils.h
index 5a26d268896..c838c9ebda3 100644
--- a/src/include/access/xlogutils.h
+++ b/src/include/access/xlogutils.h
@@ -14,6 +14,7 @@
#include "storage/bufmgr.h"
+extern bool XLogHaveInvalidPages(void);
extern void XLogCheckInvalidPages(void);
extern void XLogDropRelation(RelFileNode rnode, ForkNumber forknum);