Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Typedefs | Functions | Variables

transam.h File Reference

#include "access/xlogdefs.h"
Include dependency graph for transam.h:

Go to the source code of this file.

Data Structures

struct  VariableCacheData

Defines

#define InvalidTransactionId   ((TransactionId) 0)
#define BootstrapTransactionId   ((TransactionId) 1)
#define FrozenTransactionId   ((TransactionId) 2)
#define FirstNormalTransactionId   ((TransactionId) 3)
#define MaxTransactionId   ((TransactionId) 0xFFFFFFFF)
#define TransactionIdIsValid(xid)   ((xid) != InvalidTransactionId)
#define TransactionIdIsNormal(xid)   ((xid) >= FirstNormalTransactionId)
#define TransactionIdEquals(id1, id2)   ((id1) == (id2))
#define TransactionIdStore(xid, dest)   (*(dest) = (xid))
#define StoreInvalidTransactionId(dest)   (*(dest) = InvalidTransactionId)
#define TransactionIdAdvance(dest)
#define TransactionIdRetreat(dest)
#define NormalTransactionIdPrecedes(id1, id2)
#define FirstBootstrapObjectId   10000
#define FirstNormalObjectId   16384

Typedefs

typedef struct VariableCacheData VariableCacheData
typedef VariableCacheDataVariableCache

Functions

bool TransactionStartedDuringRecovery (void)
bool TransactionIdDidCommit (TransactionId transactionId)
bool TransactionIdDidAbort (TransactionId transactionId)
bool TransactionIdIsKnownCompleted (TransactionId transactionId)
void TransactionIdAbort (TransactionId transactionId)
void TransactionIdCommitTree (TransactionId xid, int nxids, TransactionId *xids)
void TransactionIdAsyncCommitTree (TransactionId xid, int nxids, TransactionId *xids, XLogRecPtr lsn)
void TransactionIdAbortTree (TransactionId xid, int nxids, TransactionId *xids)
bool TransactionIdPrecedes (TransactionId id1, TransactionId id2)
bool TransactionIdPrecedesOrEquals (TransactionId id1, TransactionId id2)
bool TransactionIdFollows (TransactionId id1, TransactionId id2)
bool TransactionIdFollowsOrEquals (TransactionId id1, TransactionId id2)
TransactionId TransactionIdLatest (TransactionId mainxid, int nxids, const TransactionId *xids)
XLogRecPtr TransactionIdGetCommitLSN (TransactionId xid)
TransactionId GetNewTransactionId (bool isSubXact)
TransactionId ReadNewTransactionId (void)
void SetTransactionIdLimit (TransactionId oldest_datfrozenxid, Oid oldest_datoid)
bool ForceTransactionIdLimitUpdate (void)
Oid GetNewObjectId (void)

Variables

PGDLLIMPORT VariableCache ShmemVariableCache

Define Documentation

#define BootstrapTransactionId   ((TransactionId) 1)

Definition at line 32 of file transam.h.

Referenced by TransactionLogFetch().

#define FirstBootstrapObjectId   10000
#define FirstNormalObjectId   16384
#define FirstNormalTransactionId   ((TransactionId) 3)
#define FrozenTransactionId   ((TransactionId) 2)
#define InvalidTransactionId   ((TransactionId) 0)
#define MaxTransactionId   ((TransactionId) 0xFFFFFFFF)

Definition at line 35 of file transam.h.

Referenced by SetTransactionIdLimit().

#define NormalTransactionIdPrecedes (   id1,
  id2 
)
Value:
(AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \
    (int32) ((id1) - (id2)) < 0)

Definition at line 62 of file transam.h.

Referenced by GetSnapshotData().

#define StoreInvalidTransactionId (   dest  )     (*(dest) = InvalidTransactionId)

Definition at line 45 of file transam.h.

#define TransactionIdAdvance (   dest  ) 
Value:
do { \
        (dest)++; \
        if ((dest) < FirstNormalTransactionId) \
            (dest) = FirstNormalTransactionId; \
    } while(0)

Definition at line 48 of file transam.h.

Referenced by GetNewTransactionId(), GetOldestXmin(), GetSnapshotData(), KnownAssignedXidsAdd(), multixact_redo(), PrescanPreparedTransactions(), ProcArrayApplyRecoveryInfo(), RecordKnownAssignedTransactionIds(), StartupXLOG(), xact_redo_abort(), and xact_redo_commit_internal().

#define TransactionIdEquals (   id1,
  id2 
)    ((id1) == (id2))
#define TransactionIdIsNormal (   xid  )     ((xid) >= FirstNormalTransactionId)
#define TransactionIdIsValid (   xid  )     ((xid) != InvalidTransactionId)

Definition at line 41 of file transam.h.

Referenced by _bt_check_unique(), _bt_doinsert(), AbortSubTransaction(), AssignTransactionId(), bitgetpage(), check_exclusion_constraint(), CheckCachedPlan(), CheckForSerializableConflictOut(), CheckPointPredicate(), CheckTableForSerializableConflictIn(), ClearOldPredicateLocks(), CommitSubTransaction(), ConditionalXactLockTableWait(), DropAllPredicateLocksFromTable(), EvalPlanQualFetch(), ForceTransactionIdLimitUpdate(), GetConflictingVirtualXIDs(), GetCurrentTransactionId(), GetCurrentVirtualXIDs(), GetMultiXactIdMembers(), GetRunningTransactionData(), GetRunningTransactionLocks(), GetSerializableTransactionSnapshotInt(), GetSnapshotData(), GetStableLatestTransactionId(), GetTopTransactionId(), heap_get_latest_tid(), heap_get_root_tuples(), heap_hot_search_buffer(), heap_prune_chain(), heap_prune_record_prunable(), heap_update(), heap_xlog_clean(), heapgetpage(), HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesNow(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuum(), index_getnext_tid(), KnownAssignedXidExists(), KnownAssignedXidsGetAndSetXmin(), KnownAssignedXidsRemove(), KnownAssignedXidsRemovePreceding(), KnownAssignedXidsRemoveTree(), LockGXact(), MultiXactIdCreate(), MultiXactIdExpand(), OldSerXidAdd(), OldSerXidGetMinConflictCommitSeqNo(), OldSerXidSetActiveSerXmin(), PLy_procedure_argument_valid(), predicatelock_twophase_recover(), PredicateLockPageSplit(), PredicateLockTuple(), ProcArrayApplyRecoveryInfo(), ProcArrayEndTransaction(), ProcArrayRemove(), RecordKnownAssignedTransactionIds(), RecordTransactionAbort(), RecordTransactionCommit(), RegisterPredicateLockingXid(), ResolveRecoveryConflictWithSnapshot(), SetHintBits(), SetNewSxactGlobalXmin(), spgFormDeadTuple(), spgRedoVacuumRedirect(), StandbyAcquireAccessExclusiveLock(), StandbyReleaseLocks(), StandbyReleaseOldLocks(), StandbyTransactionIdIsPrepared(), StartupXLOG(), SubTransGetTopmostTransaction(), SubTransSetParent(), SummarizeOldestCommittedSxact(), TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsActive(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdSetPageStatus(), vacuum_log_cleanup_info(), vacuumRedirectAndPlaceholder(), XactLockTableWait(), XidCacheRemoveRunningXids(), XidIsConcurrent(), and XLogWalRcvSendHSFeedback().

#define TransactionIdRetreat (   dest  ) 
Value:
do { \
        (dest)--; \
    } while ((dest) < FirstNormalTransactionId)

Definition at line 56 of file transam.h.

Referenced by ProcArrayApplyRecoveryInfo(), StartupXLOG(), and xlog_redo().

#define TransactionIdStore (   xid,
  dest 
)    (*(dest) = (xid))

Definition at line 44 of file transam.h.


Typedef Documentation

Definition at line 128 of file transam.h.


Function Documentation

bool ForceTransactionIdLimitUpdate ( void   ) 

Definition at line 397 of file varsup.c.

References DATABASEOID, LW_SHARED, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextXid, ObjectIdGetDatum, VariableCacheData::oldestXid, VariableCacheData::oldestXidDB, SearchSysCacheExists1, TransactionIdFollowsOrEquals(), TransactionIdIsNormal, TransactionIdIsValid, XidGenLock, and VariableCacheData::xidVacLimit.

Referenced by vac_update_datfrozenxid().

{
    TransactionId nextXid;
    TransactionId xidVacLimit;
    TransactionId oldestXid;
    Oid         oldestXidDB;

    /* Locking is probably not really necessary, but let's be careful */
    LWLockAcquire(XidGenLock, LW_SHARED);
    nextXid = ShmemVariableCache->nextXid;
    xidVacLimit = ShmemVariableCache->xidVacLimit;
    oldestXid = ShmemVariableCache->oldestXid;
    oldestXidDB = ShmemVariableCache->oldestXidDB;
    LWLockRelease(XidGenLock);

    if (!TransactionIdIsNormal(oldestXid))
        return true;            /* shouldn't happen, but just in case */
    if (!TransactionIdIsValid(xidVacLimit))
        return true;            /* this shouldn't happen anymore either */
    if (TransactionIdFollowsOrEquals(nextXid, xidVacLimit))
        return true;            /* past VacLimit, don't delay updating */
    if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(oldestXidDB)))
        return true;            /* could happen, per comments above */
    return false;
}

Oid GetNewObjectId ( void   ) 

Definition at line 435 of file varsup.c.

References elog, ERROR, FirstBootstrapObjectId, FirstNormalObjectId, IsPostmasterEnvironment, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextOid, VariableCacheData::oidCount, OidGenLock, RecoveryInProgress(), VAR_OID_PREFETCH, and XLogPutNextOid().

Referenced by GetNewOid(), GetNewOidWithIndex(), and GetNewRelFileNode().

{
    Oid         result;

    /* safety check, we should never get this far in a HS slave */
    if (RecoveryInProgress())
        elog(ERROR, "cannot assign OIDs during recovery");

    LWLockAcquire(OidGenLock, LW_EXCLUSIVE);

    /*
     * Check for wraparound of the OID counter.  We *must* not return 0
     * (InvalidOid); and as long as we have to check that, it seems a good
     * idea to skip over everything below FirstNormalObjectId too. (This
     * basically just avoids lots of collisions with bootstrap-assigned OIDs
     * right after a wrap occurs, so as to avoid a possibly large number of
     * iterations in GetNewOid.)  Note we are relying on unsigned comparison.
     *
     * During initdb, we start the OID generator at FirstBootstrapObjectId, so
     * we only enforce wrapping to that point when in bootstrap or standalone
     * mode.  The first time through this routine after normal postmaster
     * start, the counter will be forced up to FirstNormalObjectId. This
     * mechanism leaves the OIDs between FirstBootstrapObjectId and
     * FirstNormalObjectId available for automatic assignment during initdb,
     * while ensuring they will never conflict with user-assigned OIDs.
     */
    if (ShmemVariableCache->nextOid < ((Oid) FirstNormalObjectId))
    {
        if (IsPostmasterEnvironment)
        {
            /* wraparound in normal environment */
            ShmemVariableCache->nextOid = FirstNormalObjectId;
            ShmemVariableCache->oidCount = 0;
        }
        else
        {
            /* we may be bootstrapping, so don't enforce the full range */
            if (ShmemVariableCache->nextOid < ((Oid) FirstBootstrapObjectId))
            {
                /* wraparound in standalone environment? */
                ShmemVariableCache->nextOid = FirstBootstrapObjectId;
                ShmemVariableCache->oidCount = 0;
            }
        }
    }

    /* If we run out of logged for use oids then we must log more */
    if (ShmemVariableCache->oidCount == 0)
    {
        XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH);
        ShmemVariableCache->oidCount = VAR_OID_PREFETCH;
    }

    result = ShmemVariableCache->nextOid;

    (ShmemVariableCache->nextOid)++;
    (ShmemVariableCache->oidCount)--;

    LWLockRelease(OidGenLock);

    return result;
}

TransactionId GetNewTransactionId ( bool  isSubXact  ) 

Definition at line 46 of file varsup.c.

References Assert, elog, ereport, errcode(), errhint(), errmsg(), ERROR, ExtendCLOG(), ExtendSUBTRANS(), get_database_name(), IsBootstrapProcessingMode, IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyPgXact, MyProc, VariableCacheData::nextXid, PGXACT::nxids, VariableCacheData::oldestXidDB, PGXACT::overflowed, PGPROC_MAX_CACHED_SUBXIDS, PMSIGNAL_START_AUTOVAC_LAUNCHER, RecoveryInProgress(), SendPostmasterSignal(), PGPROC::subxids, TransactionIdAdvance, TransactionIdFollowsOrEquals(), WARNING, PGXACT::xid, XidGenLock, XidCache::xids, VariableCacheData::xidStopLimit, VariableCacheData::xidVacLimit, VariableCacheData::xidWarnLimit, and VariableCacheData::xidWrapLimit.

Referenced by AssignTransactionId().

{
    TransactionId xid;

    /*
     * During bootstrap initialization, we return the special bootstrap
     * transaction id.
     */
    if (IsBootstrapProcessingMode())
    {
        Assert(!isSubXact);
        MyPgXact->xid = BootstrapTransactionId;
        return BootstrapTransactionId;
    }

    /* safety check, we should never get this far in a HS slave */
    if (RecoveryInProgress())
        elog(ERROR, "cannot assign TransactionIds during recovery");

    LWLockAcquire(XidGenLock, LW_EXCLUSIVE);

    xid = ShmemVariableCache->nextXid;

    /*----------
     * Check to see if it's safe to assign another XID.  This protects against
     * catastrophic data loss due to XID wraparound.  The basic rules are:
     *
     * If we're past xidVacLimit, start trying to force autovacuum cycles.
     * If we're past xidWarnLimit, start issuing warnings.
     * If we're past xidStopLimit, refuse to execute transactions, unless
     * we are running in a standalone backend (which gives an escape hatch
     * to the DBA who somehow got past the earlier defenses).
     *
     * Note that this coding also appears in GetNewMultiXactId.
     *----------
     */
    if (TransactionIdFollowsOrEquals(xid, 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.
         */
        if (IsUnderPostmaster && (xid % 65536) == 0)
            SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);

        if (IsUnderPostmaster &&
            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;
    }

    /*
     * If we are allocating the first XID of a new page of the commit log,
     * zero out that commit-log page before returning. We must do this while
     * holding XidGenLock, else another xact could acquire and commit a later
     * XID before we zero the page.  Fortunately, a page of the commit log
     * holds 32K or more transactions, so we don't have to do this very often.
     *
     * Extend pg_subtrans too.
     */
    ExtendCLOG(xid);
    ExtendSUBTRANS(xid);

    /*
     * Now advance the nextXid counter.  This must not happen until after we
     * have successfully completed ExtendCLOG() --- if that routine fails, we
     * want the next incoming transaction to try it again.  We cannot assign
     * more XIDs until there is CLOG space for them.
     */
    TransactionIdAdvance(ShmemVariableCache->nextXid);

    /*
     * We must store the new XID into the shared ProcArray before releasing
     * XidGenLock.  This ensures that every active XID older than
     * latestCompletedXid is present in the ProcArray, which is essential for
     * correct OldestXmin tracking; see src/backend/access/transam/README.
     *
     * XXX by storing xid into MyPgXact without acquiring ProcArrayLock, we
     * are relying on fetch/store of an xid to be atomic, else other backends
     * might see a partially-set xid here.  But holding both locks at once
     * would be a nasty concurrency hit.  So for now, assume atomicity.
     *
     * Note that readers of PGXACT xid fields should be careful to fetch the
     * value only once, rather than assume they can read a value multiple
     * times and get the same answer each time.
     *
     * The same comments apply to the subxact xid count and overflow fields.
     *
     * A solution to the atomic-store problem would be to give each PGXACT its
     * own spinlock used only for fetching/storing that PGXACT's xid and
     * related fields.
     *
     * If there's no room to fit a subtransaction XID into PGPROC, set the
     * cache-overflowed flag instead.  This forces readers to look in
     * pg_subtrans to map subtransaction XIDs up to top-level XIDs. There is a
     * race-condition window, in that the new XID will not appear as running
     * until its parent link has been placed into pg_subtrans. However, that
     * will happen before anyone could possibly have a reason to inquire about
     * the status of the XID, so it seems OK.  (Snapshots taken during this
     * window *will* include the parent XID, so they will deliver the correct
     * answer later on when someone does have a reason to inquire.)
     */
    {
        /*
         * Use volatile pointer to prevent code rearrangement; other backends
         * could be examining my subxids info concurrently, and we don't want
         * them to see an invalid intermediate state, such as incrementing
         * nxids before filling the array entry.  Note we are assuming that
         * TransactionId and int fetch/store are atomic.
         */
        volatile PGPROC *myproc = MyProc;
        volatile PGXACT *mypgxact = MyPgXact;

        if (!isSubXact)
            mypgxact->xid = xid;
        else
        {
            int         nxids = mypgxact->nxids;

            if (nxids < PGPROC_MAX_CACHED_SUBXIDS)
            {
                myproc->subxids.xids[nxids] = xid;
                mypgxact->nxids = nxids + 1;
            }
            else
                mypgxact->overflowed = true;
        }
    }

    LWLockRelease(XidGenLock);

    return xid;
}

TransactionId ReadNewTransactionId ( void   ) 
void SetTransactionIdLimit ( TransactionId  oldest_datfrozenxid,
Oid  oldest_datoid 
)

Definition at line 257 of file varsup.c.

References Assert, autovacuum_freeze_max_age, DEBUG1, ereport, errhint(), errmsg(), FirstNormalTransactionId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxTransactionId, VariableCacheData::nextXid, VariableCacheData::oldestXid, VariableCacheData::oldestXidDB, PMSIGNAL_START_AUTOVAC_LAUNCHER, SendPostmasterSignal(), TransactionIdFollowsOrEquals(), TransactionIdIsNormal, WARNING, XidGenLock, VariableCacheData::xidStopLimit, VariableCacheData::xidVacLimit, VariableCacheData::xidWarnLimit, and VariableCacheData::xidWrapLimit.

Referenced by BootStrapXLOG(), StartupXLOG(), vac_truncate_clog(), and xlog_redo().

{
    TransactionId xidVacLimit;
    TransactionId xidWarnLimit;
    TransactionId xidStopLimit;
    TransactionId xidWrapLimit;
    TransactionId curXid;

    Assert(TransactionIdIsNormal(oldest_datfrozenxid));

    /*
     * The place where we actually get into deep trouble is halfway around
     * from the oldest potentially-existing XID.  (This calculation is
     * probably off by one or two counts, because the special XIDs reduce the
     * size of the loop a little bit.  But we throw in plenty of slop below,
     * so it doesn't matter.)
     */
    xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
    if (xidWrapLimit < FirstNormalTransactionId)
        xidWrapLimit += FirstNormalTransactionId;

    /*
     * We'll refuse to continue assigning XIDs in interactive mode once we get
     * within 1M transactions of data loss.  This leaves lots of room for the
     * DBA to fool around fixing things in a standalone backend, while not
     * being significant compared to total XID space. (Note that since
     * vacuuming requires one transaction per table cleaned, we had better be
     * sure there's lots of XIDs left...)
     */
    xidStopLimit = xidWrapLimit - 1000000;
    if (xidStopLimit < FirstNormalTransactionId)
        xidStopLimit -= FirstNormalTransactionId;

    /*
     * We'll start complaining loudly when we get within 10M transactions of
     * the stop point.  This is kind of arbitrary, but if you let your gas
     * gauge get down to 1% of full, would you be looking for the next gas
     * station?  We need to be fairly liberal about this number because there
     * are lots of scenarios where most transactions are done by automatic
     * clients that won't pay attention to warnings. (No, we're not gonna make
     * this configurable.  If you know enough to configure it, you know enough
     * to not get in this kind of trouble in the first place.)
     */
    xidWarnLimit = xidStopLimit - 10000000;
    if (xidWarnLimit < FirstNormalTransactionId)
        xidWarnLimit -= FirstNormalTransactionId;

    /*
     * We'll start trying to force autovacuums when oldest_datfrozenxid gets
     * to be more than autovacuum_freeze_max_age transactions old.
     *
     * Note: guc.c ensures that autovacuum_freeze_max_age is in a sane range,
     * so that xidVacLimit will be well before xidWarnLimit.
     *
     * Note: autovacuum_freeze_max_age is a PGC_POSTMASTER parameter so that
     * we don't have to worry about dealing with on-the-fly changes in its
     * value.  It doesn't look practical to update shared state from a GUC
     * assign hook (too many processes would try to execute the hook,
     * resulting in race conditions as well as crashes of those not connected
     * to shared memory).  Perhaps this can be improved someday.
     */
    xidVacLimit = oldest_datfrozenxid + autovacuum_freeze_max_age;
    if (xidVacLimit < FirstNormalTransactionId)
        xidVacLimit += FirstNormalTransactionId;

    /* Grab lock for just long enough to set the new limit values */
    LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
    ShmemVariableCache->oldestXid = oldest_datfrozenxid;
    ShmemVariableCache->xidVacLimit = xidVacLimit;
    ShmemVariableCache->xidWarnLimit = xidWarnLimit;
    ShmemVariableCache->xidStopLimit = xidStopLimit;
    ShmemVariableCache->xidWrapLimit = xidWrapLimit;
    ShmemVariableCache->oldestXidDB = oldest_datoid;
    curXid = ShmemVariableCache->nextXid;
    LWLockRelease(XidGenLock);

    /* Log the info */
    ereport(DEBUG1,
            (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
     * request.  The reason for this is that autovac only processes one
     * database per invocation.  Once it's finished cleaning up the oldest
     * database, it'll call here, and we'll signal the postmaster to start
     * another iteration immediately if there are still any old databases.
     */
    if (TransactionIdFollowsOrEquals(curXid, xidVacLimit) &&
        IsUnderPostmaster && !InRecovery)
        SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);

    /* Give an immediate warning if past the wrap warn point */
    if (TransactionIdFollowsOrEquals(curXid, xidWarnLimit) && !InRecovery)
    {
        char       *oldest_datname;

        /*
         * We can be called when not inside a transaction, for example during
         * StartupXLOG().  In such a case we cannot do database access, so we
         * must just report the oldest DB's OID.
         *
         * Note: it's also 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 (IsTransactionState())
            oldest_datname = get_database_name(oldest_datoid);
        else
            oldest_datname = NULL;

        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.")));
    }
}

void TransactionIdAbort ( TransactionId  transactionId  ) 
void TransactionIdAbortTree ( TransactionId  xid,
int  nxids,
TransactionId xids 
)
void TransactionIdAsyncCommitTree ( TransactionId  xid,
int  nxids,
TransactionId xids,
XLogRecPtr  lsn 
)
void TransactionIdCommitTree ( TransactionId  xid,
int  nxids,
TransactionId xids 
)
bool TransactionIdDidAbort ( TransactionId  transactionId  ) 

Definition at line 181 of file transam.c.

References elog, SubTransGetParent(), TRANSACTION_STATUS_ABORTED, TRANSACTION_STATUS_SUB_COMMITTED, TransactionIdDidAbort(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionLogFetch(), TransactionXmin, and WARNING.

Referenced by asyncQueueProcessPageEntries(), compute_new_xmax_infomask(), heap_lock_updated_tuple_rec(), heap_update(), MultiXactIdGetUpdateXid(), ProcArrayApplyRecoveryInfo(), RecoverPreparedTransactions(), StandbyAcquireAccessExclusiveLock(), StandbyRecoverPreparedTransactions(), TransactionIdDidAbort(), and TransactionIdIsInProgress().

{
    XidStatus   xidstatus;

    xidstatus = TransactionLogFetch(transactionId);

    /*
     * If it's marked aborted, it's aborted.
     */
    if (xidstatus == TRANSACTION_STATUS_ABORTED)
        return true;

    /*
     * If it's marked subcommitted, we have to check the parent recursively.
     * However, if it's older than TransactionXmin, we can't look at
     * pg_subtrans; instead assume that the parent crashed without cleaning up
     * its children.
     */
    if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
    {
        TransactionId parentXid;

        if (TransactionIdPrecedes(transactionId, TransactionXmin))
            return true;
        parentXid = SubTransGetParent(transactionId);
        if (!TransactionIdIsValid(parentXid))
        {
            /* see notes in TransactionIdDidCommit */
            elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
                 transactionId);
            return true;
        }
        return TransactionIdDidAbort(parentXid);
    }

    /*
     * It's not aborted.
     */
    return false;
}

bool TransactionIdDidCommit ( TransactionId  transactionId  ) 

Definition at line 125 of file transam.c.

References elog, SubTransGetParent(), TRANSACTION_STATUS_COMMITTED, TRANSACTION_STATUS_SUB_COMMITTED, TransactionIdDidCommit(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionLogFetch(), TransactionXmin, and WARNING.

Referenced by asyncQueueProcessPageEntries(), compute_new_xmax_infomask(), heap_lock_updated_tuple_rec(), HeapTupleHeaderAdvanceLatestRemovedXid(), HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesNow(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuum(), MultiXactIdExpand(), ProcArrayApplyRecoveryInfo(), RecordTransactionAbort(), RecordTransactionAbortPrepared(), RecoverPreparedTransactions(), StandbyAcquireAccessExclusiveLock(), StandbyRecoverPreparedTransactions(), TransactionIdDidCommit(), and UpdateXmaxHintBits().

{
    XidStatus   xidstatus;

    xidstatus = TransactionLogFetch(transactionId);

    /*
     * If it's marked committed, it's committed.
     */
    if (xidstatus == TRANSACTION_STATUS_COMMITTED)
        return true;

    /*
     * If it's marked subcommitted, we have to check the parent recursively.
     * However, if it's older than TransactionXmin, we can't look at
     * pg_subtrans; instead assume that the parent crashed without cleaning up
     * its children.
     *
     * Originally we Assert'ed that the result of SubTransGetParent was not
     * zero. However with the introduction of prepared transactions, there can
     * be a window just after database startup where we do not have complete
     * knowledge in pg_subtrans of the transactions after TransactionXmin.
     * StartupSUBTRANS() has ensured that any missing information will be
     * zeroed.  Since this case should not happen under normal conditions, it
     * seems reasonable to emit a WARNING for it.
     */
    if (xidstatus == TRANSACTION_STATUS_SUB_COMMITTED)
    {
        TransactionId parentXid;

        if (TransactionIdPrecedes(transactionId, TransactionXmin))
            return false;
        parentXid = SubTransGetParent(transactionId);
        if (!TransactionIdIsValid(parentXid))
        {
            elog(WARNING, "no pg_subtrans entry for subcommitted XID %u",
                 transactionId);
            return false;
        }
        return TransactionIdDidCommit(parentXid);
    }

    /*
     * It's not committed.
     */
    return false;
}

bool TransactionIdFollows ( TransactionId  id1,
TransactionId  id2 
)
bool TransactionIdFollowsOrEquals ( TransactionId  id1,
TransactionId  id2 
)
XLogRecPtr TransactionIdGetCommitLSN ( TransactionId  xid  ) 

Definition at line 402 of file transam.c.

References cachedCommitLSN, cachedFetchXid, TransactionIdEquals, TransactionIdGetStatus(), and TransactionIdIsNormal.

Referenced by SetHintBits().

{
    XLogRecPtr  result;

    /*
     * Currently, all uses of this function are for xids that were just
     * reported to be committed by TransactionLogFetch, so we expect that
     * checking TransactionLogFetch's cache will usually succeed and avoid an
     * extra trip to shared memory.
     */
    if (TransactionIdEquals(xid, cachedFetchXid))
        return cachedCommitLSN;

    /* Special XIDs are always known committed */
    if (!TransactionIdIsNormal(xid))
        return InvalidXLogRecPtr;

    /*
     * Get the transaction status.
     */
    (void) TransactionIdGetStatus(xid, &result);

    return result;
}

bool TransactionIdIsKnownCompleted ( TransactionId  transactionId  ) 

Definition at line 238 of file transam.c.

References cachedFetchXid, and TransactionIdEquals.

Referenced by TransactionIdIsInProgress().

{
    if (TransactionIdEquals(transactionId, cachedFetchXid))
    {
        /* If it's in the cache at all, it must be completed. */
        return true;
    }

    return false;
}

TransactionId TransactionIdLatest ( TransactionId  mainxid,
int  nxids,
const TransactionId xids 
)

Definition at line 365 of file transam.c.

References TransactionIdPrecedes().

Referenced by FinishPreparedTransaction(), ProcArrayApplyXidAssignment(), RecordTransactionAbort(), RecordTransactionCommit(), xact_redo_abort(), and xact_redo_commit_internal().

{
    TransactionId result;

    /*
     * In practice it is highly likely that the xids[] array is sorted, and so
     * we could save some cycles by just taking the last child XID, but this
     * probably isn't so performance-critical that it's worth depending on
     * that assumption.  But just to show we're not totally stupid, scan the
     * array back-to-front to avoid useless assignments.
     */
    result = mainxid;
    while (--nxids >= 0)
    {
        if (TransactionIdPrecedes(result, xids[nxids]))
            result = xids[nxids];
    }
    return result;
}

bool TransactionIdPrecedes ( TransactionId  id1,
TransactionId  id2 
)

Definition at line 300 of file transam.c.

References TransactionIdIsNormal.

Referenced by _bt_page_recyclable(), CheckForSerializableConflictOut(), CheckTargetForConflictsIn(), CLOGPagePrecedes(), convert_xid(), copy_heap_data(), do_start_worker(), ExpireTreeKnownAssignedTransactionIds(), ExportSnapshot(), get_relation_info(), GetOldestActiveTransactionId(), GetOldestXmin(), GetRunningTransactionData(), GetSnapshotData(), heap_freeze_tuple(), heap_page_is_all_visible(), heap_prune_record_prunable(), heap_tuple_needs_freeze(), HeapTupleHeaderAdvanceLatestRemovedXid(), HeapTupleIsSurelyDead(), HeapTupleSatisfiesVacuum(), KnownAssignedXidsAdd(), KnownAssignedXidsGetAndSetXmin(), KnownAssignedXidsSearch(), lazy_scan_heap(), multixact_redo(), OldSerXidAdd(), OldSerXidGetMinConflictCommitSeqNo(), OldSerXidSetActiveSerXmin(), PrescanPreparedTransactions(), ProcArrayApplyRecoveryInfo(), ProcArrayApplyXidAssignment(), ProcArrayEndTransaction(), ProcArrayRemove(), relation_needs_vacanalyze(), rewrite_heap_tuple(), SetNewSxactGlobalXmin(), SubTransGetTopmostTransaction(), SubTransPagePrecedes(), TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsActive(), TransactionIdIsCurrentTransactionId(), TransactionIdIsInProgress(), TransactionIdLatest(), vac_truncate_clog(), vac_update_datfrozenxid(), vac_update_relstats(), vacuum_set_xid_limits(), vacuumRedirectAndPlaceholder(), XidCacheRemoveRunningXids(), XidInMVCCSnapshot(), XidIsConcurrent(), and xlog_redo().

{
    /*
     * If either ID is a permanent XID then we can just do unsigned
     * comparison.  If both are normal, do a modulo-2^31 comparison.
     */
    int32       diff;

    if (!TransactionIdIsNormal(id1) || !TransactionIdIsNormal(id2))
        return (id1 < id2);

    diff = (int32) (id1 - id2);
    return (diff < 0);
}

bool TransactionIdPrecedesOrEquals ( TransactionId  id1,
TransactionId  id2 
)
bool TransactionStartedDuringRecovery ( void   ) 

Definition at line 749 of file xact.c.

References TransactionStateData::startedInRecovery.

Referenced by RelationGetIndexScan().


Variable Documentation