aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/varsup.c49
-rw-r--r--src/backend/access/transam/xact.c203
-rw-r--r--src/backend/catalog/index.c68
-rw-r--r--src/backend/storage/ipc/sinval.c302
-rw-r--r--src/backend/tcop/utility.c5
-rw-r--r--src/backend/utils/init/miscinit.c20
-rw-r--r--src/include/access/htup.h41
-rw-r--r--src/include/access/xact.h19
-rw-r--r--src/include/miscadmin.h3
-rw-r--r--src/include/storage/proc.h23
-rw-r--r--src/include/storage/sinval.h5
-rw-r--r--src/pl/plpgsql/src/pl_exec.c52
-rw-r--r--src/pl/plpgsql/src/pl_handler.c4
-rw-r--r--src/pl/plpgsql/src/plpgsql.h4
14 files changed, 523 insertions, 275 deletions
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index 9d3b0b323aa..81b60c9fda6 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -6,7 +6,7 @@
* Copyright (c) 2000-2003, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.56 2004/07/01 00:49:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.57 2004/08/01 17:32:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -68,10 +68,10 @@ GetNewTransactionId(bool isSubXact)
TransactionIdAdvance(ShmemVariableCache->nextXid);
/*
- * Must set MyProc->xid before releasing XidGenLock. This ensures
- * that when GetSnapshotData calls ReadNewTransactionId, all active
- * XIDs before the returned value of nextXid are already present in
- * the shared PGPROC array. Else we have a race condition.
+ * We must store the new XID into the shared PGPROC array before releasing
+ * XidGenLock. This ensures that when GetSnapshotData calls
+ * ReadNewTransactionId, all active XIDs before the returned value of
+ * nextXid are already present in PGPROC. Else we have a race condition.
*
* XXX by storing xid into MyProc without acquiring SInvalLock, we are
* relying on fetch/store of an xid to be atomic, else other backends
@@ -82,16 +82,41 @@ GetNewTransactionId(bool isSubXact)
* the value only once, rather than assume they can read it multiple
* times and get the same answer each time.
*
+ * The same comments apply to the subxact xid count and overflow fields.
+ *
* A solution to the atomic-store problem would be to give each PGPROC
- * its own spinlock used only for fetching/storing that PGPROC's xid.
- * (SInvalLock would then mean primarily that PGPROCs couldn't be added/
- * removed while holding the lock.)
+ * 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.)
*
- * We don't want a subtransaction to update the stored Xid; we'll check
- * if a transaction Xid is a running subxact by checking pg_subtrans.
+ * If there's no room to fit a subtransaction XID into PGPROC, set the
+ * cache-overflowed flag instead. This forces readers to look in
+ * pg_subtrans to map subtransaction XIDs up to top-level XIDs.
+ * There is a race-condition window, in that the new XID will not
+ * appear as running until its parent link has been placed into
+ * pg_subtrans. However, that will happen before anyone could possibly
+ * have a reason to inquire about the status of the XID, so it seems
+ * OK. (Snapshots taken during this window *will* include the parent
+ * XID, so they will deliver the correct answer later on when someone
+ * does have a reason to inquire.)
*/
- if (MyProc != NULL && !isSubXact)
- MyProc->xid = xid;
+ if (MyProc != NULL)
+ {
+ if (!isSubXact)
+ MyProc->xid = xid;
+ else
+ {
+ if (MyProc->subxids.nxids < PGPROC_MAX_CACHED_SUBXIDS)
+ {
+ MyProc->subxids.xids[MyProc->subxids.nxids] = xid;
+ MyProc->subxids.nxids++;
+ }
+ else
+ {
+ MyProc->subxids.overflowed = true;
+ }
+ }
+ }
LWLockRelease(XidGenLock);
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b6758a14b22..486f85be5d9 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.174 2004/07/31 07:39:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.175 2004/08/01 17:32:13 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -168,7 +168,6 @@
#include "pgstat.h"
-
/*
* transaction states - transaction state from server perspective
*/
@@ -230,6 +229,14 @@ typedef struct TransactionStateData
typedef TransactionStateData *TransactionState;
+/*
+ * childXids is currently implemented as an integer List, relying on the
+ * assumption that TransactionIds are no wider than int. We use these
+ * macros to provide some isolation in case that changes in the future.
+ */
+#define lfirst_xid(lc) ((TransactionId) lfirst_int(lc))
+#define lappend_xid(list, datum) lappend_int(list, (int) (datum))
+
static void AbortTransaction(void);
static void AtAbort_Memory(void);
@@ -239,7 +246,7 @@ static void AtCommit_Memory(void);
static void AtStart_Cache(void);
static void AtStart_Memory(void);
static void AtStart_ResourceOwner(void);
-static void CallEOXactCallbacks(bool isCommit);
+static void CallXactCallbacks(XactEvent event, TransactionId parentXid);
static void CleanupTransaction(void);
static void CommitTransaction(void);
static void RecordTransactionAbort(void);
@@ -315,16 +322,16 @@ int CommitSiblings = 5; /* number of concurrent xacts needed to
/*
- * List of add-on end-of-xact callbacks
+ * List of add-on start- and end-of-xact callbacks
*/
-typedef struct EOXactCallbackItem
+typedef struct XactCallbackItem
{
- struct EOXactCallbackItem *next;
- EOXactCallback callback;
+ struct XactCallbackItem *next;
+ XactCallback callback;
void *arg;
-} EOXactCallbackItem;
+} XactCallbackItem;
-static EOXactCallbackItem *EOXact_callbacks = NULL;
+static XactCallbackItem *Xact_callbacks = NULL;
static void (*_RollbackFunc) (void *) = NULL;
static void *_RollbackData = NULL;
@@ -490,7 +497,7 @@ TransactionIdIsCurrentTransactionId(TransactionId xid)
return true;
foreach(cell, s->childXids)
{
- if (TransactionIdEquals(xid, lfirst_int(cell)))
+ if (TransactionIdEquals(xid, lfirst_xid(cell)))
return true;
}
@@ -877,12 +884,12 @@ AtSubCommit_childXids(void)
old_cxt = MemoryContextSwitchTo(s->parent->curTransactionContext);
+ s->parent->childXids = lappend_xid(s->parent->childXids,
+ s->transactionIdData);
+
s->parent->childXids = list_concat(s->parent->childXids, s->childXids);
s->childXids = NIL; /* ensure list not doubly referenced */
- s->parent->childXids = lappend_int(s->parent->childXids,
- s->transactionIdData);
-
MemoryContextSwitchTo(old_cxt);
}
@@ -1083,6 +1090,7 @@ RecordSubTransactionAbort(void)
{
int nrels;
RelFileNode *rptr;
+ TransactionId xid = GetCurrentTransactionId();
int nchildren;
TransactionId *children;
@@ -1104,8 +1112,6 @@ RecordSubTransactionAbort(void)
*/
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)
{
- TransactionId xid = GetCurrentTransactionId();
-
START_CRIT_SECTION();
/*
@@ -1162,6 +1168,15 @@ RecordSubTransactionAbort(void)
END_CRIT_SECTION();
}
+ /*
+ * We can immediately remove failed XIDs from PGPROC's cache of
+ * running child XIDs. It's easiest to do it here while we have the
+ * child XID array at hand, even though in the main-transaction
+ * case the equivalent work happens just after return from
+ * RecordTransactionAbort.
+ */
+ XidCacheRemoveRunningXids(xid, nchildren, children);
+
/* And clean up local data */
if (rptr)
pfree(rptr);
@@ -1389,6 +1404,11 @@ CommitTransaction(void)
LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+
+ /* Clear the subtransaction-XID cache too while holding the lock */
+ MyProc->subxids.nxids = 0;
+ MyProc->subxids.overflowed = false;
+
LWLockRelease(SInvalLock);
}
@@ -1411,6 +1431,8 @@ CommitTransaction(void)
smgrDoPendingDeletes(true);
/* smgrcommit already done */
+ CallXactCallbacks(XACT_EVENT_COMMIT, InvalidTransactionId);
+
ResourceOwnerRelease(TopTransactionResourceOwner,
RESOURCE_RELEASE_BEFORE_LOCKS,
true, true);
@@ -1431,7 +1453,6 @@ CommitTransaction(void)
RESOURCE_RELEASE_AFTER_LOCKS,
true, true);
- CallEOXactCallbacks(true);
AtEOXact_GUC(true, false);
AtEOXact_SPI(true);
AtEOXact_on_commit_actions(true, s->transactionIdData);
@@ -1540,6 +1561,11 @@ AbortTransaction(void)
LWLockAcquire(SInvalLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->xmin = InvalidTransactionId;
+
+ /* Clear the subtransaction-XID cache too while holding the lock */
+ MyProc->subxids.nxids = 0;
+ MyProc->subxids.overflowed = false;
+
LWLockRelease(SInvalLock);
}
@@ -1551,6 +1577,8 @@ AbortTransaction(void)
smgrDoPendingDeletes(false);
smgrabort();
+ CallXactCallbacks(XACT_EVENT_ABORT, InvalidTransactionId);
+
ResourceOwnerRelease(TopTransactionResourceOwner,
RESOURCE_RELEASE_BEFORE_LOCKS,
false, true);
@@ -1562,13 +1590,11 @@ AbortTransaction(void)
RESOURCE_RELEASE_AFTER_LOCKS,
false, true);
- CallEOXactCallbacks(false);
AtEOXact_GUC(false, false);
AtEOXact_SPI(false);
AtEOXact_on_commit_actions(false, s->transactionIdData);
AtEOXact_Namespace(false);
AtEOXact_Files();
- SetReindexProcessing(InvalidOid, InvalidOid);
pgstat_count_xact_rollback();
/*
@@ -2158,43 +2184,46 @@ IsInTransactionChain(void *stmtNode)
/*
- * Register or deregister callback functions for end-of-xact cleanup
+ * Register or deregister callback functions for start- and end-of-xact
+ * operations.
*
* These functions are intended for use by dynamically loaded modules.
* For built-in modules we generally just hardwire the appropriate calls
* (mainly because it's easier to control the order that way, where needed).
*
- * Note that the callback occurs post-commit or post-abort, so the callback
- * functions can only do noncritical cleanup.
+ * At transaction end, the callback occurs post-commit or post-abort, so the
+ * callback functions can only do noncritical cleanup. At subtransaction
+ * start, the callback is called when the subtransaction has finished
+ * initializing.
*/
void
-RegisterEOXactCallback(EOXactCallback callback, void *arg)
+RegisterXactCallback(XactCallback callback, void *arg)
{
- EOXactCallbackItem *item;
+ XactCallbackItem *item;
- item = (EOXactCallbackItem *)
- MemoryContextAlloc(TopMemoryContext, sizeof(EOXactCallbackItem));
+ item = (XactCallbackItem *)
+ MemoryContextAlloc(TopMemoryContext, sizeof(XactCallbackItem));
item->callback = callback;
item->arg = arg;
- item->next = EOXact_callbacks;
- EOXact_callbacks = item;
+ item->next = Xact_callbacks;
+ Xact_callbacks = item;
}
void
-UnregisterEOXactCallback(EOXactCallback callback, void *arg)
+UnregisterXactCallback(XactCallback callback, void *arg)
{
- EOXactCallbackItem *item;
- EOXactCallbackItem *prev;
+ XactCallbackItem *item;
+ XactCallbackItem *prev;
prev = NULL;
- for (item = EOXact_callbacks; item; prev = item, item = item->next)
+ for (item = Xact_callbacks; item; prev = item, item = item->next)
{
if (item->callback == callback && item->arg == arg)
{
if (prev)
prev->next = item->next;
else
- EOXact_callbacks = item->next;
+ Xact_callbacks = item->next;
pfree(item);
break;
}
@@ -2202,13 +2231,13 @@ UnregisterEOXactCallback(EOXactCallback callback, void *arg)
}
static void
-CallEOXactCallbacks(bool isCommit)
+CallXactCallbacks(XactEvent event, TransactionId parentXid)
{
- EOXactCallbackItem *item;
+ XactCallbackItem *item;
- for (item = EOXact_callbacks; item; item = item->next)
+ for (item = Xact_callbacks; item; item = item->next)
{
- (*item->callback) (isCommit, item->arg);
+ (*item->callback) (event, parentXid, item->arg);
}
}
@@ -2948,32 +2977,11 @@ bool
IsSubTransaction(void)
{
TransactionState s = CurrentTransactionState;
-
- switch (s->blockState)
- {
- case TBLOCK_DEFAULT:
- case TBLOCK_STARTED:
- case TBLOCK_BEGIN:
- case TBLOCK_INPROGRESS:
- case TBLOCK_END:
- case TBLOCK_ABORT:
- case TBLOCK_ENDABORT:
- return false;
- case TBLOCK_SUBBEGIN:
- case TBLOCK_SUBINPROGRESS:
- case TBLOCK_SUBABORT:
- case TBLOCK_SUBEND:
- case TBLOCK_SUBENDABORT_ALL:
- case TBLOCK_SUBENDABORT:
- case TBLOCK_SUBABORT_PENDING:
- case TBLOCK_SUBENDABORT_RELEASE:
- return true;
- }
- /* should never get here */
- elog(FATAL, "invalid transaction block state: %s",
- BlockStateAsString(s->blockState));
- return false; /* keep compiler quiet */
+ if (s->nestingLevel >= 2)
+ return true;
+
+ return false;
}
/*
@@ -2997,7 +3005,10 @@ StartSubTransaction(void)
AtSubStart_ResourceOwner();
/*
- * Generate a new Xid and record it in pg_subtrans.
+ * Generate a new Xid and record it in pg_subtrans. NB: we must make
+ * the subtrans entry BEFORE the Xid appears anywhere in shared storage,
+ * such as in the lock table; because until it's made the Xid may not
+ * appear to be "running" to other backends. See GetNewTransactionId.
*/
s->transactionIdData = GetNewTransactionId(true);
@@ -3020,6 +3031,11 @@ StartSubTransaction(void)
s->state = TRANS_INPROGRESS;
+ /*
+ * Call start-of-subxact callbacks
+ */
+ CallXactCallbacks(XACT_EVENT_START_SUB, s->parent->transactionIdData);
+
ShowTransactionState("StartSubTransaction");
}
@@ -3037,10 +3053,7 @@ CommitSubTransaction(void)
elog(WARNING, "CommitSubTransaction while in %s state",
TransStateAsString(s->state));
- /* Pre-commit processing */
- AtSubCommit_Portals(s->parent->transactionIdData,
- s->parent->curTransactionOwner);
- DeferredTriggerEndSubXact(true);
+ /* Pre-commit processing goes here -- nothing to do at the moment */
s->state = TRANS_COMMIT;
@@ -3050,19 +3063,17 @@ CommitSubTransaction(void)
AtSubCommit_childXids();
/* Post-commit cleanup */
- AtSubCommit_smgr();
-
- AtEOSubXact_Inval(true);
- AtEOSubXact_SPI(true, s->transactionIdData);
-
+ DeferredTriggerEndSubXact(true);
+ AtSubCommit_Portals(s->parent->transactionIdData,
+ s->parent->curTransactionOwner);
AtEOSubXact_LargeObject(true, s->transactionIdData,
s->parent->transactionIdData);
+ AtSubCommit_Notify();
AtEOSubXact_UpdatePasswordFile(true, s->transactionIdData,
s->parent->transactionIdData);
- AtEOSubXact_Files(true, s->transactionIdData,
- s->parent->transactionIdData);
- AtEOSubXact_Namespace(true, s->transactionIdData,
- s->parent->transactionIdData);
+ AtSubCommit_smgr();
+
+ CallXactCallbacks(XACT_EVENT_COMMIT_SUB, s->parent->transactionIdData);
/*
* Note that we just release the resource owner's resources and don't
@@ -3074,15 +3085,20 @@ CommitSubTransaction(void)
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_BEFORE_LOCKS,
true, false);
+ AtEOSubXact_Inval(true);
/* we can skip the LOCKS phase */
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_AFTER_LOCKS,
true, false);
- AtSubCommit_Notify();
AtEOXact_GUC(true, true);
+ AtEOSubXact_SPI(true, s->transactionIdData);
AtEOSubXact_on_commit_actions(true, s->transactionIdData,
s->parent->transactionIdData);
+ AtEOSubXact_Namespace(true, s->transactionIdData,
+ s->parent->transactionIdData);
+ AtEOSubXact_Files(true, s->transactionIdData,
+ s->parent->transactionIdData);
/*
* We need to restore the upper transaction's read-only state,
@@ -3134,35 +3150,32 @@ AbortSubTransaction(void)
LockWaitCancel();
- AtSubAbort_Memory();
-
/*
* do abort processing
*/
-
- RecordSubTransactionAbort();
-
- /* Post-abort cleanup */
- AtSubAbort_smgr();
+ AtSubAbort_Memory();
DeferredTriggerEndSubXact(false);
- AtEOSubXact_SPI(false, s->transactionIdData);
AtSubAbort_Portals(s->parent->transactionIdData,
s->parent->curTransactionOwner);
- AtEOSubXact_Inval(false);
-
AtEOSubXact_LargeObject(false, s->transactionIdData,
s->parent->transactionIdData);
+ AtSubAbort_Notify();
AtEOSubXact_UpdatePasswordFile(false, s->transactionIdData,
s->parent->transactionIdData);
- AtEOSubXact_Files(false, s->transactionIdData,
- s->parent->transactionIdData);
- AtEOSubXact_Namespace(false, s->transactionIdData,
- s->parent->transactionIdData);
+
+ /* Advertise the fact that we aborted in pg_clog. */
+ RecordSubTransactionAbort();
+
+ /* Post-abort cleanup */
+ AtSubAbort_smgr();
+
+ CallXactCallbacks(XACT_EVENT_ABORT_SUB, s->parent->transactionIdData);
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_BEFORE_LOCKS,
false, false);
+ AtEOSubXact_Inval(false);
ResourceOwnerRelease(s->curTransactionOwner,
RESOURCE_RELEASE_LOCKS,
false, false);
@@ -3170,10 +3183,14 @@ AbortSubTransaction(void)
RESOURCE_RELEASE_AFTER_LOCKS,
false, false);
- AtSubAbort_Notify();
AtEOXact_GUC(false, true);
+ AtEOSubXact_SPI(false, s->transactionIdData);
AtEOSubXact_on_commit_actions(false, s->transactionIdData,
s->parent->transactionIdData);
+ AtEOSubXact_Namespace(false, s->transactionIdData,
+ s->parent->transactionIdData);
+ AtEOSubXact_Files(false, s->transactionIdData,
+ s->parent->transactionIdData);
/*
* Reset user id which might have been changed transiently. Here we
@@ -3196,8 +3213,6 @@ AbortSubTransaction(void)
*/
XactReadOnly = s->prevXactReadOnly;
- CommandCounterIncrement();
-
RESUME_INTERRUPTS();
}
@@ -3481,7 +3496,7 @@ xactGetCommittedChildren(TransactionId **ptr)
foreach(p, s->childXids)
{
- TransactionId child = lfirst_int(p);
+ TransactionId child = lfirst_xid(p);
*children++ = child;
}
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 581799fc5f5..9cb3c56110f 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.234 2004/06/18 06:13:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.235 2004/08/01 17:32:14 tgl Exp $
*
*
* INTERFACE ROUTINES
@@ -1646,7 +1646,6 @@ reindex_index(Oid indexId)
{
Relation iRel,
heapRelation;
- IndexInfo *indexInfo;
Oid heapId;
bool inplace;
@@ -1671,8 +1670,6 @@ reindex_index(Oid indexId)
/* Open and lock the parent heap relation */
heapRelation = heap_open(heapId, AccessExclusiveLock);
- SetReindexProcessing(heapId, indexId);
-
/*
* If it's a shared index, we must do inplace processing (because we
* have no way to update relfilenode in other databases). Otherwise
@@ -1690,36 +1687,51 @@ reindex_index(Oid indexId)
errmsg("shared index \"%s\" can only be reindexed in stand-alone mode",
RelationGetRelationName(iRel))));
- /* Fetch info needed for index_build */
- indexInfo = BuildIndexInfo(iRel);
-
- if (inplace)
+ PG_TRY();
{
+ IndexInfo *indexInfo;
+
+ /* Suppress use of the target index while rebuilding it */
+ SetReindexProcessing(heapId, indexId);
+
+ /* Fetch info needed for index_build */
+ indexInfo = BuildIndexInfo(iRel);
+
+ if (inplace)
+ {
+ /*
+ * Release any buffers associated with this index. If they're
+ * dirty, they're just dropped without bothering to flush to disk.
+ */
+ DropRelationBuffers(iRel);
+
+ /* Now truncate the actual data */
+ RelationTruncate(iRel, 0);
+ }
+ else
+ {
+ /*
+ * We'll build a new physical relation for the index.
+ */
+ setNewRelfilenode(iRel);
+ }
+
+ /* Initialize the index and rebuild */
+ index_build(heapRelation, iRel, indexInfo);
+
/*
- * Release any buffers associated with this index. If they're
- * dirty, they're just dropped without bothering to flush to disk.
+ * index_build will close both the heap and index relations (but not
+ * give up the locks we hold on them). So we're done.
*/
- DropRelationBuffers(iRel);
-
- /* Now truncate the actual data */
- RelationTruncate(iRel, 0);
}
- else
+ PG_CATCH();
{
- /*
- * We'll build a new physical relation for the index.
- */
- setNewRelfilenode(iRel);
+ /* Make sure flag gets cleared on error exit */
+ ResetReindexProcessing();
+ PG_RE_THROW();
}
-
- /* Initialize the index and rebuild */
- index_build(heapRelation, iRel, indexInfo);
-
- /*
- * index_build will close both the heap and index relations (but not
- * give up the locks we hold on them). So we're done.
- */
- SetReindexProcessing(InvalidOid, InvalidOid);
+ PG_END_TRY();
+ ResetReindexProcessing();
}
/*
diff --git a/src/backend/storage/ipc/sinval.c b/src/backend/storage/ipc/sinval.c
index f5e909c672c..57e39da4a4d 100644
--- a/src/backend/storage/ipc/sinval.c
+++ b/src/backend/storage/ipc/sinval.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.66 2004/07/01 03:13:05 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/ipc/sinval.c,v 1.67 2004/08/01 17:32:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -28,6 +28,30 @@
#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
* need a way to give an idle backend a swift kick in the rear and make
@@ -80,6 +104,10 @@ InitBackendSharedInvalidationState(void)
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 */
}
/*
@@ -393,7 +421,6 @@ ProcessCatchupEvent(void)
* to the doomed database, so additional interlocking is needed during
* backend startup.
*/
-
bool
DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
{
@@ -429,7 +456,41 @@ DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
}
/*
- * TransactionIdIsInProgress -- is given transaction running by some backend
+ * 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:
*
@@ -439,13 +500,15 @@ DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
* 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. This is the slowest, but sadly it has to be
- * done always if the other two failed.
+ * 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 all the Xids
+ * 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)
+ * some concurrency (we can't retrieve the main Xids from PGPROC again anyway;
+ * see GetNewTransactionId).
*/
bool
TransactionIdIsInProgress(TransactionId xid)
@@ -453,13 +516,27 @@ TransactionIdIsInProgress(TransactionId xid)
bool result = false;
SISeg *segP = shmInvalBuffer;
ProcState *stateP = segP->procState;
- int i;
+ int i,
+ j;
int nxids = 0;
TransactionId *xids;
+ TransactionId topxid;
+ bool locked;
+
+ /*
+ * Don't bother checking a very old transaction.
+ */
+ if (TransactionIdPrecedes(xid, RecentGlobalXmin))
+ {
+ xc_by_recent_xmin_inc();
+ return false;
+ }
- xids = (TransactionId *)palloc(sizeof(TransactionId) * segP->maxBackends);
+ /* 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++)
{
@@ -472,101 +549,90 @@ TransactionIdIsInProgress(TransactionId xid)
/* Fetch xid just once - see GetNewTransactionId */
TransactionId pxid = proc->xid;
+ if (!TransactionIdIsValid(pxid))
+ continue;
+
/*
- * check the main Xid (step 1 above)
+ * Step 1: check the main Xid
*/
if (TransactionIdEquals(pxid, xid))
{
+ xc_by_main_xid_inc();
result = true;
- break;
+ goto result_known;
}
/*
- * save the main Xid for step 3.
+ * We can ignore main Xids that are younger than the target Xid,
+ * since the target could not possibly be their child.
*/
- xids[nxids++] = pxid;
-
-#ifdef NOT_USED
- FIXME -- waiting to save the Xids in PGPROC ...
+ if (TransactionIdPrecedes(xid, pxid))
+ continue;
/*
- * check the saved Xids array (step 2)
+ * Step 2: check the cached child-Xids arrays
*/
- for (j = 0; j < PGPROC_MAX_SAVED_XIDS; j++)
+ for (j = proc->subxids.nxids - 1; j >= 0; j--)
{
- pxid = proc->savedxids[j];
-
- if (!TransactionIdIsValid(pxids))
- break;
+ /* Fetch xid just once - see GetNewTransactionId */
+ TransactionId cxid = proc->subxids.xids[j];
- if (TransactionIdEquals(pxid, xid))
+ if (TransactionIdEquals(cxid, xid))
{
+ xc_by_child_xid_inc();
result = true;
- break;
+ goto result_known;
}
}
-#endif
- if (result)
- break;
+ /*
+ * 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;
/*
- * Step 3: have to check pg_subtrans. Use the saved Xids.
- *
- * XXX Could save the cached Xids too for further improvement.
+ * If none of the relevant caches overflowed, we know the Xid is
+ * not running without looking at pg_subtrans.
*/
- if (!result)
- {
- /* this is a potentially expensive call. */
- xid = SubTransGetTopmostTransaction(xid);
-
- Assert(TransactionIdIsValid(xid));
-
- /*
- * We don't care if it aborted, because if it did, we won't find
- * it in the array.
- */
- for (i = 0; i < nxids; i++)
- {
- if (TransactionIdEquals(xids[i], xid))
- {
- result = true;
- break;
- }
- }
- }
-
- pfree(xids);
+ if (nxids == 0)
+ goto result_known;
- 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;
+ /*
+ * 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();
- LWLockAcquire(SInvalLock, LW_SHARED);
+ if (TransactionIdDidAbort(xid))
+ goto result_known;
- for (index = 0; index < segP->lastBackend; index++)
+ /*
+ * 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))
{
- SHMEM_OFFSET pOffset = stateP[index].procStruct;
-
- if (pOffset != INVALID_OFFSET)
+ for (i = 0; i < nxids; i++)
{
- PGPROC *proc = (PGPROC *) MAKE_PTR(pOffset);
-
- if (proc->pid == pid)
+ if (TransactionIdEquals(xids[i], topxid))
{
result = true;
break;
@@ -574,7 +640,11 @@ IsBackendPid(int pid)
}
}
- LWLockRelease(SInvalLock);
+result_known:
+ if (locked)
+ LWLockRelease(SInvalLock);
+
+ pfree(xids);
return result;
}
@@ -928,3 +998,85 @@ CountEmptyBackendSlots(void)
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;
+ }
+ }
+ /* We should have found it, unless the cache has overflowed */
+ Assert(j >= 0 || MyProc->subxids.overflowed);
+ }
+
+ for (j = MyProc->subxids.nxids - 1; j >= 0; j--)
+ {
+ if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
+ {
+ XidCacheRemove(j);
+ break;
+ }
+ }
+ /* We should have found it, unless the cache has overflowed */
+ Assert(j >= 0 || MyProc->subxids.overflowed);
+
+ 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 */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 6c32c6c3d78..d8d718a1823 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.221 2004/07/27 05:11:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.222 2004/08/01 17:32:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -326,8 +326,7 @@ ProcessUtility(Node *parsetree,
{
/*
* START TRANSACTION, as defined by SQL99:
- * Identical to BEGIN, except that it takes a few
- * additional options. Same code for both.
+ * Identical to BEGIN. Same code for both.
*/
case TRANS_STMT_BEGIN:
case TRANS_STMT_START:
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 2ae41c013c1..e5e21e8719b 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.129 2004/07/12 00:09:06 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.130 2004/08/01 17:32:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -115,19 +115,29 @@ ReindexIsProcessingIndex(Oid indexOid)
/*
* SetReindexProcessing
* Set flag that specified heap/index are being reindexed.
- * Pass InvalidOid to indicate that reindexing is not active.
*/
void
SetReindexProcessing(Oid heapOid, Oid indexOid)
{
- /* Args should be both, or neither, InvalidOid */
- Assert((heapOid == InvalidOid) == (indexOid == InvalidOid));
+ Assert(OidIsValid(heapOid) && OidIsValid(indexOid));
/* Reindexing is not re-entrant. */
- Assert(indexOid == InvalidOid || currentlyReindexedIndex == InvalidOid);
+ if (OidIsValid(currentlyReindexedIndex))
+ elog(ERROR, "cannot reindex while reindexing");
currentlyReindexedHeap = heapOid;
currentlyReindexedIndex = indexOid;
}
+/*
+ * ResetReindexProcessing
+ * Unset reindexing status.
+ */
+void
+ResetReindexProcessing(void)
+{
+ currentlyReindexedHeap = InvalidOid;
+ currentlyReindexedIndex = InvalidOid;
+}
+
/* ----------------------------------------------------------------
* database path / name support stuff
* ----------------------------------------------------------------
diff --git a/src/include/access/htup.h b/src/include/access/htup.h
index 37ba1164ec1..971a279b9c9 100644
--- a/src/include/access/htup.h
+++ b/src/include/access/htup.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.67 2004/07/11 18:01:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/htup.h,v 1.68 2004/08/01 17:32:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -68,34 +68,17 @@
* object ID (if HEAP_HASOID is set in t_infomask)
* user data fields
*
- * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac
- * in just three physical fields. Xmin is always really stored, but
- * Cmin and Xmax share a field, as do Cmax and Xvac. This works because
- * we know that there are only a limited number of states that a tuple can
- * be in, and that Cmin and Cmax are only interesting for the lifetime of
- * the inserting and deleting transactions respectively. We have the
- * following possible states of a tuple:
+ * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in four
+ * physical fields. Xmin, Cmin and Xmax are always really stored, but
+ * Cmax and Xvac share a field. This works because we know that there are
+ * only a limited number of states that a tuple can be in, and that Cmax
+ * is only interesting for the lifetime of the deleting transaction.
+ * This assumes that VACUUM FULL never tries to move a tuple whose Cmax
+ * is still interesting (ie, delete-in-progress).
*
- * XMIN CMIN XMAX CMAX XVAC
- *
- * NEW (never deleted, not moved by vacuum):
- * valid valid invalid invalid invalid
- *
- * DELETED BY CREATING XACT:
- * valid valid = XMIN valid invalid
- *
- * DELETED BY OTHER XACT:
- * valid unneeded valid valid invalid
- *
- * MOVED BY VACUUM FULL:
- * valid unneeded maybe-valid unneeded valid
- *
- * This assumes that VACUUM FULL never tries to move a tuple whose Cmin or
- * Cmax is still interesting (ie, insert-in-progress or delete-in-progress).
- *
- * This table shows that if we use an infomask bit to handle the case
- * XMAX=XMIN specially, we never need to store Cmin and Xmax at the same
- * time. Nor do we need to store Cmax and Xvac at the same time.
+ * Note that in 7.3 and 7.4 a similar idea was applied to Xmax and Cmin.
+ * However, with the advent of subtransactions, a tuple may need both Xmax
+ * and Cmin simultaneously, so this is no longer possible.
*
* Following the fixed header fields, the nulls bitmap is stored (beginning
* at t_bits). The bitmap is *not* stored if t_infomask shows that there
@@ -416,7 +399,7 @@ typedef HeapTupleData *HeapTuple;
* WAL record definitions for heapam.c's WAL operations
*
* XLOG allows to store some information in high 4 bits of log
- * record xl_info field
+ * record xl_info field. We use 3 for opcode and one for init bit.
*/
#define XLOG_HEAP_INSERT 0x00
#define XLOG_HEAP_DELETE 0x10
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 532dcf51b0e..16b7de333a4 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.68 2004/07/31 07:39:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/access/xact.h,v 1.69 2004/08/01 17:32:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,9 +42,18 @@ extern bool DefaultXactReadOnly;
extern bool XactReadOnly;
/*
- * end-of-transaction cleanup callbacks for dynamically loaded modules
+ * start- and end-of-transaction callbacks for dynamically loaded modules
*/
-typedef void (*EOXactCallback) (bool isCommit, void *arg);
+typedef enum
+{
+ XACT_EVENT_ABORT,
+ XACT_EVENT_COMMIT,
+ XACT_EVENT_START_SUB,
+ XACT_EVENT_ABORT_SUB,
+ XACT_EVENT_COMMIT_SUB
+} XactEvent;
+
+typedef void (*XactCallback) (XactEvent event, TransactionId parentXid, void *arg);
/* ----------------
@@ -118,8 +127,8 @@ extern void AbortOutOfAnyTransaction(void);
extern void PreventTransactionChain(void *stmtNode, const char *stmtType);
extern void RequireTransactionChain(void *stmtNode, const char *stmtType);
extern bool IsInTransactionChain(void *stmtNode);
-extern void RegisterEOXactCallback(EOXactCallback callback, void *arg);
-extern void UnregisterEOXactCallback(EOXactCallback callback, void *arg);
+extern void RegisterXactCallback(XactCallback callback, void *arg);
+extern void UnregisterXactCallback(XactCallback callback, void *arg);
extern void RecordTransactionCommit(void);
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 0a508861b27..3f7c0946d74 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.163 2004/06/18 06:14:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.164 2004/08/01 17:32:20 tgl Exp $
*
* NOTES
* some of the information in this file should be moved to other files.
@@ -308,6 +308,7 @@ extern void BaseInit(void);
extern void IgnoreSystemIndexes(bool mode);
extern bool IsIgnoringSystemIndexes(void);
extern void SetReindexProcessing(Oid heapOid, Oid indexOid);
+extern void ResetReindexProcessing(void);
extern bool ReindexIsProcessingHeap(Oid heapOid);
extern bool ReindexIsProcessingIndex(Oid indexOid);
extern void CreateDataDirLockFile(const char *datadir, bool amPostmaster);
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index c2411bef073..4f7f39003ad 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.71 2004/07/21 20:34:49 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.72 2004/08/01 17:32:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,25 @@
/*
+ * Each backend advertises up to PGPROC_MAX_CACHED_SUBXIDS TransactionIds
+ * for non-aborted subtransactions of its current top transaction. These
+ * have to be treated as running XIDs by other backends.
+ *
+ * We also keep track of whether the cache overflowed (ie, the transaction has
+ * generated at least one subtransaction that didn't fit in the cache).
+ * If none of the caches have overflowed, we can assume that an XID that's not
+ * listed anywhere in the PGPROC array is not a running transaction. Else we
+ * have to look at pg_subtrans.
+ */
+#define PGPROC_MAX_CACHED_SUBXIDS 64 /* XXX guessed-at value */
+
+struct XidCache {
+ bool overflowed;
+ int nxids;
+ TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS];
+};
+
+/*
* Each backend has a PGPROC struct in shared memory. There is also a list of
* currently-unused PGPROC structs that will be reallocated to new backends.
*
@@ -68,6 +87,8 @@ struct PGPROC
SHM_QUEUE procHolders; /* list of PROCLOCK objects for locks held
* or awaited by this backend */
+
+ struct XidCache subxids; /* cache for subtransaction XIDs */
};
/* NOTE: "typedef struct PGPROC PGPROC" appears in storage/lock.h. */
diff --git a/src/include/storage/sinval.h b/src/include/storage/sinval.h
index 84769200504..5ac995a29d4 100644
--- a/src/include/storage/sinval.h
+++ b/src/include/storage/sinval.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.35 2004/06/02 21:29:29 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/sinval.h,v 1.36 2004/08/01 17:32:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -104,6 +104,9 @@ 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);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 4c579223d91..f075b96c0fc 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.111 2004/07/31 23:04:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.112 2004/08/01 17:32:21 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -4216,26 +4216,44 @@ exec_set_found(PLpgSQL_execstate * estate, bool state)
* structs that are using it as no longer active.
*/
void
-plpgsql_eoxact(bool isCommit, void *arg)
+plpgsql_xact_cb(XactEvent event, TransactionId parentXid, void *arg)
{
PLpgSQL_expr *expr;
PLpgSQL_expr *enext;
- /* Mark all active exprs as inactive */
- for (expr = active_simple_exprs; expr; expr = enext)
+ switch (event)
{
- enext = expr->expr_simple_next;
- expr->expr_simple_state = NULL;
- expr->expr_simple_next = NULL;
+ /*
+ * Nothing to do at subtransaction events
+ *
+ * XXX really? Maybe subtransactions need to have their own
+ * simple_eval_estate? It would get a lot messier, so for now
+ * let's assume we don't need that.
+ */
+ case XACT_EVENT_START_SUB:
+ case XACT_EVENT_ABORT_SUB:
+ case XACT_EVENT_COMMIT_SUB:
+ break;
+
+ case XACT_EVENT_ABORT:
+ case XACT_EVENT_COMMIT:
+ /* Mark all active exprs as inactive */
+ for (expr = active_simple_exprs; expr; expr = enext)
+ {
+ enext = expr->expr_simple_next;
+ expr->expr_simple_state = NULL;
+ expr->expr_simple_next = NULL;
+ }
+ active_simple_exprs = NULL;
+ /*
+ * If we are doing a clean transaction shutdown, free the EState
+ * (so that any remaining resources will be released correctly).
+ * In an abort, we expect the regular abort recovery procedures to
+ * release everything of interest.
+ */
+ if (event == XACT_EVENT_COMMIT && simple_eval_estate)
+ FreeExecutorState(simple_eval_estate);
+ simple_eval_estate = NULL;
+ break;
}
- active_simple_exprs = NULL;
- /*
- * If we are doing a clean transaction shutdown, free the EState
- * (so that any remaining resources will be released correctly).
- * In an abort, we expect the regular abort recovery procedures to
- * release everything of interest.
- */
- if (isCommit && simple_eval_estate)
- FreeExecutorState(simple_eval_estate);
- simple_eval_estate = NULL;
}
diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c
index 5f6a83c11d6..d4e892eb719 100644
--- a/src/pl/plpgsql/src/pl_handler.c
+++ b/src/pl/plpgsql/src/pl_handler.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.22 2004/07/31 20:55:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.23 2004/08/01 17:32:22 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -66,7 +66,7 @@ plpgsql_init(void)
plpgsql_HashTableInit();
- RegisterEOXactCallback(plpgsql_eoxact, NULL);
+ RegisterXactCallback(plpgsql_xact_cb, NULL);
plpgsql_firstcall = 0;
}
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index d57d4a7025e..e054d5b25f1 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.49 2004/07/31 23:04:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.50 2004/08/01 17:32:22 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -702,7 +702,7 @@ extern Datum plpgsql_exec_function(PLpgSQL_function * func,
FunctionCallInfo fcinfo);
extern HeapTuple plpgsql_exec_trigger(PLpgSQL_function * func,
TriggerData *trigdata);
-extern void plpgsql_eoxact(bool isCommit, void *arg);
+extern void plpgsql_xact_cb(XactEvent event, TransactionId parentXid, void *arg);
/* ----------
* Functions for the dynamic string handling in pl_funcs.c