diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c index 029b2f2deb..e44cf0d450 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) @@ -72,6 +79,20 @@ GetNewTransactionId(bool isSubXact) if (TransactionIdFollowsOrEquals(xid, ShmemVariableCache->xidVacLimit) && 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 @@ -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 ed42778551..7f675a985c 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 1058bd2d31..d2b3105e02 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 fbbd372b14..38271653f6 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 @@ -219,20 +214,6 @@ write_database_file(Relation drel) dattablespace = dbform->dattablespace; 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. */ @@ -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 6bc0c197b0..66904e6b09 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut . * * 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 b24d20af2f..e5b6480eb7 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 , 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 076327f9b8..2124c8d9b0 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 b23a663c53..87609e6f81 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 0312509e65..c7a740ca71 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;