communication structure, and make it its own module with its own lock.
This should reduce contention at least a little, and it definitely makes
the code seem cleaner. Per my recent proposal.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.190 2005/05/03 19:42:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.191 2005/05/19 21:35:44 tgl Exp $
*
*
* INTERFACE ROUTINES
#include "catalog/catalog.h"
#include "catalog/namespace.h"
#include "miscadmin.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "utils/inval.h"
#include "utils/relcache.h"
#include "pgstat.h"
-$PostgreSQL: pgsql/src/backend/access/transam/README,v 1.2 2004/09/16 16:58:26 tgl Exp $
+$PostgreSQL: pgsql/src/backend/access/transam/README,v 1.3 2005/05/19 21:35:45 tgl Exp $
The Transaction System
----------------------
in shared memory, so we have to store them on disk. Note, however, that for
each transaction we keep a "cache" of Xids that are known to be part of the
transaction tree, so we can skip looking at pg_subtrans unless we know the
-cache has been overflowed. See storage/ipc/sinval.c for the gory details.
+cache has been overflowed. See storage/ipc/procarray.c for the gory details.
slru.c is the supporting mechanism for both pg_clog and pg_subtrans. It
implements the LRU policy for in-memory buffer pages. The high-level routines
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.3 2005/05/07 18:14:25 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/multixact.c,v 1.4 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/memutils.h"
#include "storage/backendid.h"
#include "storage/lmgr.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
/*
}
/*
- * This could be made better by having a special entry point in sinval.c,
- * walking the PGPROC array only once for the whole array. But in most
+ * This could be made faster by having another entry point in procarray.c,
+ * walking the PGPROC array only once for all the members. But in most
* cases nmembers should be small enough that it doesn't much matter.
*/
for (i = 0; i < nmembers; i++)
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/subtrans.c,v 1.7 2004/12/31 21:59:29 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/subtrans.c,v 1.8 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/slru.h"
#include "access/subtrans.h"
-#include "storage/sinval.h"
#include "utils/tqual.h"
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.63 2005/04/13 18:54:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.64 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* nextXid are already present in PGPROC. Else we have a race
* condition.
*
- * XXX by storing xid into MyProc without acquiring SInvalLock, we are
+ * XXX by storing xid into MyProc 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 (and in fact could cause a
*
* A solution to the atomic-store problem would be to give each PGPROC
* its own spinlock used only for fetching/storing that PGPROC's xid
- * and related fields. (SInvalLock would then mean primarily that
- * PGPROCs couldn't be added/removed while holding the lock.)
+ * 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
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.200 2005/04/28 21:47:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.201 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "miscadmin.h"
#include "storage/fd.h"
#include "storage/proc.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "storage/smgr.h"
#include "utils/flatfiles.h"
#include "utils/guc.h"
* this must be done _before_ releasing locks we hold and _after_
* RecordTransactionCommit.
*
- * LWLockAcquire(SInvalLock) is required: UPDATE with xid 0 is blocked by
- * xid 1' UPDATE, xid 1 is doing commit while xid 2 gets snapshot - if
- * xid 2' GetSnapshotData sees xid 1 as running then it must see xid 0
- * as running as well or it will see two tuple versions - one deleted
- * by xid 1 and one inserted by xid 0. See notes in GetSnapshotData.
+ * LWLockAcquire(ProcArrayLock) is required; consider this example:
+ * UPDATE with xid 0 is blocked by xid 1's UPDATE.
+ * xid 1 is doing commit while xid 2 gets snapshot.
+ * If xid 2's GetSnapshotData sees xid 1 as running then it must see
+ * xid 0 as running as well, or it will be able to see two tuple versions
+ * - one deleted by xid 1 and one inserted by xid 0. See notes in
+ * GetSnapshotData.
*/
if (MyProc != NULL)
{
- /* Lock SInvalLock because that's what GetSnapshotData uses. */
- LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
+ /* Lock ProcArrayLock because that's what GetSnapshotData uses. */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
MyProc->subxids.nxids = 0;
MyProc->subxids.overflowed = false;
- LWLockRelease(SInvalLock);
+ LWLockRelease(ProcArrayLock);
}
/*
*/
if (MyProc != NULL)
{
- /* Lock SInvalLock because that's what GetSnapshotData uses. */
- LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
+ /* Lock ProcArrayLock because that's what GetSnapshotData uses. */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
MyProc->subxids.nxids = 0;
MyProc->subxids.overflowed = false;
- LWLockRelease(SInvalLock);
+ LWLockRelease(ProcArrayLock);
}
/*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.191 2005/05/10 22:27:29 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.192 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/lwlock.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/guc.h"
if (MyLastRecPtr.xrecoff == 0 && !no_tran)
{
/*
- * We do not acquire SInvalLock here because of possible deadlock.
+ * We do not acquire ProcArrayLock here because of possible deadlock.
* Anyone who wants to inspect other procs' logRec must acquire
* WALInsertLock, instead. A better solution would be a per-PROC
* spinlock, but no time for that before 7.2 --- tgl 12/19/01.
* commits after REDO point).
*
* XXX temporarily ifdef'd out to avoid three-way deadlock condition:
- * GetUndoRecPtr needs to grab SInvalLock to ensure that it is looking
- * at a stable set of proc records, but grabbing SInvalLock while
+ * GetUndoRecPtr needs to grab ProcArrayLock to ensure that it is looking
+ * at a stable set of proc records, but grabbing ProcArrayLock while
* holding WALInsertLock is no good. GetNewTransactionId may cause a
* WAL record to be written while holding XidGenLock, and
- * GetSnapshotData needs to get XidGenLock while holding SInvalLock,
+ * GetSnapshotData needs to get XidGenLock while holding ProcArrayLock,
* so there's a risk of deadlock. Need to find a better solution. See
* pgsql-hackers discussion of 17-Dec-01.
*
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.255 2005/05/11 06:24:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.256 2005/05/19 21:35:45 tgl Exp $
*
*
* INTERFACE ROUTINES
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "parser/parse_expr.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.156 2005/04/14 20:03:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.157 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postmaster/bgwriter.h"
#include "storage/fd.h"
#include "storage/freespace.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.308 2005/05/06 17:24:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.309 2005/05/19 21:35:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "executor/executor.h"
#include "miscadmin.h"
#include "storage/freespace.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "storage/smgr.h"
#include "tcop/pquery.h"
#include "utils/acl.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.53 2005/05/07 21:32:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/vacuumlazy.c,v 1.54 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "commands/vacuum.h"
#include "miscadmin.h"
#include "storage/freespace.h"
-#include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/lsyscache.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_init.c,v 1.72 2005/03/04 20:21:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/buf_init.c,v 1.73 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
buf->flags = 0;
buf->usage_count = 0;
buf->refcount = 0;
- buf->wait_backend_id = 0;
+ buf->wait_backend_pid = 0;
SpinLockInit(&buf->buf_hdr_lock);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.188 2005/03/20 22:00:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.189 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
buf->refcount == 1)
{
/* we just released the last pin other than the waiter's */
- BackendId wait_backend_id = buf->wait_backend_id;
+ int wait_backend_pid = buf->wait_backend_pid;
buf->flags &= ~BM_PIN_COUNT_WAITER;
UnlockBufHdr_NoHoldoff(buf);
- ProcSendSignal(wait_backend_id);
+ ProcSendSignal(wait_backend_pid);
}
else
UnlockBufHdr_NoHoldoff(buf);
* signal.
*/
if ((buf->flags & BM_PIN_COUNT_WAITER) != 0 &&
- buf->wait_backend_id == MyBackendId)
+ buf->wait_backend_pid == MyProcPid)
buf->flags &= ~BM_PIN_COUNT_WAITER;
UnlockBufHdr_NoHoldoff(buf);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
elog(ERROR, "multiple backends attempting to wait for pincount 1");
}
- bufHdr->wait_backend_id = MyBackendId;
+ bufHdr->wait_backend_pid = MyProcPid;
bufHdr->flags |= BM_PIN_COUNT_WAITER;
PinCountWaitBuf = bufHdr;
UnlockBufHdr_NoHoldoff(bufHdr);
#
# Makefile for storage/ipc
#
-# $PostgreSQL: pgsql/src/backend/storage/ipc/Makefile,v 1.18 2003/11/29 19:51:56 pgsql Exp $
+# $PostgreSQL: pgsql/src/backend/storage/ipc/Makefile,v 1.19 2005/05/19 21:35:46 tgl Exp $
#
subdir = src/backend/storage/ipc
endif
endif
-OBJS = ipc.o ipci.o pmsignal.o shmem.o shmqueue.o sinval.o sinvaladt.o
+OBJS = ipc.o ipci.o pmsignal.o procarray.o shmem.o shmqueue.o \
+ sinval.o sinvaladt.o
all: SUBSYS.o
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.75 2005/04/28 21:47:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.76 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/pg_shmem.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
+#include "storage/procarray.h"
#include "storage/sinval.h"
#include "storage/spin.h"
size += SUBTRANSShmemSize();
size += MultiXactShmemSize();
size += LWLockShmemSize();
+ size += ProcArrayShmemSize(maxBackends);
size += SInvalShmemSize(maxBackends);
size += FreeSpaceShmemSize();
size += BgWriterShmemSize();
* Set up process table
*/
InitProcGlobal(maxBackends);
+ CreateSharedProcArray(maxBackends);
/*
* Set up shared-inval messaging
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * procarray.c
+ * POSTGRES process array code.
+ *
+ *
+ * This module maintains an unsorted array of the PGPROC structures for all
+ * active backends. Although there are several uses for this, the principal
+ * one is as a means of determining the set of currently running transactions.
+ *
+ * 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.
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.1 2005/05/19 21:35:46 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/subtrans.h"
+#include "miscadmin.h"
+#include "storage/proc.h"
+#include "storage/procarray.h"
+#include "utils/tqual.h"
+
+
+/* Our shared memory area */
+typedef struct ProcArrayStruct
+{
+ int numProcs; /* number of valid procs entries */
+ int maxProcs; /* allocated size of procs array */
+
+ /*
+ * We declare procs[] as 1 entry because C wants a fixed-size array,
+ * but actually it is maxProcs entries long.
+ */
+ PGPROC *procs[1]; /* VARIABLE LENGTH ARRAY */
+} ProcArrayStruct;
+
+static ProcArrayStruct *procArray;
+
+
+#ifdef XIDCACHE_DEBUG
+
+/* counters for XidCache measurement */
+static long xc_by_recent_xmin = 0;
+static long xc_by_main_xid = 0;
+static long xc_by_child_xid = 0;
+static long xc_slow_answer = 0;
+
+#define xc_by_recent_xmin_inc() (xc_by_recent_xmin++)
+#define xc_by_main_xid_inc() (xc_by_main_xid++)
+#define xc_by_child_xid_inc() (xc_by_child_xid++)
+#define xc_slow_answer_inc() (xc_slow_answer++)
+
+static void DisplayXidCache(void);
+
+#else /* !XIDCACHE_DEBUG */
+
+#define xc_by_recent_xmin_inc() ((void) 0)
+#define xc_by_main_xid_inc() ((void) 0)
+#define xc_by_child_xid_inc() ((void) 0)
+#define xc_slow_answer_inc() ((void) 0)
+
+#endif /* XIDCACHE_DEBUG */
+
+
+/*
+ * Report shared-memory space needed by CreateSharedProcArray.
+ */
+int
+ProcArrayShmemSize(int maxBackends)
+{
+ /* sizeof(ProcArrayStruct) includes the first array element */
+ return MAXALIGN(sizeof(ProcArrayStruct) +
+ (maxBackends - 1) * sizeof(PGPROC *));
+}
+
+/*
+ * Initialize the shared PGPROC array during postmaster startup.
+ */
+void
+CreateSharedProcArray(int maxBackends)
+{
+ bool found;
+
+ /* Create or attach to the ProcArray shared structure */
+ procArray = (ProcArrayStruct *)
+ ShmemInitStruct("Proc Array", ProcArrayShmemSize(maxBackends),
+ &found);
+
+ if (!found)
+ {
+ /*
+ * We're the first - initialize.
+ */
+ procArray->numProcs = 0;
+ procArray->maxProcs = maxBackends;
+ }
+}
+
+/*
+ * 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.
+ */
+void
+ProcArrayAddMyself(void)
+{
+ ProcArrayStruct *arrayP = procArray;
+
+ 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")));
+ }
+
+ arrayP->procs[arrayP->numProcs] = MyProc;
+ arrayP->numProcs++;
+
+ LWLockRelease(ProcArrayLock);
+}
+
+/*
+ * Remove my own PGPROC (found in the global MyProc) from the shared array.
+ *
+ * This must be called during backend shutdown.
+ */
+void
+ProcArrayRemoveMyself(void)
+{
+ ProcArrayStruct *arrayP = procArray;
+ int index;
+
+#ifdef XIDCACHE_DEBUG
+ DisplayXidCache();
+#endif
+
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ if (arrayP->procs[index] == MyProc)
+ {
+ arrayP->procs[index] = arrayP->procs[arrayP->numProcs - 1];
+ arrayP->numProcs--;
+ LWLockRelease(ProcArrayLock);
+ return;
+ }
+ }
+
+ /* Ooops */
+ LWLockRelease(ProcArrayLock);
+
+ elog(LOG, "failed to find my own proc %p in ProcArray", MyProc);
+}
+
+
+/*
+ * TransactionIdIsInProgress -- is given transaction running in some backend
+ *
+ * There are three possibilities for finding a running transaction:
+ *
+ * 1. the given Xid is a main transaction Id. We will find this out cheaply
+ * by looking at the PGPROC struct for each backend.
+ *
+ * 2. the given Xid is one of the cached subxact Xids in the PGPROC array.
+ * We can find this out cheaply too.
+ *
+ * 3. Search the SubTrans tree to find the Xid's topmost parent, and then
+ * see if that is running according to PGPROC. This is the slowest, but
+ * sadly it has to be done always if the other two failed, unless we see
+ * that the cached subxact sets are complete (none have overflowed).
+ *
+ * ProcArrayLock has to be held while we do 1 and 2. If we save the top Xids
+ * while doing 1, we can release the ProcArrayLock while we do 3. This buys
+ * back some concurrency (we can't retrieve the main Xids from PGPROC again
+ * anyway; see GetNewTransactionId).
+ */
+bool
+TransactionIdIsInProgress(TransactionId xid)
+{
+ bool result = false;
+ ProcArrayStruct *arrayP = procArray;
+ int i,
+ j;
+ int nxids = 0;
+ TransactionId *xids;
+ TransactionId topxid;
+ bool locked;
+
+ /*
+ * Don't bother checking a transaction older than RecentXmin; it
+ * could not possibly still be running.
+ */
+ if (TransactionIdPrecedes(xid, RecentXmin))
+ {
+ xc_by_recent_xmin_inc();
+ return false;
+ }
+
+ /* Get workspace to remember main XIDs in */
+ xids = (TransactionId *) palloc(sizeof(TransactionId) * arrayP->maxProcs);
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+ locked = true;
+
+ 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;
+
+ /*
+ * Step 1: check the main Xid
+ */
+ if (TransactionIdEquals(pxid, xid))
+ {
+ xc_by_main_xid_inc();
+ result = true;
+ goto result_known;
+ }
+
+ /*
+ * 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 = proc->subxids.nxids - 1; j >= 0; j--)
+ {
+ /* Fetch xid just once - see GetNewTransactionId */
+ TransactionId cxid = proc->subxids.xids[j];
+
+ if (TransactionIdEquals(cxid, xid))
+ {
+ xc_by_child_xid_inc();
+ result = true;
+ goto result_known;
+ }
+ }
+
+ /*
+ * Save the main Xid for step 3. 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 (proc->subxids.overflowed)
+ xids[nxids++] = pxid;
+ }
+
+ LWLockRelease(ProcArrayLock);
+ locked = false;
+
+ /*
+ * If none of the relevant caches overflowed, we know the Xid is not
+ * running without looking at pg_subtrans.
+ */
+ if (nxids == 0)
+ goto result_known;
+
+ /*
+ * Step 3: 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))
+ goto result_known;
+
+ /*
+ * It isn't aborted, so check whether the transaction tree it belongs
+ * to is still running (or, more precisely, whether it was running
+ * when this routine started -- note that we already released
+ * ProcArrayLock).
+ */
+ topxid = SubTransGetTopmostTransaction(xid);
+ Assert(TransactionIdIsValid(topxid));
+ if (!TransactionIdEquals(topxid, xid))
+ {
+ for (i = 0; i < nxids; i++)
+ {
+ if (TransactionIdEquals(xids[i], topxid))
+ {
+ result = true;
+ break;
+ }
+ }
+ }
+
+result_known:
+ if (locked)
+ LWLockRelease(ProcArrayLock);
+
+ pfree(xids);
+
+ return result;
+}
+
+/*
+ * GetOldestXmin -- returns oldest transaction that was running
+ * when any current transaction was started.
+ *
+ * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
+ * then only backends running in my own database are considered.
+ *
+ * This is used by VACUUM to decide which deleted tuples must be preserved
+ * in a table. allDbs = TRUE is needed for shared relations, but allDbs =
+ * FALSE is sufficient for non-shared relations, since only backends in my
+ * own database could ever see the tuples in them.
+ *
+ * This is also used to determine where to truncate pg_subtrans. allDbs
+ * must be TRUE for that case.
+ *
+ * Note: we include the currently running xids in the set of considered xids.
+ * This ensures that if a just-started xact has not yet set its snapshot,
+ * when it does set the snapshot it cannot set xmin less than what we compute.
+ */
+TransactionId
+GetOldestXmin(bool allDbs)
+{
+ ProcArrayStruct *arrayP = procArray;
+ TransactionId result;
+ int index;
+
+ /*
+ * Normally we start the min() calculation with our own XID. But if
+ * called by checkpointer, we will not be inside a transaction, so use
+ * next XID as starting point for min() calculation. (Note that if
+ * there are no xacts running at all, that will be the subtrans
+ * truncation point!)
+ */
+ if (IsTransactionState())
+ result = GetTopTransactionId();
+ else
+ result = ReadNewTransactionId();
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ PGPROC *proc = arrayP->procs[index];
+
+ if (allDbs || proc->databaseId == MyDatabaseId)
+ {
+ /* Fetch xid just once - see GetNewTransactionId */
+ TransactionId xid = proc->xid;
+
+ if (TransactionIdIsNormal(xid))
+ {
+ if (TransactionIdPrecedes(xid, result))
+ result = xid;
+ xid = proc->xmin;
+ if (TransactionIdIsNormal(xid))
+ if (TransactionIdPrecedes(xid, result))
+ result = xid;
+ }
+ }
+ }
+
+ LWLockRelease(ProcArrayLock);
+
+ return result;
+}
+
+/*----------
+ * GetSnapshotData -- returns information about running transactions.
+ *
+ * The returned snapshot includes xmin (lowest still-running xact ID),
+ * xmax (next xact ID to be assigned), and a list of running xact IDs
+ * in the range xmin <= xid < xmax. It is used as follows:
+ * All xact IDs < xmin are considered finished.
+ * All xact IDs >= xmax are considered still running.
+ * For an xact ID xmin <= xid < xmax, consult list to see whether
+ * it is considered running or not.
+ * This ensures that the set of transactions seen as "running" by the
+ * current xact will not change after it takes the snapshot.
+ *
+ * Note that only top-level XIDs are included in the snapshot. We can
+ * still apply the xmin and xmax limits to subtransaction XIDs, but we
+ * need to work a bit harder to see if XIDs in [xmin..xmax) are running.
+ *
+ * We also update the following backend-global variables:
+ * TransactionXmin: the oldest xmin of any snapshot in use in the
+ * current transaction (this is the same as MyProc->xmin). This
+ * is just the xmin computed for the first, serializable snapshot.
+ * RecentXmin: the xmin computed for the most recent snapshot. XIDs
+ * older than this are known not running any more.
+ * RecentGlobalXmin: the global xmin (oldest TransactionXmin across all
+ * running transactions). This is the same computation done by
+ * GetOldestXmin(TRUE).
+ *----------
+ */
+Snapshot
+GetSnapshotData(Snapshot snapshot, bool serializable)
+{
+ ProcArrayStruct *arrayP = procArray;
+ TransactionId xmin;
+ TransactionId xmax;
+ TransactionId globalxmin;
+ int index;
+ int count = 0;
+
+ Assert(snapshot != NULL);
+
+ /* Serializable snapshot must be computed before any other... */
+ Assert(serializable ?
+ !TransactionIdIsValid(MyProc->xmin) :
+ TransactionIdIsValid(MyProc->xmin));
+
+ /*
+ * Allocating space for MaxBackends xids is usually overkill;
+ * lastBackend would be sufficient. But it seems better to do the
+ * malloc while not holding the lock, so we can't look at lastBackend.
+ *
+ * This does open a possibility for avoiding repeated malloc/free: since
+ * MaxBackends 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.)
+ */
+ if (snapshot->xip == NULL)
+ {
+ /*
+ * First call for this snapshot
+ */
+ snapshot->xip = (TransactionId *)
+ malloc(MaxBackends * sizeof(TransactionId));
+ if (snapshot->xip == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_OUT_OF_MEMORY),
+ errmsg("out of memory")));
+ }
+
+ globalxmin = xmin = GetTopTransactionId();
+
+ /*
+ * If we are going to set MyProc->xmin then we'd better get exclusive
+ * lock; if not, this is a read-only operation so it can be shared.
+ */
+ LWLockAcquire(ProcArrayLock, serializable ? LW_EXCLUSIVE : LW_SHARED);
+
+ /*--------------------
+ * Unfortunately, we have to call ReadNewTransactionId() after acquiring
+ * ProcArrayLock above. It's not good because ReadNewTransactionId() does
+ * LWLockAcquire(XidGenLock), but *necessary*. We need to be sure that
+ * no transactions exit the set of currently-running transactions
+ * between the time we fetch xmax and the time we finish building our
+ * snapshot. Otherwise we could have a situation like this:
+ *
+ * 1. Tx Old is running (in Read Committed mode).
+ * 2. Tx S reads new transaction ID into xmax, then
+ * is swapped out before acquiring ProcArrayLock.
+ * 3. Tx New gets new transaction ID (>= S' xmax),
+ * makes changes and commits.
+ * 4. Tx Old changes some row R changed by Tx New and commits.
+ * 5. Tx S finishes getting its snapshot data. It sees Tx Old as
+ * done, but sees Tx New as still running (since New >= xmax).
+ *
+ * Now S will see R changed by both Tx Old and Tx New, *but* does not
+ * see other changes made by Tx New. If S is supposed to be in
+ * Serializable mode, this is wrong.
+ *
+ * By locking ProcArrayLock before we read xmax, we ensure that TX Old
+ * cannot exit the set of running transactions seen by Tx S. Therefore
+ * both Old and New will be seen as still running => no inconsistency.
+ *--------------------
+ */
+
+ xmax = ReadNewTransactionId();
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ PGPROC *proc = arrayP->procs[index];
+
+ /* Fetch xid just once - see GetNewTransactionId */
+ TransactionId xid = proc->xid;
+
+ /*
+ * Ignore my own proc (dealt with my xid above), procs not
+ * running a transaction, and xacts started since we read the
+ * next transaction ID. There's no need to store XIDs above
+ * what we got from ReadNewTransactionId, since we'll treat
+ * them as running anyway. We also assume that such xacts
+ * can't compute an xmin older than ours, so they needn't be
+ * considered in computing globalxmin.
+ */
+ if (proc == MyProc ||
+ !TransactionIdIsNormal(xid) ||
+ TransactionIdFollowsOrEquals(xid, xmax))
+ continue;
+
+ if (TransactionIdPrecedes(xid, xmin))
+ xmin = xid;
+ snapshot->xip[count] = xid;
+ count++;
+
+ /* Update globalxmin to be the smallest valid xmin */
+ xid = proc->xmin;
+ if (TransactionIdIsNormal(xid))
+ if (TransactionIdPrecedes(xid, globalxmin))
+ globalxmin = xid;
+ }
+
+ if (serializable)
+ MyProc->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;
+ RecentXmin = xmin;
+
+ snapshot->xmin = xmin;
+ snapshot->xmax = xmax;
+ snapshot->xcnt = count;
+
+ snapshot->curcid = GetCurrentCommandId();
+
+ return snapshot;
+}
+
+/*
+ * DatabaseHasActiveBackends -- are there any backends running in the given DB
+ *
+ * If 'ignoreMyself' is TRUE, ignore this particular backend while checking
+ * for backends in the target database.
+ *
+ * This function is used to interlock DROP DATABASE against there being
+ * any active backends in the target DB --- dropping the DB while active
+ * backends remain would be a Bad Thing. Note that we cannot detect here
+ * the possibility of a newly-started backend that is trying to connect
+ * to the doomed database, so additional interlocking is needed during
+ * backend startup.
+ */
+bool
+DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
+{
+ bool result = false;
+ ProcArrayStruct *arrayP = procArray;
+ int index;
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ PGPROC *proc = arrayP->procs[index];
+
+ if (proc->databaseId == databaseId)
+ {
+ if (ignoreMyself && proc == MyProc)
+ continue;
+
+ result = true;
+ break;
+ }
+ }
+
+ LWLockRelease(ProcArrayLock);
+
+ return result;
+}
+
+/*
+ * BackendPidGetProc -- get a backend's PGPROC given its PID
+ */
+struct PGPROC *
+BackendPidGetProc(int pid)
+{
+ PGPROC *result = NULL;
+ ProcArrayStruct *arrayP = procArray;
+ int index;
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ PGPROC *proc = arrayP->procs[index];
+
+ if (proc->pid == pid)
+ {
+ result = proc;
+ break;
+ }
+ }
+
+ LWLockRelease(ProcArrayLock);
+
+ return result;
+}
+
+/*
+ * IsBackendPid -- is a given pid a running backend
+ */
+bool
+IsBackendPid(int pid)
+{
+ return (BackendPidGetProc(pid) != NULL);
+}
+
+/*
+ * CountActiveBackends --- count backends (other than myself) that are in
+ * 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.
+ */
+int
+CountActiveBackends(void)
+{
+ ProcArrayStruct *arrayP = procArray;
+ int count = 0;
+ int index;
+
+ /*
+ * 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,
+ * it should be OK. The result is only used for heuristic purposes
+ * anyway...
+ */
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ PGPROC *proc = arrayP->procs[index];
+
+ if (proc == MyProc)
+ continue; /* do not count myself */
+ if (proc->logRec.xrecoff == 0)
+ continue; /* do not count if not in a transaction */
+ if (proc->waitLock != NULL)
+ continue; /* do not count if blocked on a lock */
+ count++;
+ }
+
+ 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 { \
+ MyProc->subxids.xids[i] = MyProc->subxids.xids[MyProc->subxids.nxids - 1]; \
+ MyProc->subxids.nxids--; \
+ } while (0)
+
+/*
+ * XidCacheRemoveRunningXids
+ *
+ * Remove a bunch of TransactionIds from the list of known-running
+ * subtransactions for my backend. Both the specified xid and those in
+ * the xids[] array (of length nxids) are removed from the subxids cache.
+ */
+void
+XidCacheRemoveRunningXids(TransactionId xid, int nxids, TransactionId *xids)
+{
+ int i,
+ j;
+
+ Assert(!TransactionIdEquals(xid, InvalidTransactionId));
+
+ /*
+ * We must hold ProcArrayLock exclusively in order to remove transactions
+ * from the PGPROC array. (See notes in GetSnapshotData.) 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 = MyProc->subxids.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 && !MyProc->subxids.overflowed)
+ elog(WARNING, "did not find subXID %u in MyProc", anxid);
+ }
+
+ for (j = MyProc->subxids.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 && !MyProc->subxids.overflowed)
+ elog(WARNING, "did not find subXID %u in MyProc", xid);
+
+ LWLockRelease(ProcArrayLock);
+}
+
+#ifdef XIDCACHE_DEBUG
+
+/*
+ * Print stats about effectiveness of XID cache
+ */
+static void
+DisplayXidCache(void)
+{
+ fprintf(stderr,
+ "XidCache: xmin: %ld, mainxid: %ld, childxid: %ld, slow: %ld\n",
+ xc_by_recent_xmin,
+ xc_by_main_xid,
+ xc_by_child_xid,
+ xc_slow_answer);
+}
+
+#endif /* XIDCACHE_DEBUG */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.75 2004/12/31 22:00:56 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.76 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include
-#include "access/subtrans.h"
-#include "access/transam.h"
+#include "access/xact.h"
#include "commands/async.h"
+#include "miscadmin.h"
+#include "storage/backendid.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "storage/sinval.h"
#include "storage/sinvaladt.h"
#include "utils/inval.h"
-#include "utils/tqual.h"
-#include "miscadmin.h"
-
-
-#ifdef XIDCACHE_DEBUG
-
-/* counters for XidCache measurement */
-static long xc_by_recent_xmin = 0;
-static long xc_by_main_xid = 0;
-static long xc_by_child_xid = 0;
-static long xc_slow_answer = 0;
-#define xc_by_recent_xmin_inc() (xc_by_recent_xmin++)
-#define xc_by_main_xid_inc() (xc_by_main_xid++)
-#define xc_by_child_xid_inc() (xc_by_child_xid++)
-#define xc_slow_answer_inc() (xc_slow_answer++)
-
-static void DisplayXidCache(int code, Datum arg);
-
-#else /* !XIDCACHE_DEBUG */
-
-#define xc_by_recent_xmin_inc() ((void) 0)
-#define xc_by_main_xid_inc() ((void) 0)
-#define xc_by_child_xid_inc() ((void) 0)
-#define xc_slow_answer_inc() ((void) 0)
-#endif /* XIDCACHE_DEBUG */
/*
* Because backends sitting idle will not be reading sinval events, we
ereport(FATAL,
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
-
-#ifdef XIDCACHE_DEBUG
- on_proc_exit(DisplayXidCache, (Datum) 0);
-#endif /* XIDCACHE_DEBUG */
}
/*
* this is not exactly the normal (read-only) interpretation of a
* shared lock! Look closely at the interactions before allowing
* SInvalLock to be grabbed in shared mode for any other reason!
- *
- * The routines later in this file that use shared mode are okay with
- * this, because they aren't looking at the ProcState fields
- * associated with SI message transfer; they only use the
- * ProcState array as an easy way to find all the PGPROC
- * structures.
*/
LWLockAcquire(SInvalLock, LW_SHARED);
getResult = SIGetDataEntry(shmInvalBuffer, MyBackendId, &data);
if (notify_enabled)
EnableNotifyInterrupt();
}
-
-
-/****************************************************************************/
-/* Functions that need to scan the PGPROC structures of all running backends. */
-/* It's a bit strange to keep these in sinval.c, since they don't have any */
-/* direct relationship to shared-cache invalidation. But the procState */
-/* array in the SI segment is the only place in the system where we have */
-/* an array of per-backend data, so it is the most convenient place to keep */
-/* pointers to the backends' PGPROC structures. We used to implement these */
-/* functions with a slow, ugly search through the ShmemIndex hash table --- */
-/* now they are simple loops over the SI ProcState array. */
-/****************************************************************************/
-
-
-/*
- * DatabaseHasActiveBackends -- are there any backends running in the given DB
- *
- * If 'ignoreMyself' is TRUE, ignore this particular backend while checking
- * for backends in the target database.
- *
- * This function is used to interlock DROP DATABASE against there being
- * any active backends in the target DB --- dropping the DB while active
- * backends remain would be a Bad Thing. Note that we cannot detect here
- * the possibility of a newly-started backend that is trying to connect
- * to the doomed database, so additional interlocking is needed during
- * backend startup.
- */
-bool
-DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
-{
- bool result = false;
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int index;
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (proc->databaseId == databaseId)
- {
- if (ignoreMyself && proc == MyProc)
- continue;
-
- result = true;
- break;
- }
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return result;
-}
-
-/*
- * IsBackendPid -- is a given pid a running backend
- */
-bool
-IsBackendPid(int pid)
-{
- bool result = false;
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int index;
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (proc->pid == pid)
- {
- result = true;
- break;
- }
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return result;
-}
-
-/*
- * TransactionIdIsInProgress -- is given transaction running in some backend
- *
- * There are three possibilities for finding a running transaction:
- *
- * 1. the given Xid is a main transaction Id. We will find this out cheaply
- * by looking at the PGPROC struct for each backend.
- *
- * 2. the given Xid is one of the cached subxact Xids in the PGPROC array.
- * We can find this out cheaply too.
- *
- * 3. Search the SubTrans tree to find the Xid's topmost parent, and then
- * see if that is running according to PGPROC. This is the slowest, but
- * sadly it has to be done always if the other two failed, unless we see
- * that the cached subxact sets are complete (none have overflowed).
- *
- * SInvalLock has to be held while we do 1 and 2. If we save the top Xids
- * while doing 1, we can release the SInvalLock while we do 3. This buys back
- * some concurrency (we can't retrieve the main Xids from PGPROC again anyway;
- * see GetNewTransactionId).
- */
-bool
-TransactionIdIsInProgress(TransactionId xid)
-{
- bool result = false;
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int i,
- j;
- int nxids = 0;
- TransactionId *xids;
- TransactionId topxid;
- bool locked;
-
- /*
- * Don't bother checking a transaction older than RecentXmin; it
- * could not possibly still be running.
- */
- if (TransactionIdPrecedes(xid, RecentXmin))
- {
- xc_by_recent_xmin_inc();
- return false;
- }
-
- /* Get workspace to remember main XIDs in */
- xids = (TransactionId *) palloc(sizeof(TransactionId) * segP->maxBackends);
-
- LWLockAcquire(SInvalLock, LW_SHARED);
- locked = true;
-
- for (i = 0; i < segP->lastBackend; i++)
- {
- SHMEM_OFFSET pOffset = stateP[i].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId pxid = proc->xid;
-
- if (!TransactionIdIsValid(pxid))
- continue;
-
- /*
- * Step 1: check the main Xid
- */
- if (TransactionIdEquals(pxid, xid))
- {
- xc_by_main_xid_inc();
- result = true;
- goto result_known;
- }
-
- /*
- * 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 = proc->subxids.nxids - 1; j >= 0; j--)
- {
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId cxid = proc->subxids.xids[j];
-
- if (TransactionIdEquals(cxid, xid))
- {
- xc_by_child_xid_inc();
- result = true;
- goto result_known;
- }
- }
-
- /*
- * Save the main Xid for step 3. 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 SInvalLock. So we can't
- * miss an Xid that we need to worry about.)
- */
- if (proc->subxids.overflowed)
- xids[nxids++] = pxid;
- }
- }
-
- LWLockRelease(SInvalLock);
- locked = false;
-
- /*
- * If none of the relevant caches overflowed, we know the Xid is not
- * running without looking at pg_subtrans.
- */
- if (nxids == 0)
- goto result_known;
-
- /*
- * Step 3: 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))
- goto result_known;
-
- /*
- * It isn't aborted, so check whether the transaction tree it belongs
- * to is still running (or, more precisely, whether it was running
- * when this routine started -- note that we already released
- * SInvalLock).
- */
- topxid = SubTransGetTopmostTransaction(xid);
- Assert(TransactionIdIsValid(topxid));
- if (!TransactionIdEquals(topxid, xid))
- {
- for (i = 0; i < nxids; i++)
- {
- if (TransactionIdEquals(xids[i], topxid))
- {
- result = true;
- break;
- }
- }
- }
-
-result_known:
- if (locked)
- LWLockRelease(SInvalLock);
-
- pfree(xids);
-
- return result;
-}
-
-/*
- * GetOldestXmin -- returns oldest transaction that was running
- * when any current transaction was started.
- *
- * If allDbs is TRUE then all backends are considered; if allDbs is FALSE
- * then only backends running in my own database are considered.
- *
- * This is used by VACUUM to decide which deleted tuples must be preserved
- * in a table. allDbs = TRUE is needed for shared relations, but allDbs =
- * FALSE is sufficient for non-shared relations, since only backends in my
- * own database could ever see the tuples in them.
- *
- * This is also used to determine where to truncate pg_subtrans. allDbs
- * must be TRUE for that case.
- *
- * Note: we include the currently running xids in the set of considered xids.
- * This ensures that if a just-started xact has not yet set its snapshot,
- * when it does set the snapshot it cannot set xmin less than what we compute.
- */
-TransactionId
-GetOldestXmin(bool allDbs)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- TransactionId result;
- int index;
-
- /*
- * Normally we start the min() calculation with our own XID. But if
- * called by checkpointer, we will not be inside a transaction, so use
- * next XID as starting point for min() calculation. (Note that if
- * there are no xacts running at all, that will be the subtrans
- * truncation point!)
- */
- if (IsTransactionState())
- result = GetTopTransactionId();
- else
- result = ReadNewTransactionId();
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (allDbs || proc->databaseId == MyDatabaseId)
- {
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId xid = proc->xid;
-
- if (TransactionIdIsNormal(xid))
- {
- if (TransactionIdPrecedes(xid, result))
- result = xid;
- xid = proc->xmin;
- if (TransactionIdIsNormal(xid))
- if (TransactionIdPrecedes(xid, result))
- result = xid;
- }
- }
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return result;
-}
-
-/*----------
- * GetSnapshotData -- returns information about running transactions.
- *
- * The returned snapshot includes xmin (lowest still-running xact ID),
- * xmax (next xact ID to be assigned), and a list of running xact IDs
- * in the range xmin <= xid < xmax. It is used as follows:
- * All xact IDs < xmin are considered finished.
- * All xact IDs >= xmax are considered still running.
- * For an xact ID xmin <= xid < xmax, consult list to see whether
- * it is considered running or not.
- * This ensures that the set of transactions seen as "running" by the
- * current xact will not change after it takes the snapshot.
- *
- * Note that only top-level XIDs are included in the snapshot. We can
- * still apply the xmin and xmax limits to subtransaction XIDs, but we
- * need to work a bit harder to see if XIDs in [xmin..xmax) are running.
- *
- * We also update the following backend-global variables:
- * TransactionXmin: the oldest xmin of any snapshot in use in the
- * current transaction (this is the same as MyProc->xmin). This
- * is just the xmin computed for the first, serializable snapshot.
- * RecentXmin: the xmin computed for the most recent snapshot. XIDs
- * older than this are known not running any more.
- * RecentGlobalXmin: the global xmin (oldest TransactionXmin across all
- * running transactions). This is the same computation done by
- * GetOldestXmin(TRUE).
- *----------
- */
-Snapshot
-GetSnapshotData(Snapshot snapshot, bool serializable)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- TransactionId xmin;
- TransactionId xmax;
- TransactionId globalxmin;
- int index;
- int count = 0;
-
- Assert(snapshot != NULL);
-
- /* Serializable snapshot must be computed before any other... */
- Assert(serializable ?
- !TransactionIdIsValid(MyProc->xmin) :
- TransactionIdIsValid(MyProc->xmin));
-
- /*
- * Allocating space for MaxBackends xids is usually overkill;
- * lastBackend would be sufficient. But it seems better to do the
- * malloc while not holding the lock, so we can't look at lastBackend.
- *
- * This does open a possibility for avoiding repeated malloc/free: since
- * MaxBackends 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.)
- */
- if (snapshot->xip == NULL)
- {
- /*
- * First call for this snapshot
- */
- snapshot->xip = (TransactionId *)
- malloc(MaxBackends * sizeof(TransactionId));
- if (snapshot->xip == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_OUT_OF_MEMORY),
- errmsg("out of memory")));
- }
-
- globalxmin = xmin = GetTopTransactionId();
-
- /*
- * If we are going to set MyProc->xmin then we'd better get exclusive
- * lock; if not, this is a read-only operation so it can be shared.
- */
- LWLockAcquire(SInvalLock, serializable ? LW_EXCLUSIVE : LW_SHARED);
-
- /*--------------------
- * Unfortunately, we have to call ReadNewTransactionId() after acquiring
- * SInvalLock above. It's not good because ReadNewTransactionId() does
- * LWLockAcquire(XidGenLock), but *necessary*. We need to be sure that
- * no transactions exit the set of currently-running transactions
- * between the time we fetch xmax and the time we finish building our
- * snapshot. Otherwise we could have a situation like this:
- *
- * 1. Tx Old is running (in Read Committed mode).
- * 2. Tx S reads new transaction ID into xmax, then
- * is swapped out before acquiring SInvalLock.
- * 3. Tx New gets new transaction ID (>= S' xmax),
- * makes changes and commits.
- * 4. Tx Old changes some row R changed by Tx New and commits.
- * 5. Tx S finishes getting its snapshot data. It sees Tx Old as
- * done, but sees Tx New as still running (since New >= xmax).
- *
- * Now S will see R changed by both Tx Old and Tx New, *but* does not
- * see other changes made by Tx New. If S is supposed to be in
- * Serializable mode, this is wrong.
- *
- * By locking SInvalLock before we read xmax, we ensure that TX Old
- * cannot exit the set of running transactions seen by Tx S. Therefore
- * both Old and New will be seen as still running => no inconsistency.
- *--------------------
- */
-
- xmax = ReadNewTransactionId();
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId xid = proc->xid;
-
- /*
- * Ignore my own proc (dealt with my xid above), procs not
- * running a transaction, and xacts started since we read the
- * next transaction ID. There's no need to store XIDs above
- * what we got from ReadNewTransactionId, since we'll treat
- * them as running anyway. We also assume that such xacts
- * can't compute an xmin older than ours, so they needn't be
- * considered in computing globalxmin.
- */
- if (proc == MyProc ||
- !TransactionIdIsNormal(xid) ||
- TransactionIdFollowsOrEquals(xid, xmax))
- continue;
-
- if (TransactionIdPrecedes(xid, xmin))
- xmin = xid;
- snapshot->xip[count] = xid;
- count++;
-
- /* Update globalxmin to be the smallest valid xmin */
- xid = proc->xmin;
- if (TransactionIdIsNormal(xid))
- if (TransactionIdPrecedes(xid, globalxmin))
- globalxmin = xid;
- }
- }
-
- if (serializable)
- MyProc->xmin = TransactionXmin = xmin;
-
- LWLockRelease(SInvalLock);
-
- /*
- * 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;
- RecentXmin = xmin;
-
- snapshot->xmin = xmin;
- snapshot->xmax = xmax;
- snapshot->xcnt = count;
-
- snapshot->curcid = GetCurrentCommandId();
-
- return snapshot;
-}
-
-/*
- * CountActiveBackends --- count backends (other than myself) that are in
- * 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.
- */
-int
-CountActiveBackends(void)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- int count = 0;
- int index;
-
- /*
- * Note: for speed, we don't acquire SInvalLock. This is a little bit
- * bogus, but since we are only testing xrecoff for zero or nonzero,
- * it should be OK. The result is only used for heuristic purposes
- * anyway...
- */
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (proc == MyProc)
- continue; /* do not count myself */
- if (proc->logRec.xrecoff == 0)
- continue; /* do not count if not in a transaction */
- if (proc->waitLock != NULL)
- continue; /* do not count if blocked on a lock */
- count++;
- }
- }
-
- return count;
-}
-
-#ifdef NOT_USED
-/*
- * GetUndoRecPtr -- returns oldest PGPROC->logRec.
- */
-XLogRecPtr
-GetUndoRecPtr(void)
-{
- SISeg *segP = shmInvalBuffer;
- ProcState *stateP = segP->procState;
- XLogRecPtr urec = {0, 0};
- XLogRecPtr tempr;
- int index;
-
- LWLockAcquire(SInvalLock, LW_SHARED);
-
- for (index = 0; index < segP->lastBackend; index++)
- {
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- tempr = proc->logRec;
- if (tempr.xrecoff == 0)
- continue;
- if (urec.xrecoff != 0 && XLByteLT(urec, tempr))
- continue;
- urec = tempr;
- }
- }
-
- LWLockRelease(SInvalLock);
-
- return (urec);
-}
-#endif /* NOT_USED */
-
-/*
- * BackendIdGetProc - given a BackendId, find its PGPROC structure
- *
- * This is a trivial lookup in the ProcState array. We assume that the caller
- * knows that the backend isn't going to go away, so we do not bother with
- * locking.
- */
-struct PGPROC *
-BackendIdGetProc(BackendId procId)
-{
- SISeg *segP = shmInvalBuffer;
-
- if (procId > 0 && procId <= segP->lastBackend)
- {
- ProcState *stateP = &segP->procState[procId - 1];
- SHMEM_OFFSET pOffset = stateP->procStruct;
-
- if (pOffset != INVALID_OFFSET)
- {
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- return proc;
- }
- }
-
- return NULL;
-}
-
-/*
- * CountEmptyBackendSlots - count empty slots in backend process table
- *
- * We don't actually need to count, since sinvaladt.c maintains a
- * freeBackends counter in the SI segment.
- *
- * 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(SInvalLock, LW_SHARED);
-
- count = shmInvalBuffer->freeBackends;
-
- LWLockRelease(SInvalLock);
-
- return count;
-}
-
-#define XidCacheRemove(i) \
- do { \
- MyProc->subxids.xids[i] = MyProc->subxids.xids[MyProc->subxids.nxids - 1]; \
- MyProc->subxids.nxids--; \
- } while (0)
-
-/*
- * XidCacheRemoveRunningXids
- *
- * Remove a bunch of TransactionIds from the list of known-running
- * subtransactions for my backend. Both the specified xid and those in
- * the xids[] array (of length nxids) are removed from the subxids cache.
- */
-void
-XidCacheRemoveRunningXids(TransactionId xid, int nxids, TransactionId *xids)
-{
- int i,
- j;
-
- Assert(!TransactionIdEquals(xid, InvalidTransactionId));
-
- /*
- * We must hold SInvalLock exclusively in order to remove transactions
- * from the PGPROC array. (See notes in GetSnapshotData.) 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(SInvalLock, 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 = MyProc->subxids.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 && !MyProc->subxids.overflowed)
- elog(WARNING, "did not find subXID %u in MyProc", anxid);
- }
-
- for (j = MyProc->subxids.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 && !MyProc->subxids.overflowed)
- elog(WARNING, "did not find subXID %u in MyProc", xid);
-
- LWLockRelease(SInvalLock);
-}
-
-#ifdef XIDCACHE_DEBUG
-
-/*
- * on_proc_exit hook to print stats about effectiveness of XID cache
- */
-static void
-DisplayXidCache(int code, Datum arg)
-{
- fprintf(stderr,
- "XidCache: xmin: %ld, mainxid: %ld, childxid: %ld, slow: %ld\n",
- xc_by_recent_xmin,
- xc_by_main_xid,
- xc_by_child_xid,
- xc_slow_answer);
-}
-
-#endif /* XIDCACHE_DEBUG */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.58 2004/12/31 22:00:56 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/sinvaladt.c,v 1.59 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "miscadmin.h"
#include "storage/backendid.h"
#include "storage/ipc.h"
+#include "storage/lwlock.h"
#include "storage/pmsignal.h"
-#include "storage/proc.h"
+#include "storage/shmem.h"
#include "storage/sinvaladt.h"
+
SISeg *shmInvalBuffer;
static void CleanupInvalidationState(int status, Datum arg);
{
segP->procState[i].nextMsgNum = -1; /* inactive */
segP->procState[i].resetState = false;
- segP->procState[i].procStruct = INVALID_OFFSET;
}
}
/* mark myself active, with all extant messages already read */
stateP->nextMsgNum = segP->maxMsgNum;
stateP->resetState = false;
- stateP->procStruct = MAKE_OFFSET(MyProc);
/* register exit routine to mark my entry inactive at exit */
on_shmem_exit(CleanupInvalidationState, PointerGetDatum(segP));
/* Mark myself inactive */
segP->procState[MyBackendId - 1].nextMsgNum = -1;
segP->procState[MyBackendId - 1].resetState = false;
- segP->procState[MyBackendId - 1].procStruct = INVALID_OFFSET;
/* Recompute index of last active backend */
for (i = segP->lastBackend; i > 0; i--)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.73 2005/04/30 19:03:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.74 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "utils/inval.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.157 2005/04/15 04:18:10 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.158 2005/05/19 21:35:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "storage/bufmgr.h"
#include "storage/ipc.h"
#include "storage/proc.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "storage/spin.h"
/*
* InitProcGlobal -
- * initializes the global process table. We put it here so that
- * the postmaster can do this initialization.
+ * Initialize the global process table during postmaster startup.
*
* We also create all the per-process semaphores we will need to support
* the requested number of backends. We used to allocate semaphores
MyProc->waitProcLock = NULL;
SHMQueueInit(&(MyProc->procLocks));
+ /*
+ * Add our PGPROC to the PGPROC array in shared memory.
+ */
+ ProcArrayAddMyself();
+
/*
* Arrange to clean up at backend exit.
*/
LockReleaseAll(USER_LOCKMETHOD, true);
#endif
+ /* Remove our PGPROC from the PGPROC array in shared memory */
+ ProcArrayRemoveMyself();
+
SpinLockAcquire(ProcStructLock);
/* Return PGPROC structure (and semaphore) to freelist */
}
/*
- * ProcSendSignal - send a signal to a backend identified by BackendId
+ * ProcSendSignal - send a signal to a backend identified by PID
*/
void
-ProcSendSignal(BackendId procId)
+ProcSendSignal(int pid)
{
- PGPROC *proc = BackendIdGetProc(procId);
+ PGPROC *proc = BackendPidGetProc(pid);
if (proc != NULL)
PGSemaphoreUnlock(&proc->sem);
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.42 2005/05/10 22:27:30 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.43 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "commands/dbcommands.h"
#include "miscadmin.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "storage/fd.h"
#include "utils/builtins.h"
#include "funcapi.h"
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.146 2005/05/05 19:53:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.147 2005/05/19 21:35:47 tgl Exp $
*
*
*-------------------------------------------------------------------------
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "postmaster/postmaster.h"
+#include "storage/backendid.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/proc.h"
+#include "storage/procarray.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/flatfiles.h"
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.88 2005/05/07 21:22:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.89 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/multixact.h"
#include "access/subtrans.h"
-#include "storage/sinval.h"
+#include "storage/procarray.h"
#include "utils/tqual.h"
/*
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.77 2005/03/04 20:21:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.78 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef BUFMGR_INTERNALS_H
#define BUFMGR_INTERNALS_H
-#include "storage/backendid.h"
#include "storage/buf.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
* BufferDesc -- shared descriptor/state data for a single shared buffer.
*
* Note: buf_hdr_lock must be held to examine or change the tag, flags,
- * usage_count, refcount, or wait_backend_id fields. buf_id field never
+ * usage_count, refcount, or wait_backend_pid fields. buf_id field never
* changes after initialization, so does not need locking. freeNext is
* protected by the BufFreelistLock not buf_hdr_lock. The LWLocks can take
* care of themselves. The buf_hdr_lock is *not* used to control access to
*
* We can't physically remove items from a disk page if another backend has
* the buffer pinned. Hence, a backend may need to wait for all other pins
- * to go away. This is signaled by storing its own backend ID into
- * wait_backend_id and setting flag bit BM_PIN_COUNT_WAITER. At present,
+ * to go away. This is signaled by storing its own PID into
+ * wait_backend_pid and setting flag bit BM_PIN_COUNT_WAITER. At present,
* there can be only one such waiter per buffer.
*
* We use this same struct for local buffer headers, but the lock fields
BufFlags flags; /* see bit definitions above */
uint16 usage_count; /* usage counter for clock sweep code */
unsigned refcount; /* # of backends holding pins on buffer */
- BackendId wait_backend_id; /* backend ID of pin-count waiter */
+ int wait_backend_pid; /* backend PID of pin-count waiter */
slock_t buf_hdr_lock; /* protects the above fields */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.18 2005/04/28 21:47:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.19 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
LockMgrLock,
OidGenLock,
XidGenLock,
+ ProcArrayLock,
SInvalLock,
FreeSpaceLock,
MMCacheLock,
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.77 2004/12/31 22:03:42 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.78 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define _PROC_H_
#include "access/xlog.h"
-#include "storage/backendid.h"
#include "storage/lock.h"
#include "storage/pg_sema.h"
extern void ProcWaitForSignal(void);
extern void ProcCancelWaitForSignal(void);
-extern void ProcSendSignal(BackendId procId);
+extern void ProcSendSignal(int pid);
extern bool enable_sig_alarm(int delayms, bool is_statement_timeout);
extern bool disable_sig_alarm(bool is_statement_timeout);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * procarray.h
+ * POSTGRES process array definitions.
+ *
+ *
+ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.1 2005/05/19 21:35:47 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PROCARRAY_H
+#define PROCARRAY_H
+
+extern int ProcArrayShmemSize(int maxBackends);
+extern void CreateSharedProcArray(int maxBackends);
+extern void ProcArrayAddMyself(void);
+extern void ProcArrayRemoveMyself(void);
+
+extern bool TransactionIdIsInProgress(TransactionId xid);
+extern TransactionId GetOldestXmin(bool allDbs);
+
+/* Use "struct PGPROC", not PGPROC, to avoid including proc.h here */
+extern struct PGPROC *BackendPidGetProc(int pid);
+extern bool IsBackendPid(int pid);
+extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself);
+
+extern int CountActiveBackends(void);
+extern int CountEmptyBackendSlots(void);
+
+extern void XidCacheRemoveRunningXids(TransactionId xid,
+ int nxids, TransactionId *xids);
+
+#endif /* PROCARRAY_H */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.40 2005/01/10 21:57:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.41 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef SINVAL_H
#define SINVAL_H
-#include "storage/backendid.h"
#include "storage/itemptr.h"
#include "storage/relfilenode.h"
extern int SInvalShmemSize(int maxBackends);
extern void CreateSharedInvalidationState(int maxBackends);
extern void InitBackendSharedInvalidationState(void);
+
extern void SendSharedInvalidMessage(SharedInvalidationMessage *msg);
extern void ReceiveSharedInvalidMessages(
void (*invalFunction) (SharedInvalidationMessage *msg),
void (*resetFunction) (void));
-extern bool DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself);
-extern bool TransactionIdIsInProgress(TransactionId xid);
-extern bool IsBackendPid(int pid);
-extern TransactionId GetOldestXmin(bool allDbs);
-extern int CountActiveBackends(void);
-extern int CountEmptyBackendSlots(void);
-
-/* Use "struct PGPROC", not PGPROC, to avoid including proc.h here */
-extern struct PGPROC *BackendIdGetProc(BackendId procId);
-
-extern void XidCacheRemoveRunningXids(TransactionId xid,
- int nxids, TransactionId *xids);
-
/* signal handler for catchup events (SIGUSR1) */
extern void CatchupInterruptHandler(SIGNAL_ARGS);
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/sinvaladt.h,v 1.37 2004/12/31 22:03:42 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/storage/sinvaladt.h,v 1.38 2005/05/19 21:35:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef SINVALADT_H
#define SINVALADT_H
-#include "storage/shmem.h"
#include "storage/sinval.h"
+
/*
* The shared cache invalidation manager is responsible for transmitting
* invalidation messages between backends. Any message sent by any backend
/* nextMsgNum is -1 in an inactive ProcState array entry. */
int nextMsgNum; /* next message number to read, or -1 */
bool resetState; /* true, if backend has to reset its state */
- SHMEM_OFFSET procStruct; /* location of backend's PGPROC struct */
} ProcState;
/* Shared cache invalidation memory segment */
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/tqual.h,v 1.56 2005/03/20 23:40:34 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/utils/tqual.h,v 1.57 2005/05/19 21:35:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern void FreeSnapshot(Snapshot snapshot);
extern void FreeXactSnapshot(void);
-/* in sinval.c; declared here to avoid including tqual.h in sinval.h: */
+/* in procarray.c; declared here to avoid including tqual.h in procarray.h: */
extern Snapshot GetSnapshotData(Snapshot snapshot, bool serializable);
#endif /* TQUAL_H */