aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/varsup.c156
-rw-r--r--src/backend/access/transam/xlog.c27
-rw-r--r--src/backend/commands/vacuum.c17
-rw-r--r--src/backend/utils/init/flatfiles.c27
-rw-r--r--src/backend/utils/misc/guc.c3
-rw-r--r--src/bin/pg_controldata/pg_controldata.c6
-rw-r--r--src/bin/pg_resetxlog/pg_resetxlog.c24
-rw-r--r--src/include/access/transam.h9
-rw-r--r--src/include/catalog/pg_control.h6
9 files changed, 198 insertions, 77 deletions
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 029b2f2deb7..e44cf0d4505 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -6,7 +6,7 @@
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.84 2009/04/23 00:23:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.85 2009/08/31 02:23:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,11 +16,13 @@
#include "access/clog.h"
#include "access/subtrans.h"
#include "access/transam.h"
+#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "postmaster/autovacuum.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "utils/builtins.h"
+#include "utils/syscache.h"
/* Number of OIDs to prefetch (preallocate) per XLOG write */
@@ -31,9 +33,14 @@ VariableCache ShmemVariableCache = NULL;
/*
- * Allocate the next XID for my new transaction or subtransaction.
+ * Allocate the next XID for a new transaction or subtransaction.
*
* The new XID is also stored into MyProc before returning.
+ *
+ * Note: when this is called, we are actually already inside a valid
+ * transaction, since XIDs are now not allocated until the transaction
+ * does something. So it is safe to do a database lookup if we want to
+ * issue a warning about XID wrap.
*/
TransactionId
GetNewTransactionId(bool isSubXact)
@@ -73,6 +80,20 @@ GetNewTransactionId(bool isSubXact)
TransactionIdIsValid(ShmemVariableCache->xidVacLimit))
{
/*
+ * For safety's sake, we release XidGenLock while sending signals,
+ * warnings, etc. This is not so much because we care about
+ * preserving concurrency in this situation, as to avoid any
+ * possibility of deadlock while doing get_database_name().
+ * First, copy all the shared values we'll need in this path.
+ */
+ TransactionId xidWarnLimit = ShmemVariableCache->xidWarnLimit;
+ TransactionId xidStopLimit = ShmemVariableCache->xidStopLimit;
+ TransactionId xidWrapLimit = ShmemVariableCache->xidWrapLimit;
+ Oid oldest_datoid = ShmemVariableCache->oldestXidDB;
+
+ LWLockRelease(XidGenLock);
+
+ /*
* To avoid swamping the postmaster with signals, we issue the autovac
* request only once per 64K transaction starts. This still gives
* plenty of chances before we get into real trouble.
@@ -81,22 +102,50 @@ GetNewTransactionId(bool isSubXact)
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
if (IsUnderPostmaster &&
- TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidStopLimit))
- ereport(ERROR,
- (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
- errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
- NameStr(ShmemVariableCache->limit_datname)),
- errhint("Stop the postmaster and use a standalone backend to vacuum database \"%s\".\n"
- "You might also need to commit or roll back old prepared transactions.",
- NameStr(ShmemVariableCache->limit_datname))));
- else if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidWarnLimit))
- ereport(WARNING,
- (errmsg("database \"%s\" must be vacuumed within %u transactions",
- NameStr(ShmemVariableCache->limit_datname),
- ShmemVariableCache->xidWrapLimit - xid),
- errhint("To avoid a database shutdown, execute a database-wide VACUUM in \"%s\".\n"
- "You might also need to commit or roll back old prepared transactions.",
- NameStr(ShmemVariableCache->limit_datname))));
+ TransactionIdFollowsOrEquals(xid, xidStopLimit))
+ {
+ char *oldest_datname = get_database_name(oldest_datoid);
+
+ /* complain even if that DB has disappeared */
+ if (oldest_datname)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("database is not accepting commands to avoid wraparound data loss in database \"%s\"",
+ oldest_datname),
+ errhint("Stop the postmaster and use a standalone backend to vacuum that database.\n"
+ "You might also need to commit or roll back old prepared transactions.")));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("database is not accepting commands to avoid wraparound data loss in database with OID %u",
+ oldest_datoid),
+ errhint("Stop the postmaster and use a standalone backend to vacuum that database.\n"
+ "You might also need to commit or roll back old prepared transactions.")));
+ }
+ else if (TransactionIdFollowsOrEquals(xid, xidWarnLimit))
+ {
+ char *oldest_datname = get_database_name(oldest_datoid);
+
+ /* complain even if that DB has disappeared */
+ if (oldest_datname)
+ ereport(WARNING,
+ (errmsg("database \"%s\" must be vacuumed within %u transactions",
+ oldest_datname,
+ xidWrapLimit - xid),
+ errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
+ "You might also need to commit or roll back old prepared transactions.")));
+ else
+ ereport(WARNING,
+ (errmsg("database with OID %u must be vacuumed within %u transactions",
+ oldest_datoid,
+ xidWrapLimit - xid),
+ errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
+ "You might also need to commit or roll back old prepared transactions.")));
+ }
+
+ /* Re-acquire lock and start over */
+ LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
+ xid = ShmemVariableCache->nextXid;
}
/*
@@ -199,11 +248,10 @@ ReadNewTransactionId(void)
/*
* Determine the last safe XID to allocate given the currently oldest
* datfrozenxid (ie, the oldest XID that might exist in any database
- * of our cluster).
+ * of our cluster), and the OID of the (or a) database with that value.
*/
void
-SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
- Name oldest_datname)
+SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
{
TransactionId xidVacLimit;
TransactionId xidWarnLimit;
@@ -275,14 +323,14 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
ShmemVariableCache->xidWarnLimit = xidWarnLimit;
ShmemVariableCache->xidStopLimit = xidStopLimit;
ShmemVariableCache->xidWrapLimit = xidWrapLimit;
- namecpy(&ShmemVariableCache->limit_datname, oldest_datname);
+ ShmemVariableCache->oldestXidDB = oldest_datoid;
curXid = ShmemVariableCache->nextXid;
LWLockRelease(XidGenLock);
/* Log the info */
ereport(DEBUG1,
- (errmsg("transaction ID wrap limit is %u, limited by database \"%s\"",
- xidWrapLimit, NameStr(*oldest_datname))));
+ (errmsg("transaction ID wrap limit is %u, limited by database with OID %u",
+ xidWrapLimit, oldest_datoid)));
/*
* If past the autovacuum force point, immediately signal an autovac
@@ -297,13 +345,59 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
/* Give an immediate warning if past the wrap warn point */
if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit))
- ereport(WARNING,
- (errmsg("database \"%s\" must be vacuumed within %u transactions",
- NameStr(*oldest_datname),
- xidWrapLimit - curXid),
- errhint("To avoid a database shutdown, execute a database-wide VACUUM in \"%s\".\n"
- "You might also need to commit or roll back old prepared transactions.",
- NameStr(*oldest_datname))));
+ {
+ char *oldest_datname = get_database_name(oldest_datoid);
+
+ /*
+ * Note: it's possible that get_database_name fails and returns NULL,
+ * for example because the database just got dropped. We'll still
+ * warn, even though the warning might now be unnecessary.
+ */
+ if (oldest_datname)
+ ereport(WARNING,
+ (errmsg("database \"%s\" must be vacuumed within %u transactions",
+ oldest_datname,
+ xidWrapLimit - curXid),
+ errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
+ "You might also need to commit or roll back old prepared transactions.")));
+ else
+ ereport(WARNING,
+ (errmsg("database with OID %u must be vacuumed within %u transactions",
+ oldest_datoid,
+ xidWrapLimit - curXid),
+ errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n"
+ "You might also need to commit or roll back old prepared transactions.")));
+ }
+}
+
+
+/*
+ * TransactionIdLimitIsValid -- is the shared XID wrap-limit data sane?
+ *
+ * We primarily check whether oldestXidDB is valid. The cases we have in
+ * mind are that that database was dropped, or the field was reset to zero
+ * by pg_resetxlog. In either case we should force recalculation of the
+ * wrap limit. In future we might add some more sanity checks here.
+ */
+bool
+TransactionIdLimitIsValid(void)
+{
+ TransactionId oldestXid;
+ Oid oldestXidDB;
+
+ /* Locking is probably not really necessary, but let's be careful */
+ LWLockAcquire(XidGenLock, LW_SHARED);
+ oldestXid = ShmemVariableCache->oldestXid;
+ oldestXidDB = ShmemVariableCache->oldestXidDB;
+ LWLockRelease(XidGenLock);
+
+ if (!TransactionIdIsNormal(oldestXid))
+ return false; /* shouldn't happen, but just in case */
+ if (!SearchSysCacheExists(DATABASEOID,
+ ObjectIdGetDatum(oldestXidDB),
+ 0, 0, 0))
+ return false; /* could happen, per comment above */
+ return true;
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index ed427785517..7f675a985cb 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.349 2009/08/27 07:15:41 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.350 2009/08/31 02:23:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -34,6 +34,7 @@
#include "access/xlogutils.h"
#include "catalog/catversion.h"
#include "catalog/pg_control.h"
+#include "catalog/pg_database.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqsignal.h"
@@ -4638,12 +4639,16 @@ BootStrapXLOG(void)
checkPoint.nextOid = FirstBootstrapObjectId;
checkPoint.nextMulti = FirstMultiXactId;
checkPoint.nextMultiOffset = 0;
+ checkPoint.oldestXid = FirstNormalTransactionId;
+ checkPoint.oldestXidDB = TemplateDbOid;
checkPoint.time = (pg_time_t) time(NULL);
ShmemVariableCache->nextXid = checkPoint.nextXid;
ShmemVariableCache->nextOid = checkPoint.nextOid;
ShmemVariableCache->oidCount = 0;
MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
+ ShmemVariableCache->oldestXid = checkPoint.oldestXid;
+ ShmemVariableCache->oldestXidDB = checkPoint.oldestXidDB;
/* Set up the XLOG page header */
page->xlp_magic = XLOG_PAGE_MAGIC;
@@ -5355,6 +5360,9 @@ StartupXLOG(void)
ereport(DEBUG1,
(errmsg("next MultiXactId: %u; next MultiXactOffset: %u",
checkPoint.nextMulti, checkPoint.nextMultiOffset)));
+ ereport(DEBUG1,
+ (errmsg("oldest unfrozen transaction ID: %u, in database %u",
+ checkPoint.oldestXid, checkPoint.oldestXidDB)));
if (!TransactionIdIsNormal(checkPoint.nextXid))
ereport(PANIC,
(errmsg("invalid next transaction ID")));
@@ -5363,6 +5371,8 @@ StartupXLOG(void)
ShmemVariableCache->nextOid = checkPoint.nextOid;
ShmemVariableCache->oidCount = 0;
MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset);
+ ShmemVariableCache->oldestXid = checkPoint.oldestXid;
+ ShmemVariableCache->oldestXidDB = checkPoint.oldestXidDB;
/*
* We must replay WAL entries using the same TimeLineID they were created
@@ -6546,6 +6556,8 @@ CreateCheckPoint(int flags)
*/
LWLockAcquire(XidGenLock, LW_SHARED);
checkPoint.nextXid = ShmemVariableCache->nextXid;
+ checkPoint.oldestXid = ShmemVariableCache->oldestXid;
+ checkPoint.oldestXidDB = ShmemVariableCache->oldestXidDB;
LWLockRelease(XidGenLock);
/* Increase XID epoch if we've wrapped around since last checkpoint */
@@ -6984,6 +6996,8 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
ShmemVariableCache->oidCount = 0;
MultiXactSetNextMXact(checkPoint.nextMulti,
checkPoint.nextMultiOffset);
+ ShmemVariableCache->oldestXid = checkPoint.oldestXid;
+ ShmemVariableCache->oldestXidDB = checkPoint.oldestXidDB;
/* ControlFile->checkPointCopy always tracks the latest ckpt XID */
ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch;
@@ -7022,6 +7036,12 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
}
MultiXactAdvanceNextMXact(checkPoint.nextMulti,
checkPoint.nextMultiOffset);
+ if (TransactionIdPrecedes(ShmemVariableCache->oldestXid,
+ checkPoint.oldestXid))
+ {
+ ShmemVariableCache->oldestXid = checkPoint.oldestXid;
+ ShmemVariableCache->oldestXidDB = checkPoint.oldestXidDB;
+ }
/* ControlFile->checkPointCopy always tracks the latest ckpt XID */
ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch;
@@ -7056,13 +7076,16 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
CheckPoint *checkpoint = (CheckPoint *) rec;
appendStringInfo(buf, "checkpoint: redo %X/%X; "
- "tli %u; xid %u/%u; oid %u; multi %u; offset %u; %s",
+ "tli %u; xid %u/%u; oid %u; multi %u; offset %u; "
+ "oldest xid %u in DB %u; %s",
checkpoint->redo.xlogid, checkpoint->redo.xrecoff,
checkpoint->ThisTimeLineID,
checkpoint->nextXidEpoch, checkpoint->nextXid,
checkpoint->nextOid,
checkpoint->nextMulti,
checkpoint->nextMultiOffset,
+ checkpoint->oldestXid,
+ checkpoint->oldestXidDB,
(info == XLOG_CHECKPOINT_SHUTDOWN) ? "shutdown" : "online");
}
else if (info == XLOG_NOOP)
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 1058bd2d312..d2b3105e028 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -13,7 +13,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.390 2009/08/24 02:18:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.391 2009/08/31 02:23:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -895,8 +895,9 @@ vac_update_datfrozenxid(void)
/*
* If we were able to advance datfrozenxid, mark the flat-file copy of
* pg_database for update at commit, and see if we can truncate pg_clog.
+ * Also force update if the shared XID-wrap-limit info is stale.
*/
- if (dirty)
+ if (dirty || !TransactionIdLimitIsValid())
{
database_file_update_needed();
vac_truncate_clog(newFrozenXid);
@@ -916,7 +917,7 @@ vac_update_datfrozenxid(void)
*
* This routine is shared by full and lazy VACUUM. Note that it's
* only invoked when we've managed to change our DB's datfrozenxid
- * entry.
+ * entry, or we found that the shared XID-wrap-limit info is stale.
*/
static void
vac_truncate_clog(TransactionId frozenXID)
@@ -925,11 +926,11 @@ vac_truncate_clog(TransactionId frozenXID)
Relation relation;
HeapScanDesc scan;
HeapTuple tuple;
- NameData oldest_datname;
+ Oid oldest_datoid;
bool frozenAlreadyWrapped = false;
- /* init oldest_datname to sync with my frozenXID */
- namestrcpy(&oldest_datname, get_database_name(MyDatabaseId));
+ /* init oldest_datoid to sync with my frozenXID */
+ oldest_datoid = MyDatabaseId;
/*
* Scan pg_database to compute the minimum datfrozenxid
@@ -958,7 +959,7 @@ vac_truncate_clog(TransactionId frozenXID)
else if (TransactionIdPrecedes(dbform->datfrozenxid, frozenXID))
{
frozenXID = dbform->datfrozenxid;
- namecpy(&oldest_datname, &dbform->datname);
+ oldest_datoid = HeapTupleGetOid(tuple);
}
}
@@ -987,7 +988,7 @@ vac_truncate_clog(TransactionId frozenXID)
* Update the wrap limit for GetNewTransactionId. Note: this function
* will also signal the postmaster for an(other) autovac cycle if needed.
*/
- SetTransactionIdLimit(frozenXID, &oldest_datname);
+ SetTransactionIdLimit(frozenXID, oldest_datoid);
}
diff --git a/src/backend/utils/init/flatfiles.c b/src/backend/utils/init/flatfiles.c
index fbbd372b141..38271653f6d 100644
--- a/src/backend/utils/init/flatfiles.c
+++ b/src/backend/utils/init/flatfiles.c
@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.38 2009/08/29 19:26:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.39 2009/08/31 02:23:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -166,9 +166,6 @@ name_okay(const char *str)
/*
* write_database_file: update the flat database file
- *
- * A side effect is to determine the oldest database's datfrozenxid
- * so we can set or update the XID wrap limit.
*/
static void
write_database_file(Relation drel)
@@ -180,8 +177,6 @@ write_database_file(Relation drel)
mode_t oumask;
HeapScanDesc scan;
HeapTuple tuple;
- NameData oldest_datname;
- TransactionId oldest_datfrozenxid = InvalidTransactionId;
/*
* Create a temporary filename to be renamed later. This prevents the
@@ -220,20 +215,6 @@ write_database_file(Relation drel)
datfrozenxid = dbform->datfrozenxid;
/*
- * Identify the oldest datfrozenxid. This must match the logic in
- * vac_truncate_clog() in vacuum.c.
- */
- if (TransactionIdIsNormal(datfrozenxid))
- {
- if (oldest_datfrozenxid == InvalidTransactionId ||
- TransactionIdPrecedes(datfrozenxid, oldest_datfrozenxid))
- {
- oldest_datfrozenxid = datfrozenxid;
- namestrcpy(&oldest_datname, datname);
- }
- }
-
- /*
* Check for illegal characters in the database name.
*/
if (!name_okay(datname))
@@ -270,12 +251,6 @@ write_database_file(Relation drel)
(errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\": %m",
tempname, filename)));
-
- /*
- * Set the transaction ID wrap limit using the oldest datfrozenxid
- */
- if (oldest_datfrozenxid != InvalidTransactionId)
- SetTransactionIdLimit(oldest_datfrozenxid, &oldest_datname);
}
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 6bc0c197b0f..66904e6b091 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.512 2009/08/29 19:26:51 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.513 2009/08/31 02:23:22 tgl Exp $
*
*--------------------------------------------------------------------
*/
@@ -1864,6 +1864,7 @@ static struct config_int ConfigureNamesInt[] =
NULL
},
&autovacuum_freeze_max_age,
+ /* see pg_resetxlog if you change the upper-limit value */
200000000, 100000000, 2000000000, NULL, NULL
},
{
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index b24d20af2f4..e5b6480eb7f 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -6,7 +6,7 @@
* copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
* licence: BSD
*
- * $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.43 2009/06/11 14:49:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.44 2009/08/31 02:23:22 tgl Exp $
*/
#include "postgres_fe.h"
@@ -192,6 +192,10 @@ main(int argc, char *argv[])
ControlFile.checkPointCopy.nextMulti);
printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
ControlFile.checkPointCopy.nextMultiOffset);
+ printf(_("Latest checkpoint's oldestXID: %u\n"),
+ ControlFile.checkPointCopy.oldestXid);
+ printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
+ ControlFile.checkPointCopy.oldestXidDB);
printf(_("Time of latest checkpoint: %s\n"),
ckpttime_str);
printf(_("Minimum recovery ending location: %X/%X\n"),
diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c
index 076327f9b81..2124c8d9b0d 100644
--- a/src/bin/pg_resetxlog/pg_resetxlog.c
+++ b/src/bin/pg_resetxlog/pg_resetxlog.c
@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.74 2009/06/11 14:49:07 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.75 2009/08/31 02:23:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -307,8 +307,22 @@ main(int argc, char *argv[])
ControlFile.checkPointCopy.nextXidEpoch = set_xid_epoch;
if (set_xid != 0)
+ {
ControlFile.checkPointCopy.nextXid = set_xid;
+ /*
+ * For the moment, just set oldestXid to a value that will force
+ * immediate autovacuum-for-wraparound. It's not clear whether
+ * adding user control of this is useful, so let's just do something
+ * that's reasonably safe. The magic constant here corresponds to
+ * the maximum allowed value of autovacuum_freeze_max_age.
+ */
+ ControlFile.checkPointCopy.oldestXid = set_xid - 2000000000;
+ if (ControlFile.checkPointCopy.oldestXid < FirstNormalTransactionId)
+ ControlFile.checkPointCopy.oldestXid += FirstNormalTransactionId;
+ ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
+ }
+
if (set_oid != 0)
ControlFile.checkPointCopy.nextOid = set_oid;
@@ -476,10 +490,12 @@ GuessControlValues(void)
ControlFile.checkPointCopy.redo.xrecoff = SizeOfXLogLongPHD;
ControlFile.checkPointCopy.ThisTimeLineID = 1;
ControlFile.checkPointCopy.nextXidEpoch = 0;
- ControlFile.checkPointCopy.nextXid = (TransactionId) 514; /* XXX */
+ ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;
ControlFile.checkPointCopy.nextOid = FirstBootstrapObjectId;
ControlFile.checkPointCopy.nextMulti = FirstMultiXactId;
ControlFile.checkPointCopy.nextMultiOffset = 0;
+ ControlFile.checkPointCopy.oldestXid = FirstNormalTransactionId;
+ ControlFile.checkPointCopy.oldestXidDB = InvalidOid;
ControlFile.checkPointCopy.time = (pg_time_t) time(NULL);
ControlFile.state = DB_SHUTDOWNED;
@@ -554,6 +570,10 @@ PrintControlValues(bool guessed)
ControlFile.checkPointCopy.nextMulti);
printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
ControlFile.checkPointCopy.nextMultiOffset);
+ printf(_("Latest checkpoint's oldestXID: %u\n"),
+ ControlFile.checkPointCopy.oldestXid);
+ printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
+ ControlFile.checkPointCopy.oldestXidDB);
printf(_("Maximum data alignment: %u\n"),
ControlFile.maxAlign);
/* we don't print floatFormat since can't say much useful about it */
diff --git a/src/include/access/transam.h b/src/include/access/transam.h
index b23a663c53a..87609e6f81c 100644
--- a/src/include/access/transam.h
+++ b/src/include/access/transam.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/transam.h,v 1.68 2009/05/08 03:21:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/access/transam.h,v 1.69 2009/08/31 02:23:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -90,7 +90,7 @@
* just one struct with different fields that are protected by different
* LWLocks.
*
- * Note: xidWrapLimit and limit_datname are not "active" values, but are
+ * Note: xidWrapLimit and oldestXidDB are not "active" values, but are
* used just to generate useful messages when xidWarnLimit or xidStopLimit
* are exceeded.
*/
@@ -112,7 +112,7 @@ typedef struct VariableCacheData
TransactionId xidWarnLimit; /* start complaining here */
TransactionId xidStopLimit; /* refuse to advance nextXid beyond here */
TransactionId xidWrapLimit; /* where the world ends */
- NameData limit_datname; /* database that needs vacuumed first */
+ Oid oldestXidDB; /* database with minimum datfrozenxid */
/*
* These fields are protected by ProcArrayLock.
@@ -155,7 +155,8 @@ extern XLogRecPtr TransactionIdGetCommitLSN(TransactionId xid);
extern TransactionId GetNewTransactionId(bool isSubXact);
extern TransactionId ReadNewTransactionId(void);
extern void SetTransactionIdLimit(TransactionId oldest_datfrozenxid,
- Name oldest_datname);
+ Oid oldest_datoid);
+extern bool TransactionIdLimitIsValid(void);
extern Oid GetNewObjectId(void);
#endif /* TRAMSAM_H */
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 0312509e65d..c7a740ca710 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.43 2009/01/01 17:23:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.44 2009/08/31 02:23:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,7 +21,7 @@
/* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION 843
+#define PG_CONTROL_VERSION 851
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
@@ -37,6 +37,8 @@ typedef struct CheckPoint
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
+ TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
+ Oid oldestXidDB; /* database with minimum datfrozenxid */
pg_time_t time; /* time stamp of checkpoint */
} CheckPoint;