aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xact.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r--src/backend/access/transam/xact.c380
1 files changed, 223 insertions, 157 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b6efb315581..d88f7164d34 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.170 2004/07/01 20:11:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.171 2004/07/17 03:28:23 tgl Exp $
*
* NOTES
* Transaction aborts can now occur two ways:
@@ -144,10 +144,6 @@
#include <time.h>
#include <unistd.h>
-#include "access/gistscan.h"
-#include "access/hash.h"
-#include "access/nbtree.h"
-#include "access/rtree.h"
#include "access/subtrans.h"
#include "access/xact.h"
#include "catalog/heap.h"
@@ -168,23 +164,73 @@
#include "utils/inval.h"
#include "utils/memutils.h"
#include "utils/portal.h"
-#include "utils/catcache.h"
-#include "utils/relcache.h"
+#include "utils/resowner.h"
#include "pgstat.h"
+
+/*
+ * transaction states - transaction state from server perspective
+ */
+typedef enum TransState
+{
+ TRANS_DEFAULT,
+ TRANS_START,
+ TRANS_INPROGRESS,
+ TRANS_COMMIT,
+ TRANS_ABORT
+} TransState;
+
+/*
+ * transaction block states - transaction state of client queries
+ */
+typedef enum TBlockState
+{
+ TBLOCK_DEFAULT,
+ TBLOCK_STARTED,
+ TBLOCK_BEGIN,
+ TBLOCK_INPROGRESS,
+ TBLOCK_END,
+ TBLOCK_ABORT,
+ TBLOCK_ENDABORT,
+
+ TBLOCK_SUBBEGIN,
+ TBLOCK_SUBBEGINABORT,
+ TBLOCK_SUBINPROGRESS,
+ TBLOCK_SUBEND,
+ TBLOCK_SUBABORT,
+ TBLOCK_SUBENDABORT_OK,
+ TBLOCK_SUBENDABORT_ERROR
+} TBlockState;
+
+/*
+ * transaction state structure
+ */
+typedef struct TransactionStateData
+{
+ TransactionId transactionIdData; /* my XID */
+ CommandId commandId; /* current CID */
+ TransState state; /* low-level state */
+ TBlockState blockState; /* high-level state */
+ int nestingLevel; /* nest depth */
+ MemoryContext curTransactionContext; /* my xact-lifetime context */
+ ResourceOwner curTransactionOwner; /* my query resources */
+ List *childXids; /* subcommitted child XIDs */
+ AclId currentUser; /* subxact start current_user */
+ struct TransactionStateData *parent; /* back link to parent */
+} TransactionStateData;
+
+typedef TransactionStateData *TransactionState;
+
+
static void AbortTransaction(void);
-static void AtAbort_Cache(void);
-static void AtAbort_Locks(void);
static void AtAbort_Memory(void);
static void AtCleanup_Memory(void);
-static void AtCommit_Cache(void);
static void AtCommit_LocalCache(void);
-static void AtCommit_Locks(void);
static void AtCommit_Memory(void);
static void AtStart_Cache(void);
-static void AtStart_Locks(void);
static void AtStart_Memory(void);
+static void AtStart_ResourceOwner(void);
static void CallEOXactCallbacks(bool isCommit);
static void CleanupTransaction(void);
static void CommitTransaction(void);
@@ -200,11 +246,11 @@ static void StartAbortedSubTransaction(void);
static void PushTransaction(void);
static void PopTransaction(void);
-static void AtSubAbort_Locks(void);
static void AtSubAbort_Memory(void);
static void AtSubCleanup_Memory(void);
static void AtSubCommit_Memory(void);
static void AtSubStart_Memory(void);
+static void AtSubStart_ResourceOwner(void);
static void ShowTransactionState(const char *str);
static void ShowTransactionStateRec(TransactionState state);
@@ -224,6 +270,7 @@ static TransactionStateData TopTransactionStateData = {
* perspective */
0, /* nesting level */
NULL, /* cur transaction context */
+ NULL, /* cur transaction resource owner */
NIL, /* subcommitted child Xids */
0, /* entry-time current userid */
NULL /* link to parent state block */
@@ -462,8 +509,7 @@ CommandCounterIncrement(void)
SerializableSnapshot->curcid = s->commandId;
/*
- * make cache changes visible to me. AtCommit_LocalCache() instead of
- * AtCommit_Cache() is called here.
+ * make cache changes visible to me.
*/
AtCommit_LocalCache();
AtStart_Cache();
@@ -485,20 +531,6 @@ AtStart_Cache(void)
}
/*
- * AtStart_Locks
- */
-static void
-AtStart_Locks(void)
-{
- /*
- * at present, it is unknown to me what belongs here -cim 3/18/90
- *
- * There isn't anything to do at the start of a xact for locks. -mer
- * 5/24/92
- */
-}
-
-/*
* AtStart_Memory
*/
static void
@@ -532,6 +564,29 @@ AtStart_Memory(void)
MemoryContextSwitchTo(CurTransactionContext);
}
+/*
+ * AtStart_ResourceOwner
+ */
+static void
+AtStart_ResourceOwner(void)
+{
+ TransactionState s = CurrentTransactionState;
+
+ /*
+ * We shouldn't have a transaction resource owner already.
+ */
+ Assert(TopTransactionResourceOwner == NULL);
+
+ /*
+ * Create a toplevel resource owner for the transaction.
+ */
+ s->curTransactionOwner = ResourceOwnerCreate(NULL, "TopTransaction");
+
+ TopTransactionResourceOwner = s->curTransactionOwner;
+ CurTransactionResourceOwner = s->curTransactionOwner;
+ CurrentResourceOwner = s->curTransactionOwner;
+}
+
/* ----------------------------------------------------------------
* StartSubTransaction stuff
* ----------------------------------------------------------------
@@ -563,6 +618,28 @@ AtSubStart_Memory(void)
MemoryContextSwitchTo(CurTransactionContext);
}
+/*
+ * AtSubStart_ResourceOwner
+ */
+static void
+AtSubStart_ResourceOwner(void)
+{
+ TransactionState s = CurrentTransactionState;
+
+ Assert(s->parent != NULL);
+
+ /*
+ * Create a resource owner for the subtransaction. We make it a
+ * child of the immediate parent's resource owner.
+ */
+ s->curTransactionOwner =
+ ResourceOwnerCreate(s->parent->curTransactionOwner,
+ "SubTransaction");
+
+ CurTransactionResourceOwner = s->curTransactionOwner;
+ CurrentResourceOwner = s->curTransactionOwner;
+}
+
/* ----------------------------------------------------------------
* CommitTransaction stuff
* ----------------------------------------------------------------
@@ -581,7 +658,7 @@ RecordTransactionCommit(void)
/* Get data needed for commit record */
nrels = smgrGetPendingDeletes(true, &rptr);
- nchildren = xactGetCommittedChildren(&children, false);
+ nchildren = xactGetCommittedChildren(&children);
/*
* If we made neither any XLOG entries nor any temp-rel updates,
@@ -715,23 +792,6 @@ RecordTransactionCommit(void)
/*
- * AtCommit_Cache
- */
-static void
-AtCommit_Cache(void)
-{
- /*
- * Clean up the relation cache.
- */
- AtEOXact_RelationCache(true);
-
- /*
- * Make catalog changes visible to all backends.
- */
- AtEOXact_Inval(true);
-}
-
-/*
* AtCommit_LocalCache
*/
static void
@@ -744,20 +804,6 @@ AtCommit_LocalCache(void)
}
/*
- * AtCommit_Locks
- */
-static void
-AtCommit_Locks(void)
-{
- /*
- * XXX What if ProcReleaseLocks fails? (race condition?)
- *
- * Then you're up a creek! -mer 5/24/92
- */
- ProcReleaseLocks(ReleaseAllExceptSession, 0, NULL);
-}
-
-/*
* AtCommit_Memory
*/
static void
@@ -878,7 +924,7 @@ RecordTransactionAbort(void)
/* Get data needed for abort record */
nrels = smgrGetPendingDeletes(false, &rptr);
- nchildren = xactGetCommittedChildren(&children, false);
+ nchildren = xactGetCommittedChildren(&children);
/*
* If we made neither any transaction-controlled XLOG entries nor any
@@ -980,31 +1026,6 @@ RecordTransactionAbort(void)
}
/*
- * AtAbort_Cache
- */
-static void
-AtAbort_Cache(void)
-{
- AtEOXact_RelationCache(false);
- AtEOXact_Inval(false);
-}
-
-/*
- * AtAbort_Locks
- */
-static void
-AtAbort_Locks(void)
-{
- /*
- * XXX What if ProcReleaseLocks() fails? (race condition?)
- *
- * Then you're up a creek without a paddle! -mer
- */
- ProcReleaseLocks(ReleaseAll, 0, NULL);
-}
-
-
-/*
* AtAbort_Memory
*/
static void
@@ -1029,22 +1050,6 @@ AtAbort_Memory(void)
MemoryContextSwitchTo(TopMemoryContext);
}
-/*
- * AtSubAbort_Locks
- */
-static void
-AtSubAbort_Locks(void)
-{
- int nxids;
- TransactionId *xids;
-
- nxids = xactGetCommittedChildren(&xids, true);
-
- ProcReleaseLocks(ReleaseGivenXids, nxids, xids);
-
- pfree(xids);
-}
-
/*
* AtSubAbort_Memory
@@ -1070,7 +1075,7 @@ RecordSubTransactionAbort(void)
/* Get data needed for abort record */
nrels = smgrGetPendingDeletes(false, &rptr);
- nchildren = xactGetCommittedChildren(&children, false);
+ nchildren = xactGetCommittedChildren(&children);
/*
* If we made neither any transaction-controlled XLOG entries nor any
@@ -1242,6 +1247,12 @@ StartTransaction(void)
XactReadOnly = DefaultXactReadOnly;
/*
+ * must initialize resource-management stuff first
+ */
+ AtStart_Memory();
+ AtStart_ResourceOwner();
+
+ /*
* generate a new transaction id
*/
s->transactionIdData = GetNewTransactionId(false);
@@ -1268,16 +1279,10 @@ StartTransaction(void)
*/
/*
- * initialize the various transaction subsystems
+ * initialize other subsystems for new transaction
*/
- AtStart_Memory();
AtStart_Inval();
AtStart_Cache();
- AtStart_Locks();
-
- /*
- * Tell the trigger manager we're starting a transaction
- */
DeferredTriggerBeginXact();
/*
@@ -1380,27 +1385,49 @@ CommitTransaction(void)
* pins); then release locks; then release backend-local resources. We
* want to release locks at the point where any backend waiting for us
* will see our transaction as being fully cleaned up.
+ *
+ * Resources that can be associated with individual queries are
+ * handled by the ResourceOwner mechanism. The other calls here
+ * are for backend-wide state.
*/
smgrDoPendingDeletes(true);
- AtCommit_Cache();
- AtEOXact_Buffers(true);
/* smgrcommit already done */
- AtCommit_Locks();
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ true, true);
+
+ /*
+ * Make catalog changes visible to all backends. This has to happen
+ * after relcache references are dropped (see comments for
+ * AtEOXact_RelationCache), but before locks are released (if anyone
+ * is waiting for lock on a relation we've modified, we want them to
+ * know about the catalog change before they start using the relation).
+ */
+ AtEOXact_Inval(true);
+
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_LOCKS,
+ true, true);
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ true, true);
CallEOXactCallbacks(true);
AtEOXact_GUC(true, false);
AtEOXact_SPI(true);
- AtEOXact_gist();
- AtEOXact_hash();
- AtEOXact_nbtree();
- AtEOXact_rtree();
AtEOXact_on_commit_actions(true, s->transactionIdData);
AtEOXact_Namespace(true);
- AtEOXact_CatCache(true);
AtEOXact_Files();
pgstat_count_xact_commit();
+
+ CurrentResourceOwner = NULL;
+ ResourceOwnerDelete(TopTransactionResourceOwner);
+ s->curTransactionOwner = NULL;
+ CurTransactionResourceOwner = NULL;
+ TopTransactionResourceOwner = NULL;
+
AtCommit_Memory();
s->nestingLevel = 0;
@@ -1504,22 +1531,24 @@ AbortTransaction(void)
*/
smgrDoPendingDeletes(false);
- AtAbort_Cache();
- AtEOXact_Buffers(false);
smgrabort();
- AtAbort_Locks();
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ false, true);
+ AtEOXact_Inval(false);
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_LOCKS,
+ false, true);
+ ResourceOwnerRelease(TopTransactionResourceOwner,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ false, true);
CallEOXactCallbacks(false);
AtEOXact_GUC(false, false);
AtEOXact_SPI(false);
- AtEOXact_gist();
- AtEOXact_hash();
- AtEOXact_nbtree();
- AtEOXact_rtree();
AtEOXact_on_commit_actions(false, s->transactionIdData);
AtEOXact_Namespace(false);
- AtEOXact_CatCache(false);
AtEOXact_Files();
SetReindexProcessing(InvalidOid, InvalidOid);
pgstat_count_xact_rollback();
@@ -1548,6 +1577,13 @@ CleanupTransaction(void)
* do abort cleanup processing
*/
AtCleanup_Portals(); /* now safe to release portal memory */
+
+ CurrentResourceOwner = NULL; /* and resource owner */
+ ResourceOwnerDelete(TopTransactionResourceOwner);
+ s->curTransactionOwner = NULL;
+ CurTransactionResourceOwner = NULL;
+ TopTransactionResourceOwner = NULL;
+
AtCleanup_Memory(); /* and transaction memory */
s->nestingLevel = 0;
@@ -2484,6 +2520,12 @@ StartSubTransaction(void)
s->state = TRANS_START;
/*
+ * must initialize resource-management stuff first
+ */
+ AtSubStart_Memory();
+ AtSubStart_ResourceOwner();
+
+ /*
* Generate a new Xid and record it in pg_subtrans.
*/
s->transactionIdData = GetNewTransactionId(true);
@@ -2495,13 +2537,10 @@ StartSubTransaction(void)
*/
s->currentUser = GetUserId();
- /* Initialize the various transaction subsystems */
- AtSubStart_Memory();
+ /*
+ * Initialize other subsystems for new subtransaction
+ */
AtSubStart_Inval();
- AtSubStart_RelationCache();
- AtSubStart_CatCache();
- AtSubStart_Buffers();
- AtSubStart_smgr();
AtSubStart_Notify();
DeferredTriggerBeginSubXact();
@@ -2524,7 +2563,8 @@ CommitSubTransaction(void)
elog(WARNING, "CommitSubTransaction and not in in-progress state");
/* Pre-commit processing */
- AtSubCommit_Portals(s->parent->transactionIdData);
+ AtSubCommit_Portals(s->parent->transactionIdData,
+ s->parent->curTransactionOwner);
DeferredTriggerEndSubXact(true);
s->state = TRANS_COMMIT;
@@ -2539,17 +2579,31 @@ CommitSubTransaction(void)
AtSubEOXact_Inval(true);
AtEOSubXact_SPI(true, s->transactionIdData);
+
+ /*
+ * Note that we just release the resource owner's resources and don't
+ * delete it. This is because locks are not actually released here.
+ * The owner object continues to exist as a child of its parent owner
+ * (namely my parent transaction's resource owner), and the locks
+ * effectively become that owner object's responsibility.
+ */
+ ResourceOwnerRelease(s->curTransactionOwner,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ true, false);
+ /* we can skip the LOCKS phase */
+ ResourceOwnerRelease(s->curTransactionOwner,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ true, false);
+
AtSubCommit_Notify();
AtEOXact_GUC(true, true);
- AtEOSubXact_gist(s->transactionIdData);
- AtEOSubXact_hash(s->transactionIdData);
- AtEOSubXact_rtree(s->transactionIdData);
AtEOSubXact_on_commit_actions(true, s->transactionIdData,
s->parent->transactionIdData);
- AtEOSubXact_CatCache(true);
- AtEOSubXact_RelationCache(true);
- AtEOSubXact_Buffers(true);
+ CurrentResourceOwner = s->parent->curTransactionOwner;
+ CurTransactionResourceOwner = s->parent->curTransactionOwner;
+ s->curTransactionOwner = NULL;
+
AtSubCommit_Memory();
s->state = TRANS_DEFAULT;
@@ -2597,20 +2651,25 @@ AbortSubTransaction(void)
AtSubAbort_smgr();
DeferredTriggerEndSubXact(false);
- AtSubAbort_Portals();
- AtSubEOXact_Inval(false);
- AtSubAbort_Locks();
AtEOSubXact_SPI(false, s->transactionIdData);
+ AtSubAbort_Portals(s->parent->transactionIdData,
+ s->parent->curTransactionOwner);
+ AtSubEOXact_Inval(false);
+
+ ResourceOwnerRelease(s->curTransactionOwner,
+ RESOURCE_RELEASE_BEFORE_LOCKS,
+ false, false);
+ ResourceOwnerRelease(s->curTransactionOwner,
+ RESOURCE_RELEASE_LOCKS,
+ false, false);
+ ResourceOwnerRelease(s->curTransactionOwner,
+ RESOURCE_RELEASE_AFTER_LOCKS,
+ false, false);
+
AtSubAbort_Notify();
AtEOXact_GUC(false, true);
- AtEOSubXact_gist(s->transactionIdData);
- AtEOSubXact_hash(s->transactionIdData);
- AtEOSubXact_rtree(s->transactionIdData);
AtEOSubXact_on_commit_actions(false, s->transactionIdData,
s->parent->transactionIdData);
- AtEOSubXact_RelationCache(false);
- AtEOSubXact_CatCache(false);
- AtEOSubXact_Buffers(false);
/*
* Reset user id which might have been changed transiently. Here we
@@ -2645,6 +2704,12 @@ CleanupSubTransaction(void)
elog(WARNING, "CleanupSubTransaction and not in aborted state");
AtSubCleanup_Portals();
+
+ CurrentResourceOwner = s->parent->curTransactionOwner;
+ CurTransactionResourceOwner = s->parent->curTransactionOwner;
+ ResourceOwnerDelete(s->curTransactionOwner);
+ s->curTransactionOwner = NULL;
+
AtSubCleanup_Memory();
s->state = TRANS_DEFAULT;
@@ -2685,6 +2750,7 @@ StartAbortedSubTransaction(void)
* Initialize only what has to be there for CleanupSubTransaction to work.
*/
AtSubStart_Memory();
+ AtSubStart_ResourceOwner();
s->state = TRANS_ABORT;
@@ -2723,6 +2789,7 @@ PushTransaction(void)
*/
s->transactionIdData = p->transactionIdData;
s->curTransactionContext = p->curTransactionContext;
+ s->curTransactionOwner = p->curTransactionOwner;
s->currentUser = p->currentUser;
CurrentTransactionState = s;
@@ -2752,6 +2819,10 @@ PopTransaction(void)
CurTransactionContext = s->parent->curTransactionContext;
MemoryContextSwitchTo(CurTransactionContext);
+ /* Ditto for ResourceOwner links */
+ CurTransactionResourceOwner = s->parent->curTransactionOwner;
+ CurrentResourceOwner = s->parent->curTransactionOwner;
+
/* Free the old child structure */
pfree(s);
}
@@ -2861,11 +2932,9 @@ TransStateAsString(TransState state)
* value is the number of child transactions. *children is set to point to a
* palloc'd array of TransactionIds. If there are no subxacts, *children is
* set to NULL.
- *
- * If metoo is true, include the current TransactionId.
*/
int
-xactGetCommittedChildren(TransactionId **ptr, bool metoo)
+xactGetCommittedChildren(TransactionId **ptr)
{
TransactionState s = CurrentTransactionState;
int nchildren;
@@ -2873,8 +2942,6 @@ xactGetCommittedChildren(TransactionId **ptr, bool metoo)
ListCell *p;
nchildren = list_length(s->childXids);
- if (metoo)
- nchildren++;
if (nchildren == 0)
{
*ptr = NULL;
@@ -2887,10 +2954,9 @@ xactGetCommittedChildren(TransactionId **ptr, bool metoo)
foreach(p, s->childXids)
{
TransactionId child = lfirst_int(p);
- *children++ = (TransactionId)child;
+
+ *children++ = child;
}
- if (metoo)
- *children = s->transactionIdData;
return nchildren;
}