diff options
Diffstat (limited to 'src/backend/storage/ipc/procarray.c')
-rw-r--r-- | src/backend/storage/ipc/procarray.c | 140 |
1 files changed, 89 insertions, 51 deletions
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 23b198b1497..7c2766e6285 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -11,6 +11,11 @@ * Because of various subtle race conditions it is critical that a backend * hold the correct locks while setting or clearing its MyProc->xid field. * See notes in GetSnapshotData. + * + * The process array now also includes PGPROC structures representing + * prepared transactions. The xid and subxids fields of these are valid, + * as is the procLocks list. They can be distinguished from regular backend + * PGPROCs at need by checking for pid == 0. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group @@ -18,13 +23,14 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.2 2005/05/19 23:57:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.3 2005/06/17 22:32:45 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/subtrans.h" +#include "access/twophase.h" #include "miscadmin.h" #include "storage/proc.h" #include "storage/procarray.h" @@ -76,25 +82,23 @@ static void DisplayXidCache(void); * Report shared-memory space needed by CreateSharedProcArray. */ int -ProcArrayShmemSize(int maxBackends) +ProcArrayShmemSize(void) { - /* sizeof(ProcArrayStruct) includes the first array element */ - return MAXALIGN(sizeof(ProcArrayStruct) + - (maxBackends - 1) * sizeof(PGPROC *)); + return MAXALIGN(offsetof(ProcArrayStruct, procs) + + (MaxBackends + max_prepared_xacts) * sizeof(PGPROC *)); } /* * Initialize the shared PGPROC array during postmaster startup. */ void -CreateSharedProcArray(int maxBackends) +CreateSharedProcArray(void) { bool found; /* Create or attach to the ProcArray shared structure */ procArray = (ProcArrayStruct *) - ShmemInitStruct("Proc Array", ProcArrayShmemSize(maxBackends), - &found); + ShmemInitStruct("Proc Array", ProcArrayShmemSize(), &found); if (!found) { @@ -102,18 +106,15 @@ CreateSharedProcArray(int maxBackends) * We're the first - initialize. */ procArray->numProcs = 0; - procArray->maxProcs = maxBackends; + procArray->maxProcs = MaxBackends + max_prepared_xacts; } } /* - * Add my own PGPROC (found in the global MyProc) to the shared array. - * - * This must be called during backend startup, after fully initializing - * the contents of MyProc. + * Add the specified PGPROC to the shared array. */ void -ProcArrayAddMyself(void) +ProcArrayAdd(PGPROC *proc) { ProcArrayStruct *arrayP = procArray; @@ -132,32 +133,32 @@ ProcArrayAddMyself(void) errmsg("sorry, too many clients already"))); } - arrayP->procs[arrayP->numProcs] = MyProc; + arrayP->procs[arrayP->numProcs] = proc; arrayP->numProcs++; LWLockRelease(ProcArrayLock); } /* - * Remove my own PGPROC (found in the global MyProc) from the shared array. - * - * This must be called during backend shutdown. + * Remove the specified PGPROC from the shared array. */ void -ProcArrayRemoveMyself(void) +ProcArrayRemove(PGPROC *proc) { ProcArrayStruct *arrayP = procArray; int index; #ifdef XIDCACHE_DEBUG - DisplayXidCache(); + /* dump stats at backend shutdown, but not prepared-xact end */ + if (proc->pid != 0) + DisplayXidCache(); #endif LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); for (index = 0; index < arrayP->numProcs; index++) { - if (arrayP->procs[index] == MyProc) + if (arrayP->procs[index] == proc) { arrayP->procs[index] = arrayP->procs[arrayP->numProcs - 1]; arrayP->numProcs--; @@ -169,7 +170,7 @@ ProcArrayRemoveMyself(void) /* Ooops */ LWLockRelease(ProcArrayLock); - elog(LOG, "failed to find my own proc %p in ProcArray", MyProc); + elog(LOG, "failed to find proc %p in ProcArray", proc); } @@ -330,6 +331,55 @@ result_known: } /* + * TransactionIdIsActive -- is xid the top-level XID of an active backend? + * + * This differs from TransactionIdIsInProgress in that it ignores prepared + * transactions. Also, we ignore subtransactions since that's not needed + * for current uses. + */ +bool +TransactionIdIsActive(TransactionId xid) +{ + 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++) + { + PGPROC *proc = arrayP->procs[i]; + + /* Fetch xid just once - see GetNewTransactionId */ + TransactionId pxid = proc->xid; + + if (!TransactionIdIsValid(pxid)) + continue; + + if (proc->pid == 0) + continue; /* ignore prepared transactions */ + + if (TransactionIdEquals(pxid, xid)) + { + result = true; + break; + } + } + + LWLockRelease(ProcArrayLock); + + return result; +} + + +/* * GetOldestXmin -- returns oldest transaction that was running * when any current transaction was started. * @@ -441,12 +491,12 @@ GetSnapshotData(Snapshot snapshot, bool serializable) TransactionIdIsValid(MyProc->xmin)); /* - * Allocating space for MaxBackends xids is usually overkill; + * 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. * * This does open a possibility for avoiding repeated malloc/free: since - * MaxBackends does not change at runtime, we can simply reuse the + * maxProcs does not change at runtime, we can simply reuse the * previous xip array if any. (This relies on the fact that all * callers pass static SnapshotData structs.) */ @@ -456,7 +506,7 @@ GetSnapshotData(Snapshot snapshot, bool serializable) * First call for this snapshot */ snapshot->xip = (TransactionId *) - malloc(MaxBackends * sizeof(TransactionId)); + malloc(arrayP->maxProcs * sizeof(TransactionId)); if (snapshot->xip == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -602,14 +652,21 @@ DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself) /* * BackendPidGetProc -- get a backend's PGPROC given its PID + * + * Returns NULL if not found. Note that it is up to the caller to be + * sure that the question remains meaningful for long enough for the + * answer to be used ... */ -struct PGPROC * +PGPROC * BackendPidGetProc(int pid) { 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++) @@ -642,10 +699,8 @@ IsBackendPid(int pid) * active transactions. This is used as a heuristic to decide if * a pre-XLOG-flush delay is worthwhile during commit. * - * An active transaction is something that has written at least one XLOG - * record; read-only transactions don't count. Also, do not count backends - * that are blocked waiting for locks, since they are not going to get to - * run until someone else commits. + * Do not count backends that are blocked waiting for locks, since they are + * not going to get to run until someone else commits. */ int CountActiveBackends(void) @@ -656,7 +711,7 @@ CountActiveBackends(void) /* * Note: for speed, we don't acquire ProcArrayLock. This is a little bit - * bogus, but since we are only testing xrecoff for zero or nonzero, + * 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... */ @@ -666,7 +721,9 @@ CountActiveBackends(void) if (proc == MyProc) continue; /* do not count myself */ - if (proc->logRec.xrecoff == 0) + if (proc->pid == 0) + continue; /* do not count prepared xacts */ + if (proc->xid == InvalidTransactionId) continue; /* do not count if not in a transaction */ if (proc->waitLock != NULL) continue; /* do not count if blocked on a lock */ @@ -676,25 +733,6 @@ CountActiveBackends(void) return count; } -/* - * CountEmptyBackendSlots - count empty slots in backend process table - * - * Acquiring the lock here is almost certainly overkill, but just in - * case fetching an int is not atomic on your machine ... - */ -int -CountEmptyBackendSlots(void) -{ - int count; - - LWLockAcquire(ProcArrayLock, LW_SHARED); - - count = procArray->maxProcs - procArray->numProcs; - - LWLockRelease(ProcArrayLock); - - return count; -} #define XidCacheRemove(i) \ do { \ |