On Mon, Oct 3, 2011 at 4:32 PM, Simon Riggs <si...@2ndquadrant.com> wrote: >> I don't think this should use the rm_safe_restartpoint machinery. As you >> said, it's not tied to any specific resource manager. And I've actually been >> thinking that we will get rid of rm_safe_restartpoint altogether in the >> future. The two things that still use it are the b-tree and gin, and I'd >> like to change both of those to not require any post-recovery cleanup step >> to finish multi-page operations, similar to what I did with GiST in 9.1. > > I thought that was quite neat doing it that way, but there's no > specific reason to do it that way I guess. If you're happy to rewrite > the patch then I guess we're OK. > > I certainly would like to get rid of rm_safe_restartpoint in the > longer term, hopefully sooner.
Though Heikki might be already working on that,... anyway, the attached patch is the version which doesn't use rm_safe_restartpoint machinery. Regards, -- Fujii Masao NIPPON TELEGRAPH AND TELEPHONE CORPORATION NTT Open Source Software Center
*** 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; *************** *** 6841,6852 **** 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 --- 6841,6846 ---- *************** *** 6983,6988 **** CheckRecoveryConsistency(void) --- 6977,6988 ---- 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", *************** *** 7974,7980 **** RecoveryRestartPoint(const CheckPoint *checkPoint) volatile XLogCtlData *xlogctl = XLogCtl; /* ! * Is it safe to checkpoint? 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. --- 7974,7980 ---- volatile XLogCtlData *xlogctl = XLogCtl; /* ! * 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. *************** *** 7994,7999 **** RecoveryRestartPoint(const CheckPoint *checkPoint) --- 7994,8015 ---- } /* + * Is it safe to restartpoint? We must check whether there are any + * unresolved references to invalid pages 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. + */ + if (have_invalid_pages()) + { + 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 bgwriter can use * it the next time it wants to perform a restartpoint. */ *** 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) { *************** *** 181,186 **** forget_invalid_pages_db(Oid dbid) --- 199,214 ---- } } + /* Are there any unresolved references to invalid pages? */ + bool + have_invalid_pages(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,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; } --- 228,235 ---- */ 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; } *** 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 *************** *** 14,19 **** --- 14,21 ---- #include "storage/bufmgr.h" + extern bool have_invalid_pages(void); + extern void XLogCheckInvalidPages(void); extern void XLogDropRelation(RelFileNode rnode, ForkNumber forknum);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers