Header And Logo

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

Functions

procarray.h File Reference

#include "storage/standby.h"
#include "utils/snapshot.h"
Include dependency graph for procarray.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

Size ProcArrayShmemSize (void)
void CreateSharedProcArray (void)
void ProcArrayAdd (PGPROC *proc)
void ProcArrayRemove (PGPROC *proc, TransactionId latestXid)
void ProcArrayEndTransaction (PGPROC *proc, TransactionId latestXid)
void ProcArrayClearTransaction (PGPROC *proc)
void ProcArrayApplyRecoveryInfo (RunningTransactions running)
void ProcArrayApplyXidAssignment (TransactionId topxid, int nsubxids, TransactionId *subxids)
void RecordKnownAssignedTransactionIds (TransactionId xid)
void ExpireTreeKnownAssignedTransactionIds (TransactionId xid, int nsubxids, TransactionId *subxids, TransactionId max_xid)
void ExpireAllKnownAssignedTransactionIds (void)
void ExpireOldKnownAssignedTransactionIds (TransactionId xid)
int GetMaxSnapshotXidCount (void)
int GetMaxSnapshotSubxidCount (void)
Snapshot GetSnapshotData (Snapshot snapshot)
bool ProcArrayInstallImportedXmin (TransactionId xmin, TransactionId sourcexid)
RunningTransactions GetRunningTransactionData (void)
bool TransactionIdIsInProgress (TransactionId xid)
bool TransactionIdIsActive (TransactionId xid)
TransactionId GetOldestXmin (bool allDbs, bool ignoreVacuum)
TransactionId GetOldestActiveTransactionId (void)
VirtualTransactionIdGetVirtualXIDsDelayingChkpt (int *nvxids)
bool HaveVirtualXIDsDelayingChkpt (VirtualTransactionId *vxids, int nvxids)
PGPROCBackendPidGetProc (int pid)
int BackendXidGetPid (TransactionId xid)
bool IsBackendPid (int pid)
VirtualTransactionIdGetCurrentVirtualXIDs (TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
VirtualTransactionIdGetConflictingVirtualXIDs (TransactionId limitXmin, Oid dbOid)
pid_t CancelVirtualTransaction (VirtualTransactionId vxid, ProcSignalReason sigmode)
bool MinimumActiveBackends (int min)
int CountDBBackends (Oid databaseid)
void CancelDBBackends (Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
int CountUserBackends (Oid roleid)
bool CountOtherDBBackends (Oid databaseId, int *nbackends, int *nprepared)
void XidCacheRemoveRunningXids (TransactionId xid, int nxids, const TransactionId *xids, TransactionId latestXid)

Function Documentation

PGPROC* BackendPidGetProc ( int  pid  ) 

Definition at line 1893 of file procarray.c.

References LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, and ProcArrayLock.

Referenced by IsBackendPid(), pg_signal_backend(), and ProcSendSignal().

{
    PGPROC     *result = NULL;
    ProcArrayStruct *arrayP = procArray;
    int         index;

    if (pid == 0)               /* never match dummy PGPROCs */
        return NULL;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        PGPROC     *proc = &allProcs[arrayP->pgprocnos[index]];

        if (proc->pid == pid)
        {
            result = proc;
            break;
        }
    }

    LWLockRelease(ProcArrayLock);

    return result;
}

int BackendXidGetPid ( TransactionId  xid  ) 

Definition at line 1934 of file procarray.c.

References InvalidTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, and PGXACT::xid.

Referenced by pgrowlocks().

{
    int         result = 0;
    ProcArrayStruct *arrayP = procArray;
    int         index;

    if (xid == InvalidTransactionId)    /* never match invalid xid */
        return 0;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];

        if (pgxact->xid == xid)
        {
            result = proc->pid;
            break;
        }
    }

    LWLockRelease(ProcArrayLock);

    return result;
}

void CancelDBBackends ( Oid  databaseid,
ProcSignalReason  sigmode,
bool  conflictPending 
)

Definition at line 2294 of file procarray.c.

References VirtualTransactionId::backendId, PGPROC::databaseId, GET_VXID_FROM_PGPROC, InvalidOid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, PGPROC::recoveryConflictPending, and SendProcSignal().

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

{
    ProcArrayStruct *arrayP = procArray;
    int         index;
    pid_t       pid = 0;

    /* tell all backends to die */
    LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];

        if (databaseid == InvalidOid || proc->databaseId == databaseid)
        {
            VirtualTransactionId procvxid;

            GET_VXID_FROM_PGPROC(procvxid, *proc);

            proc->recoveryConflictPending = conflictPending;
            pid = proc->pid;
            if (pid != 0)
            {
                /*
                 * Kill the pid if it's still here. If not, that's what we
                 * wanted so ignore any errors.
                 */
                (void) SendProcSignal(pid, sigmode, procvxid.backendId);
            }
        }
    }

    LWLockRelease(ProcArrayLock);
}

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 2162 of file procarray.c.

References VirtualTransactionId::backendId, GET_VXID_FROM_PGPROC, VirtualTransactionId::localTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, PGPROC::recoveryConflictPending, and SendProcSignal().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

{
    ProcArrayStruct *arrayP = procArray;
    int         index;
    pid_t       pid = 0;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        VirtualTransactionId procvxid;

        GET_VXID_FROM_PGPROC(procvxid, *proc);

        if (procvxid.backendId == vxid.backendId &&
            procvxid.localTransactionId == vxid.localTransactionId)
        {
            proc->recoveryConflictPending = true;
            pid = proc->pid;
            if (pid != 0)
            {
                /*
                 * Kill the pid if it's still here. If not, that's what we
                 * wanted so ignore any errors.
                 */
                (void) SendProcSignal(pid, sigmode, vxid.backendId);
            }
            break;
        }
    }

    LWLockRelease(ProcArrayLock);

    return pid;
}

int CountDBBackends ( Oid  databaseid  ) 

Definition at line 2265 of file procarray.c.

References PGPROC::databaseId, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, OidIsValid, ProcArrayStruct::pgprocnos, PGPROC::pid, and ProcArrayLock.

Referenced by btree_xlog_delete_get_latestRemovedXid(), CheckMyDatabase(), and ResolveRecoveryConflictWithDatabase().

{
    ProcArrayStruct *arrayP = procArray;
    int         count = 0;
    int         index;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];

        if (proc->pid == 0)
            continue;           /* do not count prepared xacts */
        if (!OidIsValid(databaseid) ||
            proc->databaseId == databaseid)
            count++;
    }

    LWLockRelease(ProcArrayLock);

    return count;
}

bool CountOtherDBBackends ( Oid  databaseId,
int *  nbackends,
int *  nprepared 
)

Definition at line 2382 of file procarray.c.

References CHECK_FOR_INTERRUPTS, PGPROC::databaseId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MAXAUTOVACPIDS, MyProc, ProcArrayStruct::numProcs, pg_usleep(), ProcArrayStruct::pgprocnos, PGPROC::pid, PROC_IS_AUTOVACUUM, ProcArrayLock, and PGXACT::vacuumFlags.

Referenced by createdb(), dropdb(), movedb(), and RenameDatabase().

{
    ProcArrayStruct *arrayP = procArray;

#define MAXAUTOVACPIDS  10      /* max autovacs to SIGTERM per iteration */
    int         autovac_pids[MAXAUTOVACPIDS];
    int         tries;

    /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
    for (tries = 0; tries < 50; tries++)
    {
        int         nautovacs = 0;
        bool        found = false;
        int         index;

        CHECK_FOR_INTERRUPTS();

        *nbackends = *nprepared = 0;

        LWLockAcquire(ProcArrayLock, LW_SHARED);

        for (index = 0; index < arrayP->numProcs; index++)
        {
            int         pgprocno = arrayP->pgprocnos[index];
            volatile PGPROC *proc = &allProcs[pgprocno];
            volatile PGXACT *pgxact = &allPgXact[pgprocno];

            if (proc->databaseId != databaseId)
                continue;
            if (proc == MyProc)
                continue;

            found = true;

            if (proc->pid == 0)
                (*nprepared)++;
            else
            {
                (*nbackends)++;
                if ((pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
                    nautovacs < MAXAUTOVACPIDS)
                    autovac_pids[nautovacs++] = proc->pid;
            }
        }

        LWLockRelease(ProcArrayLock);

        if (!found)
            return false;       /* no conflicting backends, so done */

        /*
         * Send SIGTERM to any conflicting autovacuums before sleeping. We
         * postpone this step until after the loop because we don't want to
         * hold ProcArrayLock while issuing kill(). We have no idea what might
         * block kill() inside the kernel...
         */
        for (index = 0; index < nautovacs; index++)
            (void) kill(autovac_pids[index], SIGTERM);  /* ignore any error */

        /* sleep, then try again */
        pg_usleep(100 * 1000L); /* 100ms */
    }

    return true;                /* timed out, still conflicts */
}

int CountUserBackends ( Oid  roleid  ) 

Definition at line 2334 of file procarray.c.

References LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, and PGPROC::roleId.

Referenced by InitializeSessionUserId().

{
    ProcArrayStruct *arrayP = procArray;
    int         count = 0;
    int         index;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];

        if (proc->pid == 0)
            continue;           /* do not count prepared xacts */
        if (proc->roleId == roleid)
            count++;
    }

    LWLockRelease(ProcArrayLock);

    return count;
}

void CreateSharedProcArray ( void   ) 

Definition at line 212 of file procarray.c.

References add_size(), PROC_HDR::allPgXact, PROC_HDR::allProcs, EnableHotStandby, ProcArrayStruct::headKnownAssignedXids, ProcArrayStruct::known_assigned_xids_lck, KnownAssignedXids, KnownAssignedXidsValid, ProcArrayStruct::lastOverflowedXid, ProcArrayStruct::maxKnownAssignedXids, ProcArrayStruct::maxProcs, mul_size(), ProcArrayStruct::numKnownAssignedXids, ProcArrayStruct::numProcs, offsetof, PROCARRAY_MAXPROCS, ProcGlobal, ShmemInitStruct(), SpinLockInit, ProcArrayStruct::tailKnownAssignedXids, and TOTAL_MAX_CACHED_SUBXIDS.

Referenced by CreateSharedMemoryAndSemaphores().

{
    bool        found;

    /* Create or attach to the ProcArray shared structure */
    procArray = (ProcArrayStruct *)
        ShmemInitStruct("Proc Array",
                        add_size(offsetof(ProcArrayStruct, pgprocnos),
                                 mul_size(sizeof(int),
                                          PROCARRAY_MAXPROCS)),
                        &found);

    if (!found)
    {
        /*
         * We're the first - initialize.
         */
        procArray->numProcs = 0;
        procArray->maxProcs = PROCARRAY_MAXPROCS;
        procArray->maxKnownAssignedXids = TOTAL_MAX_CACHED_SUBXIDS;
        procArray->numKnownAssignedXids = 0;
        procArray->tailKnownAssignedXids = 0;
        procArray->headKnownAssignedXids = 0;
        SpinLockInit(&procArray->known_assigned_xids_lck);
        procArray->lastOverflowedXid = InvalidTransactionId;
    }

    allProcs = ProcGlobal->allProcs;
    allPgXact = ProcGlobal->allPgXact;

    /* Create or attach to the KnownAssignedXids arrays too, if needed */
    if (EnableHotStandby)
    {
        KnownAssignedXids = (TransactionId *)
            ShmemInitStruct("KnownAssignedXids",
                            mul_size(sizeof(TransactionId),
                                     TOTAL_MAX_CACHED_SUBXIDS),
                            &found);
        KnownAssignedXidsValid = (bool *)
            ShmemInitStruct("KnownAssignedXidsValid",
                            mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
                            &found);
    }
}

void ExpireAllKnownAssignedTransactionIds ( void   ) 
void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid  ) 
void ExpireTreeKnownAssignedTransactionIds ( TransactionId  xid,
int  nsubxids,
TransactionId subxids,
TransactionId  max_xid 
)
VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 2090 of file procarray.c.

References VirtualTransactionId::backendId, PGPROC::databaseId, ereport, errcode(), errmsg(), ERROR, GET_VXID_FROM_PGPROC, VirtualTransactionId::localTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, ProcArrayStruct::maxProcs, NULL, ProcArrayStruct::numProcs, OidIsValid, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, TransactionIdFollows(), TransactionIdIsValid, VirtualTransactionIdIsValid, and PGXACT::xmin.

Referenced by ResolveRecoveryConflictWithLock(), ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

{
    static VirtualTransactionId *vxids;
    ProcArrayStruct *arrayP = procArray;
    int         count = 0;
    int         index;

    /*
     * If first time through, get workspace to remember main XIDs in. We
     * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
     * result space, remembering room for a terminator.
     */
    if (vxids == NULL)
    {
        vxids = (VirtualTransactionId *)
            malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
        if (vxids == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
    }

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];

        /* Exclude prepared transactions */
        if (proc->pid == 0)
            continue;

        if (!OidIsValid(dbOid) ||
            proc->databaseId == dbOid)
        {
            /* Fetch xmin just once - can't change on us, but good coding */
            TransactionId pxmin = pgxact->xmin;

            /*
             * We ignore an invalid pxmin because this means that backend has
             * no snapshot and cannot get another one while we hold exclusive
             * lock.
             */
            if (!TransactionIdIsValid(limitXmin) ||
                (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
            {
                VirtualTransactionId vxid;

                GET_VXID_FROM_PGPROC(vxid, *proc);
                if (VirtualTransactionIdIsValid(vxid))
                    vxids[count++] = vxid;
            }
        }
    }

    LWLockRelease(ProcArrayLock);

    /* add the terminator */
    vxids[count].backendId = InvalidBackendId;
    vxids[count].localTransactionId = InvalidLocalTransactionId;

    return vxids;
}

VirtualTransactionId* GetCurrentVirtualXIDs ( TransactionId  limitXmin,
bool  excludeXmin0,
bool  allDbs,
int  excludeVacuum,
int *  nvxids 
)

Definition at line 2002 of file procarray.c.

References PGPROC::databaseId, GET_VXID_FROM_PGPROC, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::maxProcs, MyDatabaseId, MyProc, ProcArrayStruct::numProcs, palloc(), ProcArrayStruct::pgprocnos, ProcArrayLock, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), PGXACT::vacuumFlags, VirtualTransactionIdIsValid, and PGXACT::xmin.

Referenced by DefineIndex().

{
    VirtualTransactionId *vxids;
    ProcArrayStruct *arrayP = procArray;
    int         count = 0;
    int         index;

    /* allocate what's certainly enough result space */
    vxids = (VirtualTransactionId *)
        palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];

        if (proc == MyProc)
            continue;

        if (excludeVacuum & pgxact->vacuumFlags)
            continue;

        if (allDbs || proc->databaseId == MyDatabaseId)
        {
            /* Fetch xmin just once - might change on us */
            TransactionId pxmin = pgxact->xmin;

            if (excludeXmin0 && !TransactionIdIsValid(pxmin))
                continue;

            /*
             * InvalidTransactionId precedes all other XIDs, so a proc that
             * hasn't set xmin yet will not be rejected by this test.
             */
            if (!TransactionIdIsValid(limitXmin) ||
                TransactionIdPrecedesOrEquals(pxmin, limitXmin))
            {
                VirtualTransactionId vxid;

                GET_VXID_FROM_PGPROC(vxid, *proc);
                if (VirtualTransactionIdIsValid(vxid))
                    vxids[count++] = vxid;
            }
        }
    }

    LWLockRelease(ProcArrayLock);

    *nvxids = count;
    return vxids;
}

int GetMaxSnapshotSubxidCount ( void   ) 

Definition at line 1219 of file procarray.c.

Referenced by ExportSnapshot(), GetSnapshotData(), ImportSnapshot(), and SetTransactionSnapshot().

{
    return TOTAL_MAX_CACHED_SUBXIDS;
}

int GetMaxSnapshotXidCount ( void   ) 

Definition at line 1208 of file procarray.c.

References ProcArrayStruct::maxProcs.

Referenced by GetSnapshotData(), ImportSnapshot(), and SetTransactionSnapshot().

{
    return procArray->maxProcs;
}

TransactionId GetOldestActiveTransactionId ( void   ) 

Definition at line 1731 of file procarray.c.

References Assert, LW_SHARED, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextXid, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, ProcArrayLock, RecoveryInProgress(), ShmemVariableCache, TransactionIdIsNormal, TransactionIdPrecedes(), and PGXACT::xid.

Referenced by CreateCheckPoint().

{
    ProcArrayStruct *arrayP = procArray;
    TransactionId oldestRunningXid;
    int         index;

    Assert(!RecoveryInProgress());

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    /*
     * It's okay to read nextXid without acquiring XidGenLock because (1) we
     * assume TransactionIds can be read atomically and (2) we don't care if
     * we get a slightly stale value.  It can't be very stale anyway, because
     * the LWLockAcquire above will have done any necessary memory
     * interlocking.
     */
    oldestRunningXid = ShmemVariableCache->nextXid;

    /*
     * Spin over procArray collecting all xids and subxids.
     */
    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];
        TransactionId xid;

        /* Fetch xid just once - see GetNewTransactionId */
        xid = pgxact->xid;

        if (!TransactionIdIsNormal(xid))
            continue;

        if (TransactionIdPrecedes(xid, oldestRunningXid))
            oldestRunningXid = xid;

        /*
         * Top-level XID of a transaction is always less than any of its
         * subxids, so we don't need to check if any of the subxids are
         * smaller than oldestRunningXid
         */
    }

    LWLockRelease(ProcArrayLock);

    return oldestRunningXid;
}

TransactionId GetOldestXmin ( bool  allDbs,
bool  ignoreVacuum 
)

Definition at line 1103 of file procarray.c.

References Assert, PGPROC::databaseId, KnownAssignedXidsGetOldestXmin(), VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PROC_IN_VACUUM, ProcArrayLock, RecoveryInProgress(), ShmemVariableCache, TransactionIdAdvance, TransactionIdIsNormal, TransactionIdPrecedes(), vacuum_defer_cleanup_age, PGXACT::vacuumFlags, PGXACT::xid, and PGXACT::xmin.

Referenced by acquire_sample_rows(), CreateCheckPoint(), CreateRestartPoint(), IndexBuildHeapScan(), vac_update_datfrozenxid(), vacuum_set_xid_limits(), and XLogWalRcvSendHSFeedback().

{
    ProcArrayStruct *arrayP = procArray;
    TransactionId result;
    int         index;

    /* Cannot look for individual databases during recovery */
    Assert(allDbs || !RecoveryInProgress());

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    /*
     * We initialize the MIN() calculation with latestCompletedXid + 1. This
     * is a lower bound for the XIDs that might appear in the ProcArray later,
     * and so protects us against overestimating the result due to future
     * additions.
     */
    result = ShmemVariableCache->latestCompletedXid;
    Assert(TransactionIdIsNormal(result));
    TransactionIdAdvance(result);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];

        if (ignoreVacuum && (pgxact->vacuumFlags & PROC_IN_VACUUM))
            continue;

        if (allDbs ||
            proc->databaseId == MyDatabaseId ||
            proc->databaseId == 0)      /* always include WalSender */
        {
            /* Fetch xid just once - see GetNewTransactionId */
            TransactionId xid = pgxact->xid;

            /* First consider the transaction's own Xid, if any */
            if (TransactionIdIsNormal(xid) &&
                TransactionIdPrecedes(xid, result))
                result = xid;

            /*
             * Also consider the transaction's Xmin, if set.
             *
             * We must check both Xid and Xmin because a transaction might
             * have an Xmin but not (yet) an Xid; conversely, if it has an
             * Xid, that could determine some not-yet-set Xmin.
             */
            xid = pgxact->xmin; /* Fetch just once */
            if (TransactionIdIsNormal(xid) &&
                TransactionIdPrecedes(xid, result))
                result = xid;
        }
    }

    if (RecoveryInProgress())
    {
        /*
         * Check to see whether KnownAssignedXids contains an xid value older
         * than the main procarray.
         */
        TransactionId kaxmin = KnownAssignedXidsGetOldestXmin();

        LWLockRelease(ProcArrayLock);

        if (TransactionIdIsNormal(kaxmin) &&
            TransactionIdPrecedes(kaxmin, result))
            result = kaxmin;
    }
    else
    {
        /*
         * No other information needed, so release the lock immediately.
         */
        LWLockRelease(ProcArrayLock);

        /*
         * Compute the cutoff XID by subtracting vacuum_defer_cleanup_age,
         * being careful not to generate a "permanent" XID.
         *
         * vacuum_defer_cleanup_age provides some additional "slop" for the
         * benefit of hot standby queries on slave servers.  This is quick and
         * dirty, and perhaps not all that useful unless the master has a
         * predictable transaction rate, but it offers some protection when
         * there's no walsender connection.  Note that we are assuming
         * vacuum_defer_cleanup_age isn't large enough to cause wraparound ---
         * so guc.c should limit it to no more than the xidStopLimit threshold
         * in varsup.c.  Also note that we intentionally don't apply
         * vacuum_defer_cleanup_age on standby servers.
         */
        result -= vacuum_defer_cleanup_age;
        if (!TransactionIdIsNormal(result))
            result = FirstNormalTransactionId;
    }

    return result;
}

RunningTransactions GetRunningTransactionData ( void   ) 

Definition at line 1581 of file procarray.c.

References Assert, ereport, errcode(), errmsg(), ERROR, RunningTransactionsData::latestCompletedXid, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, RunningTransactionsData::nextXid, VariableCacheData::nextXid, NULL, ProcArrayStruct::numProcs, PGXACT::nxids, RunningTransactionsData::oldestRunningXid, PGXACT::overflowed, ProcArrayStruct::pgprocnos, ProcArrayLock, RecoveryInProgress(), ShmemVariableCache, RunningTransactionsData::subxcnt, RunningTransactionsData::subxid_overflow, PGPROC::subxids, TOTAL_MAX_CACHED_SUBXIDS, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), RunningTransactionsData::xcnt, PGXACT::xid, XidGenLock, XidCache::xids, and RunningTransactionsData::xids.

Referenced by LogStandbySnapshot().

{
    /* result workspace */
    static RunningTransactionsData CurrentRunningXactsData;

    ProcArrayStruct *arrayP = procArray;
    RunningTransactions CurrentRunningXacts = &CurrentRunningXactsData;
    TransactionId latestCompletedXid;
    TransactionId oldestRunningXid;
    TransactionId *xids;
    int         index;
    int         count;
    int         subcount;
    bool        suboverflowed;

    Assert(!RecoveryInProgress());

    /*
     * Allocating space for maxProcs xids is usually overkill; numProcs would
     * be sufficient.  But it seems better to do the malloc while not holding
     * the lock, so we can't look at numProcs.  Likewise, we allocate much
     * more subxip storage than is probably needed.
     *
     * Should only be allocated in bgwriter, since only ever executed during
     * checkpoints.
     */
    if (CurrentRunningXacts->xids == NULL)
    {
        /*
         * First call
         */
        CurrentRunningXacts->xids = (TransactionId *)
            malloc(TOTAL_MAX_CACHED_SUBXIDS * sizeof(TransactionId));
        if (CurrentRunningXacts->xids == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
    }

    xids = CurrentRunningXacts->xids;

    count = subcount = 0;
    suboverflowed = false;

    /*
     * Ensure that no xids enter or leave the procarray while we obtain
     * snapshot.
     */
    LWLockAcquire(ProcArrayLock, LW_SHARED);
    LWLockAcquire(XidGenLock, LW_SHARED);

    latestCompletedXid = ShmemVariableCache->latestCompletedXid;

    oldestRunningXid = ShmemVariableCache->nextXid;

    /*
     * Spin over procArray collecting all xids
     */
    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];
        TransactionId xid;

        /* Fetch xid just once - see GetNewTransactionId */
        xid = pgxact->xid;

        /*
         * We don't need to store transactions that don't have a TransactionId
         * yet because they will not show as running on a standby server.
         */
        if (!TransactionIdIsValid(xid))
            continue;

        xids[count++] = xid;

        if (TransactionIdPrecedes(xid, oldestRunningXid))
            oldestRunningXid = xid;

        if (pgxact->overflowed)
            suboverflowed = true;
    }

    /*
     * Spin over procArray collecting all subxids, but only if there hasn't
     * been a suboverflow.
     */
    if (!suboverflowed)
    {
        for (index = 0; index < arrayP->numProcs; index++)
        {
            int         pgprocno = arrayP->pgprocnos[index];
            volatile PGPROC *proc = &allProcs[pgprocno];
            volatile PGXACT *pgxact = &allPgXact[pgprocno];
            int         nxids;

            /*
             * Save subtransaction XIDs. Other backends can't add or remove
             * entries while we're holding XidGenLock.
             */
            nxids = pgxact->nxids;
            if (nxids > 0)
            {
                memcpy(&xids[count], (void *) proc->subxids.xids,
                       nxids * sizeof(TransactionId));
                count += nxids;
                subcount += nxids;

                /*
                 * Top-level XID of a transaction is always less than any of
                 * its subxids, so we don't need to check if any of the subxids
                 * are smaller than oldestRunningXid
                 */
            }
        }
    }

    CurrentRunningXacts->xcnt = count - subcount;
    CurrentRunningXacts->subxcnt = subcount;
    CurrentRunningXacts->subxid_overflow = suboverflowed;
    CurrentRunningXacts->nextXid = ShmemVariableCache->nextXid;
    CurrentRunningXacts->oldestRunningXid = oldestRunningXid;
    CurrentRunningXacts->latestCompletedXid = latestCompletedXid;

    /* We don't release XidGenLock here, the caller is responsible for that */
    LWLockRelease(ProcArrayLock);

    Assert(TransactionIdIsValid(CurrentRunningXacts->nextXid));
    Assert(TransactionIdIsValid(CurrentRunningXacts->oldestRunningXid));
    Assert(TransactionIdIsNormal(CurrentRunningXacts->latestCompletedXid));

    return CurrentRunningXacts;
}

Snapshot GetSnapshotData ( Snapshot  snapshot  ) 

Definition at line 1258 of file procarray.c.

References SnapshotData::active_count, Assert, SnapshotData::copied, SnapshotData::curcid, ereport, errcode(), errmsg(), ERROR, GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, MyPgXact, NormalTransactionIdPrecedes, NULL, ProcArrayStruct::numProcs, PGXACT::nxids, PGXACT::overflowed, ProcArrayStruct::pgprocnos, PROC_IN_VACUUM, ProcArrayLock, RecentGlobalXmin, RecentXmin, RecoveryInProgress(), SnapshotData::regd_count, ShmemVariableCache, SnapshotData::suboverflowed, SnapshotData::subxcnt, PGPROC::subxids, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdAdvance, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdPrecedesOrEquals(), TransactionXmin, vacuum_defer_cleanup_age, PGXACT::vacuumFlags, SnapshotData::xcnt, PGXACT::xid, XidCache::xids, SnapshotData::xip, SnapshotData::xmax, SnapshotData::xmin, and PGXACT::xmin.

Referenced by GetLatestSnapshot(), GetSerializableTransactionSnapshotInt(), GetTransactionSnapshot(), and SetTransactionSnapshot().

{
    ProcArrayStruct *arrayP = procArray;
    TransactionId xmin;
    TransactionId xmax;
    TransactionId globalxmin;
    int         index;
    int         count = 0;
    int         subcount = 0;
    bool        suboverflowed = false;

    Assert(snapshot != NULL);

    /*
     * Allocating space for maxProcs xids is usually overkill; numProcs would
     * be sufficient.  But it seems better to do the malloc while not holding
     * the lock, so we can't look at numProcs.  Likewise, we allocate much
     * more subxip storage than is probably needed.
     *
     * This does open a possibility for avoiding repeated malloc/free: since
     * maxProcs does not change at runtime, we can simply reuse the previous
     * xip arrays if any.  (This relies on the fact that all callers pass
     * static SnapshotData structs.)
     */
    if (snapshot->xip == NULL)
    {
        /*
         * First call for this snapshot. Snapshot is same size whether or not
         * we are in recovery, see later comments.
         */
        snapshot->xip = (TransactionId *)
            malloc(GetMaxSnapshotXidCount() * sizeof(TransactionId));
        if (snapshot->xip == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
        Assert(snapshot->subxip == NULL);
        snapshot->subxip = (TransactionId *)
            malloc(GetMaxSnapshotSubxidCount() * sizeof(TransactionId));
        if (snapshot->subxip == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
    }

    /*
     * It is sufficient to get shared lock on ProcArrayLock, even if we are
     * going to set MyPgXact->xmin.
     */
    LWLockAcquire(ProcArrayLock, LW_SHARED);

    /* xmax is always latestCompletedXid + 1 */
    xmax = ShmemVariableCache->latestCompletedXid;
    Assert(TransactionIdIsNormal(xmax));
    TransactionIdAdvance(xmax);

    /* initialize xmin calculation with xmax */
    globalxmin = xmin = xmax;

    snapshot->takenDuringRecovery = RecoveryInProgress();

    if (!snapshot->takenDuringRecovery)
    {
        int        *pgprocnos = arrayP->pgprocnos;
        int         numProcs;

        /*
         * Spin over procArray checking xid, xmin, and subxids.  The goal is
         * to gather all active xids, find the lowest xmin, and try to record
         * subxids.
         */
        numProcs = arrayP->numProcs;
        for (index = 0; index < numProcs; index++)
        {
            int         pgprocno = pgprocnos[index];
            volatile PGXACT *pgxact = &allPgXact[pgprocno];
            TransactionId xid;

            /* Ignore procs running LAZY VACUUM */
            if (pgxact->vacuumFlags & PROC_IN_VACUUM)
                continue;

            /* Update globalxmin to be the smallest valid xmin */
            xid = pgxact->xmin; /* fetch just once */
            if (TransactionIdIsNormal(xid) &&
                NormalTransactionIdPrecedes(xid, globalxmin))
                globalxmin = xid;

            /* Fetch xid just once - see GetNewTransactionId */
            xid = pgxact->xid;

            /*
             * If the transaction has no XID assigned, we can skip it; it
             * won't have sub-XIDs either.  If the XID is >= xmax, we can also
             * skip it; such transactions will be treated as running anyway
             * (and any sub-XIDs will also be >= xmax).
             */
            if (!TransactionIdIsNormal(xid)
                || !NormalTransactionIdPrecedes(xid, xmax))
                continue;

            /*
             * We don't include our own XIDs (if any) in the snapshot, but we
             * must include them in xmin.
             */
            if (NormalTransactionIdPrecedes(xid, xmin))
                xmin = xid;
            if (pgxact == MyPgXact)
                continue;

            /* Add XID to snapshot. */
            snapshot->xip[count++] = xid;

            /*
             * Save subtransaction XIDs if possible (if we've already
             * overflowed, there's no point).  Note that the subxact XIDs must
             * be later than their parent, so no need to check them against
             * xmin.  We could filter against xmax, but it seems better not to
             * do that much work while holding the ProcArrayLock.
             *
             * The other backend can add more subxids concurrently, but cannot
             * remove any.  Hence it's important to fetch nxids just once.
             * Should be safe to use memcpy, though.  (We needn't worry about
             * missing any xids added concurrently, because they must postdate
             * xmax.)
             *
             * Again, our own XIDs are not included in the snapshot.
             */
            if (!suboverflowed)
            {
                if (pgxact->overflowed)
                    suboverflowed = true;
                else
                {
                    int         nxids = pgxact->nxids;

                    if (nxids > 0)
                    {
                        volatile PGPROC *proc = &allProcs[pgprocno];

                        memcpy(snapshot->subxip + subcount,
                               (void *) proc->subxids.xids,
                               nxids * sizeof(TransactionId));
                        subcount += nxids;
                    }
                }
            }
        }
    }
    else
    {
        /*
         * We're in hot standby, so get XIDs from KnownAssignedXids.
         *
         * We store all xids directly into subxip[]. Here's why:
         *
         * In recovery we don't know which xids are top-level and which are
         * subxacts, a design choice that greatly simplifies xid processing.
         *
         * It seems like we would want to try to put xids into xip[] only, but
         * that is fairly small. We would either need to make that bigger or
         * to increase the rate at which we WAL-log xid assignment; neither is
         * an appealing choice.
         *
         * We could try to store xids into xip[] first and then into subxip[]
         * if there are too many xids. That only works if the snapshot doesn't
         * overflow because we do not search subxip[] in that case. A simpler
         * way is to just store all xids in the subxact array because this is
         * by far the bigger array. We just leave the xip array empty.
         *
         * Either way we need to change the way XidInMVCCSnapshot() works
         * depending upon when the snapshot was taken, or change normal
         * snapshot processing so it matches.
         *
         * Note: It is possible for recovery to end before we finish taking the
         * snapshot, and for newly assigned transaction ids to be added to the
         * ProcArray.  xmax cannot change while we hold ProcArrayLock, so those
         * newly added transaction ids would be filtered away, so we need not
         * be concerned about them.
         */
        subcount = KnownAssignedXidsGetAndSetXmin(snapshot->subxip, &xmin,
                                                  xmax);

        if (TransactionIdPrecedesOrEquals(xmin, procArray->lastOverflowedXid))
            suboverflowed = true;
    }

    if (!TransactionIdIsValid(MyPgXact->xmin))
        MyPgXact->xmin = TransactionXmin = xmin;
    LWLockRelease(ProcArrayLock);

    /*
     * Update globalxmin to include actual process xids.  This is a slightly
     * different way of computing it than GetOldestXmin uses, but should give
     * the same result.
     */
    if (TransactionIdPrecedes(xmin, globalxmin))
        globalxmin = xmin;

    /* Update global variables too */
    RecentGlobalXmin = globalxmin - vacuum_defer_cleanup_age;
    if (!TransactionIdIsNormal(RecentGlobalXmin))
        RecentGlobalXmin = FirstNormalTransactionId;
    RecentXmin = xmin;

    snapshot->xmin = xmin;
    snapshot->xmax = xmax;
    snapshot->xcnt = count;
    snapshot->subxcnt = subcount;
    snapshot->suboverflowed = suboverflowed;

    snapshot->curcid = GetCurrentCommandId(false);

    /*
     * This is a new snapshot, so set both refcounts are zero, and mark it as
     * not copied in persistent memory.
     */
    snapshot->active_count = 0;
    snapshot->regd_count = 0;
    snapshot->copied = false;

    return snapshot;
}

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids  ) 

Definition at line 1799 of file procarray.c.

References PGXACT::delayChkpt, GET_VXID_FROM_PGPROC, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::maxProcs, ProcArrayStruct::numProcs, palloc(), ProcArrayStruct::pgprocnos, ProcArrayLock, and VirtualTransactionIdIsValid.

Referenced by CreateCheckPoint().

{
    VirtualTransactionId *vxids;
    ProcArrayStruct *arrayP = procArray;
    int         count = 0;
    int         index;

    /* allocate what's certainly enough result space */
    vxids = (VirtualTransactionId *)
        palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int     pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC    *proc = &allProcs[pgprocno];
        volatile PGXACT    *pgxact = &allPgXact[pgprocno];

        if (pgxact->delayChkpt)
        {
            VirtualTransactionId vxid;

            GET_VXID_FROM_PGPROC(vxid, *proc);
            if (VirtualTransactionIdIsValid(vxid))
                vxids[count++] = vxid;
        }
    }

    LWLockRelease(ProcArrayLock);

    *nvxids = count;
    return vxids;
}

bool HaveVirtualXIDsDelayingChkpt ( VirtualTransactionId vxids,
int  nvxids 
)

Definition at line 1844 of file procarray.c.

References PGXACT::delayChkpt, GET_VXID_FROM_PGPROC, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, ProcArrayLock, VirtualTransactionIdEquals, and VirtualTransactionIdIsValid.

Referenced by CreateCheckPoint().

{
    bool        result = false;
    ProcArrayStruct *arrayP = procArray;
    int         index;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    while (VirtualTransactionIdIsValid(*vxids))
    {
        for (index = 0; index < arrayP->numProcs; index++)
        {
            int     pgprocno = arrayP->pgprocnos[index];
            volatile PGPROC    *proc = &allProcs[pgprocno];
            volatile PGXACT    *pgxact = &allPgXact[pgprocno];
            VirtualTransactionId vxid;

            GET_VXID_FROM_PGPROC(vxid, *proc);
            if (VirtualTransactionIdIsValid(vxid))
            {
                if (VirtualTransactionIdEquals(vxid, *vxids) &&
                    pgxact->delayChkpt)
                {
                    result = true;
                    break;
                }
            }
        }

        if (result)
            break;

        /* The virtual transaction is gone now, wait for the next one */
        vxids++;
    }

    LWLockRelease(ProcArrayLock);

    return result;
}

bool IsBackendPid ( int  pid  ) 

Definition at line 1969 of file procarray.c.

References BackendPidGetProc(), and NULL.

{
    return (BackendPidGetProc(pid) != NULL);
}

bool MinimumActiveBackends ( int  min  ) 

Definition at line 2210 of file procarray.c.

References InvalidTransactionId, MyProc, NULL, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, PGPROC::waitLock, and PGXACT::xid.

Referenced by XLogFlush().

{
    ProcArrayStruct *arrayP = procArray;
    int         count = 0;
    int         index;

    /* Quick short-circuit if no minimum is specified */
    if (min == 0)
        return true;

    /*
     * Note: for speed, we don't acquire ProcArrayLock.  This is a little bit
     * bogus, but since we are only testing fields for zero or nonzero, it
     * should be OK.  The result is only used for heuristic purposes anyway...
     */
    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];

        /*
         * Since we're not holding a lock, need to check that the pointer is
         * valid. Someone holding the lock could have incremented numProcs
         * already, but not yet inserted a valid pointer to the array.
         *
         * If someone just decremented numProcs, 'proc' could also point to a
         * PGPROC entry that's no longer in the array. It still points to a
         * PGPROC struct, though, because freed PGPROC entries just go to the
         * free list and are recycled. Its contents are nonsense in that case,
         * but that's acceptable for this function.
         */
        if (proc == NULL)
            continue;

        if (proc == MyProc)
            continue;           /* do not count myself */
        if (pgxact->xid == InvalidTransactionId)
            continue;           /* do not count if no XID assigned */
        if (proc->pid == 0)
            continue;           /* do not count prepared xacts */
        if (proc->waitLock != NULL)
            continue;           /* do not count if blocked on a lock */
        count++;
        if (count >= min)
            break;
    }

    return count >= min;
}

void ProcArrayAdd ( PGPROC proc  ) 

Definition at line 261 of file procarray.c.

References ereport, errcode(), errmsg(), FATAL, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::maxProcs, memmove, ProcArrayStruct::numProcs, PGPROC::pgprocno, ProcArrayStruct::pgprocnos, and ProcArrayLock.

Referenced by InitProcessPhase2(), and MarkAsPrepared().

{
    ProcArrayStruct *arrayP = procArray;
    int         index;

    LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

    if (arrayP->numProcs >= arrayP->maxProcs)
    {
        /*
         * Ooops, no room.  (This really shouldn't happen, since there is a
         * fixed supply of PGPROC structs too, and so we should have failed
         * earlier.)
         */
        LWLockRelease(ProcArrayLock);
        ereport(FATAL,
                (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                 errmsg("sorry, too many clients already")));
    }

    /*
     * Keep the procs array sorted by (PGPROC *) so that we can utilize
     * locality of references much better. This is useful while traversing the
     * ProcArray because there is a increased likelihood of finding the next
     * PGPROC structure in the cache.
     *
     * Since the occurrence of adding/removing a proc is much lower than the
     * access to the ProcArray itself, the overhead should be marginal
     */
    for (index = 0; index < arrayP->numProcs; index++)
    {
        /*
         * If we are the first PGPROC or if we have found our right position
         * in the array, break
         */
        if ((arrayP->pgprocnos[index] == -1) || (arrayP->pgprocnos[index] > proc->pgprocno))
            break;
    }

    memmove(&arrayP->pgprocnos[index + 1], &arrayP->pgprocnos[index],
            (arrayP->numProcs - index) * sizeof(int));
    arrayP->pgprocnos[index] = proc->pgprocno;
    arrayP->numProcs++;

    LWLockRelease(ProcArrayLock);
}

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running  ) 

Definition at line 488 of file procarray.c.

References Assert, DEBUG1, DEBUG3, elog, ERROR, ExpireOldKnownAssignedTransactionIds(), i, KnownAssignedXidsAdd(), KnownAssignedXidsDisplay(), KnownAssignedXidsReset(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, RunningTransactionsData::latestCompletedXid, latestObservedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextXid, RunningTransactionsData::nextXid, ProcArrayStruct::numKnownAssignedXids, RunningTransactionsData::oldestRunningXid, palloc(), pfree(), ProcArrayLock, qsort, ShmemVariableCache, STANDBY_INITIALIZED, STANDBY_SNAPSHOT_PENDING, STANDBY_SNAPSHOT_READY, StandbyReleaseOldLocks(), standbySnapshotPendingXmin, standbyState, RunningTransactionsData::subxcnt, RunningTransactionsData::subxid_overflow, trace_recovery(), TransactionIdAdvance, TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdFollows(), TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdRetreat, RunningTransactionsData::xcnt, xidComparator(), XidGenLock, and RunningTransactionsData::xids.

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

{
    TransactionId *xids;
    int         nxids;
    TransactionId nextXid;
    int         i;

    Assert(standbyState >= STANDBY_INITIALIZED);
    Assert(TransactionIdIsValid(running->nextXid));
    Assert(TransactionIdIsValid(running->oldestRunningXid));
    Assert(TransactionIdIsNormal(running->latestCompletedXid));

    /*
     * Remove stale transactions, if any.
     */
    ExpireOldKnownAssignedTransactionIds(running->oldestRunningXid);

    /*
     * Remove stale locks, if any.
     *
     * Locks are always assigned to the toplevel xid so we don't need to care
     * about subxcnt/subxids (and by extension not about ->suboverflowed).
     */
    StandbyReleaseOldLocks(running->xcnt, running->xids);

    /*
     * If our snapshot is already valid, nothing else to do...
     */
    if (standbyState == STANDBY_SNAPSHOT_READY)
        return;

    /*
     * If our initial RunningTransactionsData had an overflowed snapshot then
     * we knew we were missing some subxids from our snapshot. If we continue
     * to see overflowed snapshots then we might never be able to start up, so
     * we make another test to see if our snapshot is now valid. We know that
     * the missing subxids are equal to or earlier than nextXid. After we
     * initialise we continue to apply changes during recovery, so once the
     * oldestRunningXid is later than the nextXid from the initial snapshot we
     * know that we no longer have missing information and can mark the
     * snapshot as valid.
     */
    if (standbyState == STANDBY_SNAPSHOT_PENDING)
    {
        /*
         * If the snapshot isn't overflowed or if its empty we can reset our
         * pending state and use this snapshot instead.
         */
        if (!running->subxid_overflow || running->xcnt == 0)
        {
            /*
             * If we have already collected known assigned xids, we need to
             * throw them away before we apply the recovery snapshot.
             */
            KnownAssignedXidsReset();
            standbyState = STANDBY_INITIALIZED;
        }
        else
        {
            if (TransactionIdPrecedes(standbySnapshotPendingXmin,
                                      running->oldestRunningXid))
            {
                standbyState = STANDBY_SNAPSHOT_READY;
                elog(trace_recovery(DEBUG1),
                     "recovery snapshots are now enabled");
            }
            else
                elog(trace_recovery(DEBUG1),
                  "recovery snapshot waiting for non-overflowed snapshot or "
                "until oldest active xid on standby is at least %u (now %u)",
                     standbySnapshotPendingXmin,
                     running->oldestRunningXid);
            return;
        }
    }

    Assert(standbyState == STANDBY_INITIALIZED);

    /*
     * OK, we need to initialise from the RunningTransactionsData record
     */

    /*
     * Nobody else is running yet, but take locks anyhow
     */
    LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

    /*
     * KnownAssignedXids is sorted so we cannot just add the xids, we have to
     * sort them first.
     *
     * Some of the new xids are top-level xids and some are subtransactions.
     * We don't call SubtransSetParent because it doesn't matter yet. If we
     * aren't overflowed then all xids will fit in snapshot and so we don't
     * need subtrans. If we later overflow, an xid assignment record will add
     * xids to subtrans. If RunningXacts is overflowed then we don't have
     * enough information to correctly update subtrans anyway.
     */

    /*
     * Allocate a temporary array to avoid modifying the array passed as
     * argument.
     */
    xids = palloc(sizeof(TransactionId) * (running->xcnt + running->subxcnt));

    /*
     * Add to the temp array any xids which have not already completed.
     */
    nxids = 0;
    for (i = 0; i < running->xcnt + running->subxcnt; i++)
    {
        TransactionId xid = running->xids[i];

        /*
         * The running-xacts snapshot can contain xids that were still visible
         * in the procarray when the snapshot was taken, but were already
         * WAL-logged as completed. They're not running anymore, so ignore
         * them.
         */
        if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid))
            continue;

        xids[nxids++] = xid;
    }

    if (nxids > 0)
    {
        if (procArray->numKnownAssignedXids != 0)
        {
            LWLockRelease(ProcArrayLock);
            elog(ERROR, "KnownAssignedXids is not empty");
        }

        /*
         * Sort the array so that we can add them safely into
         * KnownAssignedXids.
         */
        qsort(xids, nxids, sizeof(TransactionId), xidComparator);

        /*
         * Add the sorted snapshot into KnownAssignedXids
         */
        for (i = 0; i < nxids; i++)
            KnownAssignedXidsAdd(xids[i], xids[i], true);

        KnownAssignedXidsDisplay(trace_recovery(DEBUG3));
    }

    pfree(xids);

    /*
     * Now we've got the running xids we need to set the global values that
     * are used to track snapshots as they evolve further.
     *
     * - latestCompletedXid which will be the xmax for snapshots -
     * lastOverflowedXid which shows whether snapshots overflow - nextXid
     *
     * If the snapshot overflowed, then we still initialise with what we know,
     * but the recovery snapshot isn't fully valid yet because we know there
     * are some subxids missing. We don't know the specific subxids that are
     * missing, so conservatively assume the last one is latestObservedXid.
     */
    latestObservedXid = running->nextXid;
    TransactionIdRetreat(latestObservedXid);

    if (running->subxid_overflow)
    {
        standbyState = STANDBY_SNAPSHOT_PENDING;

        standbySnapshotPendingXmin = latestObservedXid;
        procArray->lastOverflowedXid = latestObservedXid;
    }
    else
    {
        standbyState = STANDBY_SNAPSHOT_READY;

        standbySnapshotPendingXmin = InvalidTransactionId;
    }

    /*
     * If a transaction wrote a commit record in the gap between taking and
     * logging the snapshot then latestCompletedXid may already be higher than
     * the value from the snapshot, so check before we use the incoming value.
     */
    if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
                              running->latestCompletedXid))
        ShmemVariableCache->latestCompletedXid = running->latestCompletedXid;

    Assert(TransactionIdIsNormal(ShmemVariableCache->latestCompletedXid));

    LWLockRelease(ProcArrayLock);

    /*
     * ShmemVariableCache->nextXid must be beyond any observed xid.
     *
     * We don't expect anyone else to modify nextXid, hence we don't need to
     * hold a lock while examining it.  We still acquire the lock to modify
     * it, though.
     */
    nextXid = latestObservedXid;
    TransactionIdAdvance(nextXid);
    if (TransactionIdFollows(nextXid, ShmemVariableCache->nextXid))
    {
        LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
        ShmemVariableCache->nextXid = nextXid;
        LWLockRelease(XidGenLock);
    }

    Assert(TransactionIdIsValid(ShmemVariableCache->nextXid));

    KnownAssignedXidsDisplay(trace_recovery(DEBUG3));
    if (standbyState == STANDBY_SNAPSHOT_READY)
        elog(trace_recovery(DEBUG1), "recovery snapshots are now enabled");
    else
        elog(trace_recovery(DEBUG1),
             "recovery snapshot waiting for non-overflowed snapshot or "
             "until oldest active xid on standby is at least %u (now %u)",
             standbySnapshotPendingXmin,
             running->oldestRunningXid);
}

void ProcArrayApplyXidAssignment ( TransactionId  topxid,
int  nsubxids,
TransactionId subxids 
)

Definition at line 714 of file procarray.c.

References Assert, i, InvalidTransactionId, KnownAssignedXidsRemoveTree(), ProcArrayStruct::lastOverflowedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayLock, RecordKnownAssignedTransactionIds(), STANDBY_INITIALIZED, standbyState, SubTransSetParent(), TransactionIdLatest(), and TransactionIdPrecedes().

Referenced by xact_redo().

{
    TransactionId max_xid;
    int         i;

    Assert(standbyState >= STANDBY_INITIALIZED);

    max_xid = TransactionIdLatest(topxid, nsubxids, subxids);

    /*
     * Mark all the subtransactions as observed.
     *
     * NOTE: This will fail if the subxid contains too many previously
     * unobserved xids to fit into known-assigned-xids. That shouldn't happen
     * as the code stands, because xid-assignment records should never contain
     * more than PGPROC_MAX_CACHED_SUBXIDS entries.
     */
    RecordKnownAssignedTransactionIds(max_xid);

    /*
     * Notice that we update pg_subtrans with the top-level xid, rather than
     * the parent xid. This is a difference between normal processing and
     * recovery, yet is still correct in all cases. The reason is that
     * subtransaction commit is not marked in clog until commit processing, so
     * all aborted subtransactions have already been clearly marked in clog.
     * As a result we are able to refer directly to the top-level
     * transaction's state rather than skipping through all the intermediate
     * states in the subtransaction tree. This should be the first time we
     * have attempted to SubTransSetParent().
     */
    for (i = 0; i < nsubxids; i++)
        SubTransSetParent(subxids[i], topxid, false);

    /*
     * Uses same locking as transaction commit
     */
    LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

    /*
     * Remove subxids from known-assigned-xacts.
     */
    KnownAssignedXidsRemoveTree(InvalidTransactionId, nsubxids, subxids);

    /*
     * Advance lastOverflowedXid to be at least the last of these subxids.
     */
    if (TransactionIdPrecedes(procArray->lastOverflowedXid, max_xid))
        procArray->lastOverflowedXid = max_xid;

    LWLockRelease(ProcArrayLock);
}

void ProcArrayClearTransaction ( PGPROC proc  ) 

Definition at line 448 of file procarray.c.

References PGXACT::delayChkpt, PGPROC::lxid, PGXACT::nxids, PGXACT::overflowed, PGPROC::pgprocno, PGPROC::recoveryConflictPending, PGXACT::vacuumFlags, PGXACT::xid, and PGXACT::xmin.

Referenced by PrepareTransaction().

{
    PGXACT     *pgxact = &allPgXact[proc->pgprocno];

    /*
     * We can skip locking ProcArrayLock here, because this action does not
     * actually change anyone's view of the set of running XIDs: our entry is
     * duplicate with the gxact that has already been inserted into the
     * ProcArray.
     */
    pgxact->xid = InvalidTransactionId;
    proc->lxid = InvalidLocalTransactionId;
    pgxact->xmin = InvalidTransactionId;
    proc->recoveryConflictPending = false;

    /* redundant, but just in case */
    pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
    pgxact->delayChkpt = false;

    /* Clear the subtransaction-XID cache too */
    pgxact->nxids = 0;
    pgxact->overflowed = false;
}

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 382 of file procarray.c.

References Assert, PGXACT::delayChkpt, VariableCacheData::latestCompletedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PGPROC::lxid, PGXACT::nxids, PGXACT::overflowed, PGPROC::pgprocno, ProcArrayLock, PGPROC::recoveryConflictPending, ShmemVariableCache, TransactionIdIsValid, TransactionIdPrecedes(), PGXACT::vacuumFlags, PGXACT::xid, and PGXACT::xmin.

Referenced by AbortTransaction(), and CommitTransaction().

{
    PGXACT     *pgxact = &allPgXact[proc->pgprocno];

    if (TransactionIdIsValid(latestXid))
    {
        /*
         * We must lock ProcArrayLock while clearing our advertised XID, so
         * that we do not exit the set of "running" transactions while someone
         * else is taking a snapshot.  See discussion in
         * src/backend/access/transam/README.
         */
        Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid));

        LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

        pgxact->xid = InvalidTransactionId;
        proc->lxid = InvalidLocalTransactionId;
        pgxact->xmin = InvalidTransactionId;
        /* must be cleared with xid/xmin: */
        pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
        pgxact->delayChkpt = false; /* be sure this is cleared in abort */
        proc->recoveryConflictPending = false;

        /* Clear the subtransaction-XID cache too while holding the lock */
        pgxact->nxids = 0;
        pgxact->overflowed = false;

        /* Also advance global latestCompletedXid while holding the lock */
        if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
                                  latestXid))
            ShmemVariableCache->latestCompletedXid = latestXid;

        LWLockRelease(ProcArrayLock);
    }
    else
    {
        /*
         * If we have no XID, we don't need to lock, since we won't affect
         * anyone else's calculation of a snapshot.  We might change their
         * estimate of global xmin, but that's OK.
         */
        Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xid));

        proc->lxid = InvalidLocalTransactionId;
        pgxact->xmin = InvalidTransactionId;
        /* must be cleared with xid/xmin: */
        pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
        pgxact->delayChkpt = false; /* be sure this is cleared in abort */
        proc->recoveryConflictPending = false;

        Assert(pgxact->nxids == 0);
        Assert(pgxact->overflowed == false);
    }
}

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
TransactionId  sourcexid 
)

Definition at line 1493 of file procarray.c.

References Assert, PGPROC::databaseId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyPgXact, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PROC_IN_VACUUM, ProcArrayLock, TransactionIdIsNormal, TransactionIdPrecedesOrEquals(), TransactionXmin, PGXACT::vacuumFlags, PGXACT::xid, and PGXACT::xmin.

Referenced by GetSerializableTransactionSnapshotInt(), and SetTransactionSnapshot().

{
    bool        result = false;
    ProcArrayStruct *arrayP = procArray;
    int         index;

    Assert(TransactionIdIsNormal(xmin));
    if (!TransactionIdIsNormal(sourcexid))
        return false;

    /* Get lock so source xact can't end while we're doing this */
    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (index = 0; index < arrayP->numProcs; index++)
    {
        int         pgprocno = arrayP->pgprocnos[index];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];
        TransactionId xid;

        /* Ignore procs running LAZY VACUUM */
        if (pgxact->vacuumFlags & PROC_IN_VACUUM)
            continue;

        xid = pgxact->xid;      /* fetch just once */
        if (xid != sourcexid)
            continue;

        /*
         * We check the transaction's database ID for paranoia's sake: if it's
         * in another DB then its xmin does not cover us.  Caller should have
         * detected this already, so we just treat any funny cases as
         * "transaction not found".
         */
        if (proc->databaseId != MyDatabaseId)
            continue;

        /*
         * Likewise, let's just make real sure its xmin does cover us.
         */
        xid = pgxact->xmin;     /* fetch just once */
        if (!TransactionIdIsNormal(xid) ||
            !TransactionIdPrecedesOrEquals(xid, xmin))
            continue;

        /*
         * We're good.  Install the new xmin.  As in GetSnapshotData, set
         * TransactionXmin too.  (Note that because snapmgr.c called
         * GetSnapshotData first, we'll be overwriting a valid xmin here, so
         * we don't check that.)
         */
        MyPgXact->xmin = TransactionXmin = xmin;

        result = true;
        break;
    }

    LWLockRelease(ProcArrayLock);

    return result;
}

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 319 of file procarray.c.

References Assert, elog, VariableCacheData::latestCompletedXid, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), memmove, ProcArrayStruct::numProcs, PGPROC::pgprocno, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, ShmemVariableCache, TransactionIdIsValid, TransactionIdPrecedes(), and PGXACT::xid.

Referenced by FinishPreparedTransaction(), and RemoveProcFromArray().

{
    ProcArrayStruct *arrayP = procArray;
    int         index;

#ifdef XIDCACHE_DEBUG
    /* dump stats at backend shutdown, but not prepared-xact end */
    if (proc->pid != 0)
        DisplayXidCache();
#endif

    LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

    if (TransactionIdIsValid(latestXid))
    {
        Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid));

        /* Advance global latestCompletedXid while holding the lock */
        if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
                                  latestXid))
            ShmemVariableCache->latestCompletedXid = latestXid;
    }
    else
    {
        /* Shouldn't be trying to remove a live transaction here */
        Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
    }

    for (index = 0; index < arrayP->numProcs; index++)
    {
        if (arrayP->pgprocnos[index] == proc->pgprocno)
        {
            /* Keep the PGPROC array sorted. See notes above */
            memmove(&arrayP->pgprocnos[index], &arrayP->pgprocnos[index + 1],
                    (arrayP->numProcs - index - 1) * sizeof(int));
            arrayP->pgprocnos[arrayP->numProcs - 1] = -1;       /* for debugging */
            arrayP->numProcs--;
            LWLockRelease(ProcArrayLock);
            return;
        }
    }

    /* Ooops */
    LWLockRelease(ProcArrayLock);

    elog(LOG, "failed to find proc %p in ProcArray", proc);
}

Size ProcArrayShmemSize ( void   ) 

Definition at line 170 of file procarray.c.

References add_size(), EnableHotStandby, mul_size(), offsetof, PROCARRAY_MAXPROCS, and TOTAL_MAX_CACHED_SUBXIDS.

Referenced by CreateSharedMemoryAndSemaphores().

{
    Size        size;

    /* Size of the ProcArray structure itself */
#define PROCARRAY_MAXPROCS  (MaxBackends + max_prepared_xacts)

    size = offsetof(ProcArrayStruct, pgprocnos);
    size = add_size(size, mul_size(sizeof(int), PROCARRAY_MAXPROCS));

    /*
     * During Hot Standby processing we have a data structure called
     * KnownAssignedXids, created in shared memory. Local data structures are
     * also created in various backends during GetSnapshotData(),
     * TransactionIdIsInProgress() and GetRunningTransactionData(). All of the
     * main structures created in those functions must be identically sized,
     * since we may at times copy the whole of the data structures around. We
     * refer to this size as TOTAL_MAX_CACHED_SUBXIDS.
     *
     * Ideally we'd only create this structure if we were actually doing hot
     * standby in the current run, but we don't know that yet at the time
     * shared memory is being set up.
     */
#define TOTAL_MAX_CACHED_SUBXIDS \
    ((PGPROC_MAX_CACHED_SUBXIDS + 1) * PROCARRAY_MAXPROCS)

    if (EnableHotStandby)
    {
        size = add_size(size,
                        mul_size(sizeof(TransactionId),
                                 TOTAL_MAX_CACHED_SUBXIDS));
        size = add_size(size,
                        mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS));
    }

    return size;
}

void RecordKnownAssignedTransactionIds ( TransactionId  xid  ) 

Definition at line 2621 of file procarray.c.

References Assert, DEBUG4, elog, ExtendCLOG(), ExtendSUBTRANS(), KnownAssignedXidsAdd(), latestObservedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextXid, ShmemVariableCache, STANDBY_INITIALIZED, standbyState, trace_recovery(), TransactionIdAdvance, TransactionIdFollows(), TransactionIdIsValid, TransactionIdPrecedesOrEquals(), and XidGenLock.

Referenced by ProcArrayApplyXidAssignment(), StartupXLOG(), xact_redo_abort(), and xact_redo_commit_internal().

{
    Assert(standbyState >= STANDBY_INITIALIZED);
    Assert(TransactionIdIsValid(xid));

    elog(trace_recovery(DEBUG4), "record known xact %u latestObservedXid %u",
         xid, latestObservedXid);

    /*
     * If the KnownAssignedXids machinery isn't up yet, do nothing.
     */
    if (standbyState <= STANDBY_INITIALIZED)
        return;

    Assert(TransactionIdIsValid(latestObservedXid));

    /*
     * When a newly observed xid arrives, it is frequently the case that it is
     * *not* the next xid in sequence. When this occurs, we must treat the
     * intervening xids as running also.
     */
    if (TransactionIdFollows(xid, latestObservedXid))
    {
        TransactionId next_expected_xid;

        /*
         * Extend clog and subtrans like we do in GetNewTransactionId() during
         * normal operation using individual extend steps. Typical case
         * requires almost no activity.
         */
        next_expected_xid = latestObservedXid;
        TransactionIdAdvance(next_expected_xid);
        while (TransactionIdPrecedesOrEquals(next_expected_xid, xid))
        {
            ExtendCLOG(next_expected_xid);
            ExtendSUBTRANS(next_expected_xid);

            TransactionIdAdvance(next_expected_xid);
        }

        /*
         * Add the new xids onto the KnownAssignedXids array.
         */
        next_expected_xid = latestObservedXid;
        TransactionIdAdvance(next_expected_xid);
        KnownAssignedXidsAdd(next_expected_xid, xid, false);

        /*
         * Now we can advance latestObservedXid
         */
        latestObservedXid = xid;

        /* ShmemVariableCache->nextXid must be beyond any observed xid */
        next_expected_xid = latestObservedXid;
        TransactionIdAdvance(next_expected_xid);
        LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
        ShmemVariableCache->nextXid = next_expected_xid;
        LWLockRelease(XidGenLock);
    }
}

bool TransactionIdIsActive ( TransactionId  xid  ) 

Definition at line 1011 of file procarray.c.

References i, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, ProcArrayLock, RecentXmin, TransactionIdEquals, TransactionIdIsValid, TransactionIdPrecedes(), and PGXACT::xid.

Referenced by LockGXact(), and MarkAsPreparing().

{
    bool        result = false;
    ProcArrayStruct *arrayP = procArray;
    int         i;

    /*
     * Don't bother checking a transaction older than RecentXmin; it could not
     * possibly still be running.
     */
    if (TransactionIdPrecedes(xid, RecentXmin))
        return false;

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    for (i = 0; i < arrayP->numProcs; i++)
    {
        int         pgprocno = arrayP->pgprocnos[i];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];
        TransactionId pxid;

        /* Fetch xid just once - see GetNewTransactionId */
        pxid = pgxact->xid;

        if (!TransactionIdIsValid(pxid))
            continue;

        if (proc->pid == 0)
            continue;           /* ignore prepared transactions */

        if (TransactionIdEquals(pxid, xid))
        {
            result = true;
            break;
        }
    }

    LWLockRelease(ProcArrayLock);

    return result;
}

bool TransactionIdIsInProgress ( TransactionId  xid  ) 

Definition at line 794 of file procarray.c.

References Assert, ereport, errcode(), errmsg(), ERROR, i, KnownAssignedXidExists(), KnownAssignedXidsGet(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, ProcArrayStruct::maxProcs, MyProc, NULL, ProcArrayStruct::numProcs, PGXACT::nxids, PGXACT::overflowed, ProcArrayStruct::pgprocnos, ProcArrayLock, RecentXmin, RecoveryInProgress(), ShmemVariableCache, SubTransGetTopmostTransaction(), PGPROC::subxids, TOTAL_MAX_CACHED_SUBXIDS, TransactionIdDidAbort(), TransactionIdEquals, TransactionIdIsCurrentTransactionId(), TransactionIdIsKnownCompleted(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdPrecedesOrEquals(), xc_by_child_xid_inc, xc_by_known_assigned_inc, xc_by_known_xact_inc, xc_by_latest_xid_inc, xc_by_main_xid_inc, xc_by_my_xact_inc, xc_by_recent_xmin_inc, xc_no_overflow_inc, xc_slow_answer_inc, PGXACT::xid, and XidCache::xids.

Referenced by compute_new_xmax_infomask(), ConditionalXactLockTableWait(), Do_MultiXactIdWait(), heap_lock_updated_tuple_rec(), HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesMVCC(), HeapTupleSatisfiesNow(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuum(), MultiXactIdExpand(), MultiXactIdIsRunning(), and XactLockTableWait().

{
    static TransactionId *xids = NULL;
    int         nxids = 0;
    ProcArrayStruct *arrayP = procArray;
    TransactionId topxid;
    int         i,
                j;

    /*
     * Don't bother checking a transaction older than RecentXmin; it could not
     * possibly still be running.  (Note: in particular, this guarantees that
     * we reject InvalidTransactionId, FrozenTransactionId, etc as not
     * running.)
     */
    if (TransactionIdPrecedes(xid, RecentXmin))
    {
        xc_by_recent_xmin_inc();
        return false;
    }

    /*
     * We may have just checked the status of this transaction, so if it is
     * already known to be completed, we can fall out without any access to
     * shared memory.
     */
    if (TransactionIdIsKnownCompleted(xid))
    {
        xc_by_known_xact_inc();
        return false;
    }

    /*
     * Also, we can handle our own transaction (and subtransactions) without
     * any access to shared memory.
     */
    if (TransactionIdIsCurrentTransactionId(xid))
    {
        xc_by_my_xact_inc();
        return true;
    }

    /*
     * If first time through, get workspace to remember main XIDs in. We
     * malloc it permanently to avoid repeated palloc/pfree overhead.
     */
    if (xids == NULL)
    {
        /*
         * In hot standby mode, reserve enough space to hold all xids in the
         * known-assigned list. If we later finish recovery, we no longer need
         * the bigger array, but we don't bother to shrink it.
         */
        int         maxxids = RecoveryInProgress() ? TOTAL_MAX_CACHED_SUBXIDS : arrayP->maxProcs;

        xids = (TransactionId *) malloc(maxxids * sizeof(TransactionId));
        if (xids == NULL)
            ereport(ERROR,
                    (errcode(ERRCODE_OUT_OF_MEMORY),
                     errmsg("out of memory")));
    }

    LWLockAcquire(ProcArrayLock, LW_SHARED);

    /*
     * Now that we have the lock, we can check latestCompletedXid; if the
     * target Xid is after that, it's surely still running.
     */
    if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid, xid))
    {
        LWLockRelease(ProcArrayLock);
        xc_by_latest_xid_inc();
        return true;
    }

    /* No shortcuts, gotta grovel through the array */
    for (i = 0; i < arrayP->numProcs; i++)
    {
        int         pgprocno = arrayP->pgprocnos[i];
        volatile PGPROC *proc = &allProcs[pgprocno];
        volatile PGXACT *pgxact = &allPgXact[pgprocno];
        TransactionId pxid;

        /* Ignore my own proc --- dealt with it above */
        if (proc == MyProc)
            continue;

        /* Fetch xid just once - see GetNewTransactionId */
        pxid = pgxact->xid;

        if (!TransactionIdIsValid(pxid))
            continue;

        /*
         * Step 1: check the main Xid
         */
        if (TransactionIdEquals(pxid, xid))
        {
            LWLockRelease(ProcArrayLock);
            xc_by_main_xid_inc();
            return true;
        }

        /*
         * We can ignore main Xids that are younger than the target Xid, since
         * the target could not possibly be their child.
         */
        if (TransactionIdPrecedes(xid, pxid))
            continue;

        /*
         * Step 2: check the cached child-Xids arrays
         */
        for (j = pgxact->nxids - 1; j >= 0; j--)
        {
            /* Fetch xid just once - see GetNewTransactionId */
            TransactionId cxid = proc->subxids.xids[j];

            if (TransactionIdEquals(cxid, xid))
            {
                LWLockRelease(ProcArrayLock);
                xc_by_child_xid_inc();
                return true;
            }
        }

        /*
         * Save the main Xid for step 4.  We only need to remember main Xids
         * that have uncached children.  (Note: there is no race condition
         * here because the overflowed flag cannot be cleared, only set, while
         * we hold ProcArrayLock.  So we can't miss an Xid that we need to
         * worry about.)
         */
        if (pgxact->overflowed)
            xids[nxids++] = pxid;
    }

    /*
     * Step 3: in hot standby mode, check the known-assigned-xids list.  XIDs
     * in the list must be treated as running.
     */
    if (RecoveryInProgress())
    {
        /* none of the PGXACT entries should have XIDs in hot standby mode */
        Assert(nxids == 0);

        if (KnownAssignedXidExists(xid))
        {
            LWLockRelease(ProcArrayLock);
            xc_by_known_assigned_inc();
            return true;
        }

        /*
         * If the KnownAssignedXids overflowed, we have to check pg_subtrans
         * too.  Fetch all xids from KnownAssignedXids that are lower than
         * xid, since if xid is a subtransaction its parent will always have a
         * lower value.  Note we will collect both main and subXIDs here, but
         * there's no help for it.
         */
        if (TransactionIdPrecedesOrEquals(xid, procArray->lastOverflowedXid))
            nxids = KnownAssignedXidsGet(xids, xid);
    }

    LWLockRelease(ProcArrayLock);

    /*
     * If none of the relevant caches overflowed, we know the Xid is not
     * running without even looking at pg_subtrans.
     */
    if (nxids == 0)
    {
        xc_no_overflow_inc();
        return false;
    }

    /*
     * Step 4: have to check pg_subtrans.
     *
     * At this point, we know it's either a subtransaction of one of the Xids
     * in xids[], or it's not running.  If it's an already-failed
     * subtransaction, we want to say "not running" even though its parent may
     * still be running.  So first, check pg_clog to see if it's been aborted.
     */
    xc_slow_answer_inc();

    if (TransactionIdDidAbort(xid))
        return false;

    /*
     * It isn't aborted, so check whether the transaction tree it belongs to
     * is still running (or, more precisely, whether it was running when we
     * held ProcArrayLock).
     */
    topxid = SubTransGetTopmostTransaction(xid);
    Assert(TransactionIdIsValid(topxid));
    if (!TransactionIdEquals(topxid, xid))
    {
        for (i = 0; i < nxids; i++)
        {
            if (TransactionIdEquals(xids[i], topxid))
                return true;
        }
    }

    return false;
}

void XidCacheRemoveRunningXids ( TransactionId  xid,
int  nxids,
const TransactionId xids,
TransactionId  latestXid 
)

Definition at line 2464 of file procarray.c.

References Assert, elog, i, VariableCacheData::latestCompletedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyPgXact, MyProc, PGXACT::nxids, ProcArrayLock, ShmemVariableCache, PGPROC::subxids, TransactionIdEquals, TransactionIdIsValid, TransactionIdPrecedes(), WARNING, XidCacheRemove, and XidCache::xids.

Referenced by RecordTransactionAbort().

{
    int         i,
                j;

    Assert(TransactionIdIsValid(xid));

    /*
     * We must hold ProcArrayLock exclusively in order to remove transactions
     * from the PGPROC array.  (See src/backend/access/transam/README.)  It's
     * possible this could be relaxed since we know this routine is only used
     * to abort subtransactions, but pending closer analysis we'd best be
     * conservative.
     */
    LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

    /*
     * Under normal circumstances xid and xids[] will be in increasing order,
     * as will be the entries in subxids.  Scan backwards to avoid O(N^2)
     * behavior when removing a lot of xids.
     */
    for (i = nxids - 1; i >= 0; i--)
    {
        TransactionId anxid = xids[i];

        for (j = MyPgXact->nxids - 1; j >= 0; j--)
        {
            if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
            {
                XidCacheRemove(j);
                break;
            }
        }

        /*
         * Ordinarily we should have found it, unless the cache has
         * overflowed. However it's also possible for this routine to be
         * invoked multiple times for the same subtransaction, in case of an
         * error during AbortSubTransaction.  So instead of Assert, emit a
         * debug warning.
         */
        if (j < 0 && !MyPgXact->overflowed)
            elog(WARNING, "did not find subXID %u in MyProc", anxid);
    }

    for (j = MyPgXact->nxids - 1; j >= 0; j--)
    {
        if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
        {
            XidCacheRemove(j);
            break;
        }
    }
    /* Ordinarily we should have found it, unless the cache has overflowed */
    if (j < 0 && !MyPgXact->overflowed)
        elog(WARNING, "did not find subXID %u in MyProc", xid);

    /* Also advance global latestCompletedXid while holding the lock */
    if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
                              latestXid))
        ShmemVariableCache->latestCompletedXid = latestXid;

    LWLockRelease(ProcArrayLock);
}