From 1e616f639156b2431725f7823c999486ca46c1ea Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 2 Dec 2011 10:49:54 +0200 Subject: During recovery, if we reach consistent state and still have entries in the invalid-page hash table, PANIC immediately. Immediate PANIC is much better than waiting for end-of-recovery, which is what we did before, because the end-of-recovery might not come until months later if this is a standby server. Also refrain from creating a restartpoint if there are invalid-page entries in the hash table. Restarting recovery from such a restartpoint would not see the invalid references, and wouldn't be able to cross-check them when consistency is reached. That wouldn't matter when things are going smoothly, but the more sanity checks you have the better. Fujii Masao --- src/backend/access/transam/xlogutils.c | 63 +++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 20 deletions(-) (limited to 'src/backend/access/transam/xlogutils.c') 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, @@ -61,23 +77,27 @@ log_invalid_page(RelFileNode node, ForkNumber forkno, BlockNumber blkno, xl_invalid_page *hentry; 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; } -- cgit v1.2.3