diff options
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r-- | src/backend/access/transam/xlog.c | 94 |
1 files changed, 84 insertions, 10 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index d78f1c30744..16fb6b5e5e8 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.248 2006/08/17 23:04:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.249 2006/08/21 16:16:31 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -312,10 +312,8 @@ static XLogRecPtr RedoRecPtr; * new log file. * * CheckpointLock: must be held to do a checkpoint (ensures only one - * checkpointer at a time; even though the postmaster won't launch - * parallel checkpoint processes, we need this because manual checkpoints - * could be launched simultaneously). XXX now that all checkpoints are - * done by the bgwriter, isn't this lock redundant? + * checkpointer at a time; currently, with all checkpoints done by the + * bgwriter, this is just pro forma). * *---------- */ @@ -363,9 +361,13 @@ typedef struct XLogCtlData { /* Protected by WALInsertLock: */ XLogCtlInsert Insert; + /* Protected by info_lck: */ XLogwrtRqst LogwrtRqst; XLogwrtResult LogwrtResult; + uint32 ckptXidEpoch; /* nextXID & epoch of latest checkpoint */ + TransactionId ckptXid; + /* Protected by WALWriteLock: */ XLogCtlWrite Write; @@ -380,7 +382,7 @@ typedef struct XLogCtlData int XLogCacheBlck; /* highest allocated xlog buffer index */ TimeLineID ThisTimeLineID; - slock_t info_lck; /* locks shared LogwrtRqst/LogwrtResult */ + slock_t info_lck; /* locks shared variables shown above */ } XLogCtlData; static XLogCtlData *XLogCtl = NULL; @@ -4086,6 +4088,7 @@ BootStrapXLOG(void) checkPoint.redo.xrecoff = SizeOfXLogLongPHD; checkPoint.undo = checkPoint.redo; checkPoint.ThisTimeLineID = ThisTimeLineID; + checkPoint.nextXidEpoch = 0; checkPoint.nextXid = FirstNormalTransactionId; checkPoint.nextOid = FirstBootstrapObjectId; checkPoint.nextMulti = FirstMultiXactId; @@ -4752,8 +4755,9 @@ StartupXLOG(void) checkPoint.undo.xlogid, checkPoint.undo.xrecoff, wasShutdown ? "TRUE" : "FALSE"))); ereport(LOG, - (errmsg("next transaction ID: %u; next OID: %u", - checkPoint.nextXid, checkPoint.nextOid))); + (errmsg("next transaction ID: %u/%u; next OID: %u", + checkPoint.nextXidEpoch, checkPoint.nextXid, + checkPoint.nextOid))); ereport(LOG, (errmsg("next MultiXactId: %u; next MultiXactOffset: %u", checkPoint.nextMulti, checkPoint.nextMultiOffset))); @@ -5135,6 +5139,10 @@ StartupXLOG(void) /* start the archive_timeout timer running */ XLogCtl->Write.lastSegSwitchTime = ControlFile->time; + /* initialize shared-memory copy of latest checkpoint XID/epoch */ + XLogCtl->ckptXidEpoch = ControlFile->checkPointCopy.nextXidEpoch; + XLogCtl->ckptXid = ControlFile->checkPointCopy.nextXid; + /* Start up the commit log and related stuff, too */ StartupCLOG(); StartupSUBTRANS(oldestActiveXID); @@ -5365,6 +5373,46 @@ GetRecentNextXid(void) } /* + * GetNextXidAndEpoch - get the current nextXid value and associated epoch + * + * This is exported for use by code that would like to have 64-bit XIDs. + * We don't really support such things, but all XIDs within the system + * can be presumed "close to" the result, and thus the epoch associated + * with them can be determined. + */ +void +GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch) +{ + uint32 ckptXidEpoch; + TransactionId ckptXid; + TransactionId nextXid; + + /* Must read checkpoint info first, else have race condition */ + { + /* use volatile pointer to prevent code rearrangement */ + volatile XLogCtlData *xlogctl = XLogCtl; + + SpinLockAcquire(&xlogctl->info_lck); + ckptXidEpoch = xlogctl->ckptXidEpoch; + ckptXid = xlogctl->ckptXid; + SpinLockRelease(&xlogctl->info_lck); + } + + /* Now fetch current nextXid */ + nextXid = ReadNewTransactionId(); + + /* + * nextXid is certainly logically later than ckptXid. So if it's + * numerically less, it must have wrapped into the next epoch. + */ + if (nextXid < ckptXid) + ckptXidEpoch++; + + *xid = nextXid; + *epoch = ckptXidEpoch; +} + +/* * This must be called ONCE during postmaster or standalone-backend shutdown */ void @@ -5531,6 +5579,11 @@ CreateCheckPoint(bool shutdown, bool force) checkPoint.nextXid = ShmemVariableCache->nextXid; LWLockRelease(XidGenLock); + /* Increase XID epoch if we've wrapped around since last checkpoint */ + checkPoint.nextXidEpoch = ControlFile->checkPointCopy.nextXidEpoch; + if (checkPoint.nextXid < ControlFile->checkPointCopy.nextXid) + checkPoint.nextXidEpoch++; + LWLockAcquire(OidGenLock, LW_SHARED); checkPoint.nextOid = ShmemVariableCache->nextOid; if (!shutdown) @@ -5600,6 +5653,17 @@ CreateCheckPoint(bool shutdown, bool force) UpdateControlFile(); LWLockRelease(ControlFileLock); + /* Update shared-memory copy of checkpoint XID/epoch */ + { + /* use volatile pointer to prevent code rearrangement */ + volatile XLogCtlData *xlogctl = XLogCtl; + + SpinLockAcquire(&xlogctl->info_lck); + xlogctl->ckptXidEpoch = checkPoint.nextXidEpoch; + xlogctl->ckptXid = checkPoint.nextXid; + SpinLockRelease(&xlogctl->info_lck); + } + /* * We are now done with critical updates; no need for system panic if we * have trouble while fooling with offline log segments. @@ -5803,6 +5867,10 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record) MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset); + /* ControlFile->checkPointCopy always tracks the latest ckpt XID */ + ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch; + ControlFile->checkPointCopy.nextXid = checkPoint.nextXid; + /* * TLI may change in a shutdown checkpoint, but it shouldn't decrease */ @@ -5836,6 +5904,11 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record) } MultiXactAdvanceNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset); + + /* ControlFile->checkPointCopy always tracks the latest ckpt XID */ + ControlFile->checkPointCopy.nextXidEpoch = checkPoint.nextXidEpoch; + ControlFile->checkPointCopy.nextXid = checkPoint.nextXid; + /* TLI should not change in an on-line checkpoint */ if (checkPoint.ThisTimeLineID != ThisTimeLineID) ereport(PANIC, @@ -5861,10 +5934,11 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec) CheckPoint *checkpoint = (CheckPoint *) rec; appendStringInfo(buf, "checkpoint: redo %X/%X; undo %X/%X; " - "tli %u; xid %u; oid %u; multi %u; offset %u; %s", + "tli %u; xid %u/%u; oid %u; multi %u; offset %u; %s", checkpoint->redo.xlogid, checkpoint->redo.xrecoff, checkpoint->undo.xlogid, checkpoint->undo.xrecoff, - checkpoint->ThisTimeLineID, checkpoint->nextXid, + checkpoint->ThisTimeLineID, + checkpoint->nextXidEpoch, checkpoint->nextXid, checkpoint->nextOid, checkpoint->nextMulti, checkpoint->nextMultiOffset, |