xact.c

来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,442 行 · 第 1/5 页

C
2,442
字号
		/*		 * Catch the scenario where we aborted partway through		 * RecordTransactionCommit ...		 */		if (TransactionIdDidCommit(xid))			elog(PANIC, "cannot abort transaction %u, it was already committed", xid);		START_CRIT_SECTION();		/*		 * We only need to log the abort in XLOG if the transaction made any		 * transaction-controlled XLOG entries or will delete files. (If it		 * made no transaction-controlled XLOG entries, its XID appears		 * nowhere in permanent storage, so no one else will ever care if it		 * committed.)		 *		 * We do not flush XLOG to disk unless deleting files, since the		 * default assumption after a crash would be that we aborted, anyway.		 * For the same reason, we don't need to worry about interlocking		 * against checkpoint start.		 */		if (MyLastRecPtr.xrecoff != 0 || nrels > 0)		{			XLogRecData rdata[3];			int			lastrdata = 0;			xl_xact_abort xlrec;			XLogRecPtr	recptr;			xlrec.xtime = time(NULL);			xlrec.nrels = nrels;			xlrec.nsubxacts = nchildren;			rdata[0].data = (char *) (&xlrec);			rdata[0].len = MinSizeOfXactAbort;			rdata[0].buffer = InvalidBuffer;			/* dump rels to delete */			if (nrels > 0)			{				rdata[0].next = &(rdata[1]);				rdata[1].data = (char *) rels;				rdata[1].len = nrels * sizeof(RelFileNode);				rdata[1].buffer = InvalidBuffer;				lastrdata = 1;			}			/* dump committed child Xids */			if (nchildren > 0)			{				rdata[lastrdata].next = &(rdata[2]);				rdata[2].data = (char *) children;				rdata[2].len = nchildren * sizeof(TransactionId);				rdata[2].buffer = InvalidBuffer;				lastrdata = 2;			}			rdata[lastrdata].next = NULL;			recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);			/* Must flush if we are deleting files... */			if (nrels > 0)				XLogFlush(recptr);		}		/*		 * Mark the transaction aborted in clog.  This is not absolutely		 * necessary but we may as well do it while we are here.		 *		 * The ordering here isn't critical but it seems best to mark the		 * parent first.  This assures an atomic transition of all the		 * subtransactions to aborted state from the point of view of		 * concurrent TransactionIdDidAbort calls.		 */		TransactionIdAbort(xid);		TransactionIdAbortTree(nchildren, children);		END_CRIT_SECTION();	}	/* Break the chain of back-links in the XLOG records I output */	MyLastRecPtr.xrecoff = 0;	MyXactMadeXLogEntry = false;	MyXactMadeTempRelUpdate = false;	/* And clean up local data */	if (rels)		pfree(rels);	if (children)		pfree(children);}/* *	AtAbort_Memory */static voidAtAbort_Memory(void){	/*	 * Make sure we are in a valid context (not a child of	 * TopTransactionContext...).  Note that it is possible for this code to	 * be called when we aren't in a transaction at all; go directly to	 * TopMemoryContext in that case.	 */	if (TopTransactionContext != NULL)	{		MemoryContextSwitchTo(TopTransactionContext);		/*		 * We do not want to destroy the transaction's global state yet, so we		 * can't free any memory here.		 */	}	else		MemoryContextSwitchTo(TopMemoryContext);}/* * AtSubAbort_Memory */static voidAtSubAbort_Memory(void){	Assert(TopTransactionContext != NULL);	MemoryContextSwitchTo(TopTransactionContext);}/* *	AtAbort_ResourceOwner */static voidAtAbort_ResourceOwner(void){	/*	 * Make sure we have a valid ResourceOwner, if possible (else it will be	 * NULL, which is OK)	 */	CurrentResourceOwner = TopTransactionResourceOwner;}/* * AtSubAbort_ResourceOwner */static voidAtSubAbort_ResourceOwner(void){	TransactionState s = CurrentTransactionState;	/* Make sure we have a valid ResourceOwner */	CurrentResourceOwner = s->curTransactionOwner;}/* * AtSubAbort_childXids */static voidAtSubAbort_childXids(void){	TransactionState s = CurrentTransactionState;	/*	 * We keep the child-XID lists in TopTransactionContext (see	 * AtSubCommit_childXids).	This means we'd better free the list	 * explicitly at abort to avoid leakage.	 */	list_free(s->childXids);	s->childXids = NIL;}/* * RecordSubTransactionAbort */static voidRecordSubTransactionAbort(void){	int			nrels;	RelFileNode *rels;	TransactionId xid = GetCurrentTransactionId();	int			nchildren;	TransactionId *children;	/* Get data needed for abort record */	nrels = smgrGetPendingDeletes(false, &rels);	nchildren = xactGetCommittedChildren(&children);	/*	 * If we made neither any transaction-controlled XLOG entries nor any	 * temp-rel updates, and are not going to delete any files, we can omit	 * recording the transaction abort at all.	No one will ever care that it	 * aborted.  (These tests cover our whole transaction tree, and therefore	 * may mark subxacts that don't really need it, but it's probably not	 * worth being tenser.)	 *	 * In this case we needn't worry about marking subcommitted children as	 * aborted, because they didn't mark themselves as subcommitted in the	 * first place; see the optimization in RecordSubTransactionCommit.	 */	if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)	{		START_CRIT_SECTION();		/*		 * We only need to log the abort in XLOG if the transaction made any		 * transaction-controlled XLOG entries or will delete files.		 */		if (MyLastRecPtr.xrecoff != 0 || nrels > 0)		{			XLogRecData rdata[3];			int			lastrdata = 0;			xl_xact_abort xlrec;			XLogRecPtr	recptr;			xlrec.xtime = time(NULL);			xlrec.nrels = nrels;			xlrec.nsubxacts = nchildren;			rdata[0].data = (char *) (&xlrec);			rdata[0].len = MinSizeOfXactAbort;			rdata[0].buffer = InvalidBuffer;			/* dump rels to delete */			if (nrels > 0)			{				rdata[0].next = &(rdata[1]);				rdata[1].data = (char *) rels;				rdata[1].len = nrels * sizeof(RelFileNode);				rdata[1].buffer = InvalidBuffer;				lastrdata = 1;			}			/* dump committed child Xids */			if (nchildren > 0)			{				rdata[lastrdata].next = &(rdata[2]);				rdata[2].data = (char *) children;				rdata[2].len = nchildren * sizeof(TransactionId);				rdata[2].buffer = InvalidBuffer;				lastrdata = 2;			}			rdata[lastrdata].next = NULL;			recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, rdata);			/* Must flush if we are deleting files... */			if (nrels > 0)				XLogFlush(recptr);		}		/*		 * Mark the transaction aborted in clog.  This is not absolutely		 * necessary but XactLockTableWait makes use of it to avoid waiting		 * for already-aborted subtransactions.		 */		TransactionIdAbort(xid);		TransactionIdAbortTree(nchildren, children);		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 (rels)		pfree(rels);	if (children)		pfree(children);}/* ---------------------------------------------------------------- *						CleanupTransaction stuff * ---------------------------------------------------------------- *//* *	AtCleanup_Memory */static voidAtCleanup_Memory(void){	/*	 * Now that we're "out" of a transaction, have the system allocate things	 * in the top memory context instead of per-transaction contexts.	 */	MemoryContextSwitchTo(TopMemoryContext);	Assert(CurrentTransactionState->parent == NULL);	/*	 * Release all transaction-local memory.	 */	if (TopTransactionContext != NULL)		MemoryContextDelete(TopTransactionContext);	TopTransactionContext = NULL;	CurTransactionContext = NULL;	CurrentTransactionState->curTransactionContext = NULL;}/* ---------------------------------------------------------------- *						CleanupSubTransaction stuff * ---------------------------------------------------------------- *//* * AtSubCleanup_Memory */static voidAtSubCleanup_Memory(void){	TransactionState s = CurrentTransactionState;	Assert(s->parent != NULL);	/* Make sure we're not in an about-to-be-deleted context */	MemoryContextSwitchTo(s->parent->curTransactionContext);	CurTransactionContext = s->parent->curTransactionContext;	/*	 * Delete the subxact local memory contexts. Its CurTransactionContext can	 * go too (note this also kills CurTransactionContexts from any children	 * of the subxact).	 */	if (s->curTransactionContext)		MemoryContextDelete(s->curTransactionContext);	s->curTransactionContext = NULL;}/* ---------------------------------------------------------------- *						interface routines * ---------------------------------------------------------------- *//* *	StartTransaction */static voidStartTransaction(void){	TransactionState s;	/*	 * Let's just make sure the state stack is empty	 */	s = &TopTransactionStateData;	CurrentTransactionState = s;	/*	 * check the current transaction state	 */	if (s->state != TRANS_DEFAULT)		elog(WARNING, "StartTransaction while in %s state",			 TransStateAsString(s->state));	/*	 * set the current transaction state information appropriately during	 * start processing	 */	s->state = TRANS_START;	s->transactionId = InvalidTransactionId;	/* until assigned */	/*	 * Make sure we've freed any old snapshot, and reset xact state variables	 */	FreeXactSnapshot();	XactIsoLevel = DefaultXactIsoLevel;	XactReadOnly = DefaultXactReadOnly;	/*	 * reinitialize within-transaction counters	 */	s->subTransactionId = TopSubTransactionId;	currentSubTransactionId = TopSubTransactionId;	currentCommandId = FirstCommandId;	/*	 * must initialize resource-management stuff first	 */	AtStart_Memory();	AtStart_ResourceOwner();	/*	 * generate a new transaction id	 */	s->transactionId = GetNewTransactionId(false);	XactLockTableInsert(s->transactionId);	/*	 * set now()	 */	xactStartTimestamp = GetCurrentTimestamp();	/*	 * initialize current transaction state fields	 */	s->nestingLevel = 1;	s->childXids = NIL;	/*	 * You might expect to see "s->currentUser = GetUserId();" here, but you	 * won't because it doesn't work during startup; the userid isn't set yet	 * during a backend's first transaction start.  We only use the	 * currentUser field in sub-transaction state structs.	 *	 * prevXactReadOnly is also valid only in sub-transactions.	 */	/*	 * initialize other subsystems for new transaction	 */	AtStart_Inval();	AtStart_Cache();	AfterTriggerBeginXact();	/*	 * done with start processing, set current transaction state to "in	 * progress"	 */	s->state = TRANS_INPROGRESS;	ShowTransactionState("StartTransaction");}/* *	CommitTransaction * * NB: if you change this routine, better look at PrepareTransaction too! */static voidCommitTransaction(void){	TransactionState s = CurrentTransactionState;	ShowTransactionState("CommitTransaction");	/*	 * check the current transaction state	 */	if (s->state != TRANS_INPROGRESS)		elog(WARNING, "CommitTransaction while in %s state",			 TransStateAsString(s->state));	Assert(s->parent == NULL);	/*	 * Do pre-commit processing (most of this stuff requires database access,	 * and in fact could still cause an error...)	 *	 * It is possible for CommitHoldablePortals to invoke functions that queue	 * deferred triggers, and it's also possible that triggers create holdable	 * cursors.  So we have to loop until there's nothing left to do.	 */	for (;;)	{		/*		 * Fire all currently pending deferred triggers.		 */		AfterTriggerFireDeferred();		/*		 * Convert any open holdable cursors into static portals.  If there		 * weren't any, we are done ... otherwise loop back to check if they		 * queued deferred triggers.  Lather, rinse, repeat.		 */		if (!CommitHoldablePortals())			break;	}	/* Now we can shut down the deferred-trigger manager */	AfterTriggerEndXact(true);	/* Close any open regular cursors */	AtCommit_Portals();	/*	 * Let ON COMMIT management do its thing (must happen after closing	 * cursors, to avoid dangling-reference problems)	 */	PreCommit_on_commit_actions();	/* close large objects before lower-level cleanup */	AtEOXact_LargeObject(true);	/* NOTIFY commit must come before lower-level cleanup */	AtCommit_Notify();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?