On Mon, Oct 3, 2011 at 4:32 PM, Simon Riggs <[email protected]> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers