xact.c

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

C
2,442
字号
}/* *	CommandCounterIncrement */voidCommandCounterIncrement(void){	currentCommandId += 1;	if (currentCommandId == FirstCommandId)		/* check for overflow */	{		currentCommandId -= 1;		ereport(ERROR,				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),		  errmsg("cannot have more than 2^32-1 commands in a transaction")));	}	/* Propagate new command ID into static snapshots, if set */	if (SerializableSnapshot)		SerializableSnapshot->curcid = currentCommandId;	if (LatestSnapshot)		LatestSnapshot->curcid = currentCommandId;	/*	 * make cache changes visible to me.	 */	AtCommit_LocalCache();	AtStart_Cache();}/* ---------------------------------------------------------------- *						StartTransaction stuff * ---------------------------------------------------------------- *//* *	AtStart_Cache */static voidAtStart_Cache(void){	AcceptInvalidationMessages();}/* *	AtStart_Memory */static voidAtStart_Memory(void){	TransactionState s = CurrentTransactionState;	/*	 * We shouldn't have a transaction context already.	 */	Assert(TopTransactionContext == NULL);	/*	 * Create a toplevel context for the transaction.	 */	TopTransactionContext =		AllocSetContextCreate(TopMemoryContext,							  "TopTransactionContext",							  ALLOCSET_DEFAULT_MINSIZE,							  ALLOCSET_DEFAULT_INITSIZE,							  ALLOCSET_DEFAULT_MAXSIZE);	/*	 * In a top-level transaction, CurTransactionContext is the same as	 * TopTransactionContext.	 */	CurTransactionContext = TopTransactionContext;	s->curTransactionContext = CurTransactionContext;	/* Make the CurTransactionContext active. */	MemoryContextSwitchTo(CurTransactionContext);}/* *	AtStart_ResourceOwner */static voidAtStart_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 * ---------------------------------------------------------------- *//* * AtSubStart_Memory */static voidAtSubStart_Memory(void){	TransactionState s = CurrentTransactionState;	Assert(CurTransactionContext != NULL);	/*	 * Create a CurTransactionContext, which will be used to hold data that	 * survives subtransaction commit but disappears on subtransaction abort.	 * We make it a child of the immediate parent's CurTransactionContext.	 */	CurTransactionContext = AllocSetContextCreate(CurTransactionContext,												  "CurTransactionContext",												  ALLOCSET_DEFAULT_MINSIZE,												  ALLOCSET_DEFAULT_INITSIZE,												  ALLOCSET_DEFAULT_MAXSIZE);	s->curTransactionContext = CurTransactionContext;	/* Make the CurTransactionContext active. */	MemoryContextSwitchTo(CurTransactionContext);}/* * AtSubStart_ResourceOwner */static voidAtSubStart_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 * ---------------------------------------------------------------- *//* *	RecordTransactionCommit */voidRecordTransactionCommit(void){	int			nrels;	RelFileNode *rels;	int			nchildren;	TransactionId *children;	/* Get data needed for commit record */	nrels = smgrGetPendingDeletes(true, &rels);	nchildren = xactGetCommittedChildren(&children);	/*	 * If we made neither any XLOG entries nor any temp-rel updates, and have	 * no files to be deleted, we can omit recording the transaction commit at	 * all.  (This test includes the effects of subtransactions, so the	 * presence of committed subxacts need not alone force a write.)	 */	if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate || nrels > 0)	{		TransactionId xid = GetCurrentTransactionId();		bool		madeTCentries;		XLogRecPtr	recptr;		/* Tell bufmgr and smgr to prepare for commit */		BufmgrCommit();		START_CRIT_SECTION();		/*		 * If our transaction made any transaction-controlled XLOG entries, we		 * need to lock out checkpoint start between writing our XLOG record		 * and updating pg_clog.  Otherwise it is possible for the checkpoint		 * to set REDO after the XLOG record but fail to flush the pg_clog		 * update to disk, leading to loss of the transaction commit if we		 * crash a little later.  Slightly klugy fix for problem discovered		 * 2004-08-10.		 *		 * (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; so it doesn't matter if we lose the commit flag.)		 *		 * Note we only need a shared lock.		 */		madeTCentries = (MyLastRecPtr.xrecoff != 0);		if (madeTCentries)			LWLockAcquire(CheckpointStartLock, LW_SHARED);		/*		 * We only need to log the commit in XLOG if the transaction made any		 * transaction-controlled XLOG entries or will delete files.		 */		if (madeTCentries || nrels > 0)		{			XLogRecData rdata[3];			int			lastrdata = 0;			xl_xact_commit xlrec;			xlrec.xtime = time(NULL);			xlrec.nrels = nrels;			xlrec.nsubxacts = nchildren;			rdata[0].data = (char *) (&xlrec);			rdata[0].len = MinSizeOfXactCommit;			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_COMMIT, rdata);		}		else		{			/* Just flush through last record written by me */			recptr = ProcLastRecEnd;		}		/*		 * We must flush our XLOG entries to disk if we made any XLOG entries,		 * whether in or out of transaction control.  For example, if we		 * reported a nextval() result to the client, this ensures that any		 * XLOG record generated by nextval will hit the disk before we report		 * the transaction committed.		 *		 * Note: if we generated a commit record above, MyXactMadeXLogEntry		 * will certainly be set now.		 */		if (MyXactMadeXLogEntry)		{			/*			 * Sleep before flush! So we can flush more than one commit			 * records per single fsync.  (The idea is some other backend may			 * do the XLogFlush while we're sleeping.  This needs work still,			 * because on most Unixen, the minimum select() delay is 10msec or			 * more, which is way too long.)			 *			 * We do not sleep if enableFsync is not turned on, nor if there			 * are fewer than CommitSiblings other backends with active			 * transactions.			 */			if (CommitDelay > 0 && enableFsync &&				CountActiveBackends() >= CommitSiblings)				pg_usleep(CommitDelay);			XLogFlush(recptr);		}		/*		 * We must mark the transaction committed in clog if its XID appears		 * either in permanent rels or in local temporary rels. We test this		 * by seeing if we made transaction-controlled entries *OR* local-rel		 * tuple updates.  Note that if we made only the latter, we have not		 * emitted an XLOG record for our commit, and so in the event of a		 * crash the clog update might be lost.  This is okay because no one		 * else will ever care whether we committed.		 */		if (madeTCentries || MyXactMadeTempRelUpdate)		{			TransactionIdCommit(xid);			/* to avoid race conditions, the parent must commit first */			TransactionIdCommitTree(nchildren, children);		}		/* Unlock checkpoint lock if we acquired it */		if (madeTCentries)			LWLockRelease(CheckpointStartLock);		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);}/* *	AtCommit_LocalCache */static voidAtCommit_LocalCache(void){	/*	 * Make catalog changes visible to me for the next command.	 */	CommandEndInvalidationMessages();}/* *	AtCommit_Memory */static voidAtCommit_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);	/*	 * Release all transaction-local memory.	 */	Assert(TopTransactionContext != NULL);	MemoryContextDelete(TopTransactionContext);	TopTransactionContext = NULL;	CurTransactionContext = NULL;	CurrentTransactionState->curTransactionContext = NULL;}/* ---------------------------------------------------------------- *						CommitSubTransaction stuff * ---------------------------------------------------------------- *//* * AtSubCommit_Memory */static voidAtSubCommit_Memory(void){	TransactionState s = CurrentTransactionState;	Assert(s->parent != NULL);	/* Return to parent transaction level's memory context. */	CurTransactionContext = s->parent->curTransactionContext;	MemoryContextSwitchTo(CurTransactionContext);	/*	 * Ordinarily we cannot throw away the child's CurTransactionContext,	 * since the data it contains will be needed at upper commit.  However, if	 * there isn't actually anything in it, we can throw it away.  This avoids	 * a small memory leak in the common case of "trivial" subxacts.	 */	if (MemoryContextIsEmpty(s->curTransactionContext))	{		MemoryContextDelete(s->curTransactionContext);		s->curTransactionContext = NULL;	}}/* * AtSubCommit_childXids * * Pass my own XID and my child XIDs up to my parent as committed children. */static voidAtSubCommit_childXids(void){	TransactionState s = CurrentTransactionState;	MemoryContext old_cxt;	Assert(s->parent != NULL);	/*	 * We keep the child-XID lists in TopTransactionContext; this avoids	 * setting up child-transaction contexts for what might be just a few	 * bytes of grandchild XIDs.	 */	old_cxt = MemoryContextSwitchTo(TopTransactionContext);	s->parent->childXids = lappend_xid(s->parent->childXids,									   s->transactionId);	if (s->childXids != NIL)	{		s->parent->childXids = list_concat(s->parent->childXids,										   s->childXids);		/*		 * list_concat doesn't free the list header for the second list; do so		 * here to avoid memory leakage (kluge)		 */		pfree(s->childXids);		s->childXids = NIL;	}	MemoryContextSwitchTo(old_cxt);}/* * RecordSubTransactionCommit */static voidRecordSubTransactionCommit(void){	/*	 * We do not log the subcommit in XLOG; it doesn't matter until the	 * top-level transaction commits.	 *	 * We must mark the subtransaction subcommitted in clog if its XID appears	 * either in permanent rels or in local temporary rels. We test this by	 * seeing if we made transaction-controlled entries *OR* local-rel tuple	 * updates.  (The test here actually covers the entire transaction tree so	 * far, so it may mark subtransactions that don't really need it, but it's	 * probably not worth being tenser. Note that if a prior subtransaction	 * dirtied these variables, then RecordTransactionCommit will have to do	 * the full pushup anyway...)	 */	if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)	{		TransactionId xid = GetCurrentTransactionId();		/* XXX does this really need to be a critical section? */		START_CRIT_SECTION();		/* Record subtransaction subcommit */		TransactionIdSubCommit(xid);		END_CRIT_SECTION();	}}/* ---------------------------------------------------------------- *						AbortTransaction stuff * ---------------------------------------------------------------- *//* *	RecordTransactionAbort */static voidRecordTransactionAbort(void){	int			nrels;	RelFileNode *rels;	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.)	 */	if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate || nrels > 0)	{		TransactionId xid = GetCurrentTransactionId();

⌨️ 快捷键说明

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