xact.c

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

C
2,442
字号
	/*	 * Update flat files if we changed pg_database, pg_authid or	 * pg_auth_members.  This should be the last step before commit.	 */	AtEOXact_UpdateFlatFiles(true);	/* Prevent cancel/die interrupt while cleaning up */	HOLD_INTERRUPTS();	/*	 * set the current transaction state information appropriately during	 * commit processing	 */	s->state = TRANS_COMMIT;	/*	 * Here is where we really truly commit.	 */	RecordTransactionCommit();	/*----------	 * Let others know about no transaction in progress by me. Note that	 * this must be done _before_ releasing locks we hold and _after_	 * RecordTransactionCommit.	 *	 * 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.	 *	 * Note: MyProc may be null during bootstrap.	 *----------	 */	if (MyProc != NULL)	{		/* Lock ProcArrayLock because that's what GetSnapshotData uses. */		LWLockAcquire(ProcArrayLock, 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(ProcArrayLock);	}	/*	 * This is all post-commit cleanup.  Note that if an error is raised here,	 * it's too late to abort the transaction.  This should be just	 * noncritical resource releasing.	 *	 * The ordering of operations is not entirely random.  The idea is:	 * release resources visible to other backends (eg, files, buffer 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.	 */	CallXactCallbacks(XACT_EVENT_COMMIT);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_BEFORE_LOCKS,						 true, true);	/* Check we've released all buffer pins */	AtEOXact_Buffers(true);	/* Clean up the relation cache */	AtEOXact_RelationCache(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);	/*	 * Likewise, dropping of files deleted during the transaction is best done	 * after releasing relcache and buffer pins.  (This is not strictly	 * necessary during commit, since such pins should have been released	 * already, but this ordering is definitely critical during abort.)	 */	smgrDoPendingDeletes(true);	AtEOXact_MultiXact();	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_LOCKS,						 true, true);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_AFTER_LOCKS,						 true, true);	/* Check we've released all catcache entries */	AtEOXact_CatCache(true);	AtEOXact_GUC(true, false);	AtEOXact_SPI(true);	AtEOXact_on_commit_actions(true);	AtEOXact_Namespace(true);	/* smgrcommit already done */	AtEOXact_Files();	pgstat_count_xact_commit();	CurrentResourceOwner = NULL;	ResourceOwnerDelete(TopTransactionResourceOwner);	s->curTransactionOwner = NULL;	CurTransactionResourceOwner = NULL;	TopTransactionResourceOwner = NULL;	AtCommit_Memory();	s->transactionId = InvalidTransactionId;	s->subTransactionId = InvalidSubTransactionId;	s->nestingLevel = 0;	s->childXids = NIL;	/*	 * done with commit processing, set current transaction state back to	 * default	 */	s->state = TRANS_DEFAULT;	RESUME_INTERRUPTS();}/* *	PrepareTransaction * * NB: if you change this routine, better look at CommitTransaction too! */static voidPrepareTransaction(void){	TransactionState s = CurrentTransactionState;	TransactionId xid = GetCurrentTransactionId();	GlobalTransaction gxact;	TimestampTz prepared_at;	ShowTransactionState("PrepareTransaction");	/*	 * check the current transaction state	 */	if (s->state != TRANS_INPROGRESS)		elog(WARNING, "PrepareTransaction 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 PrepareHoldablePortals 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 (!PrepareHoldablePortals())			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 and flatfiles will be handled below */	/* Prevent cancel/die interrupt while cleaning up */	HOLD_INTERRUPTS();	/*	 * set the current transaction state information appropriately during	 * prepare processing	 */	s->state = TRANS_PREPARE;	prepared_at = GetCurrentTimestamp();	/* Tell bufmgr and smgr to prepare for commit */	BufmgrCommit();	/*	 * Reserve the GID for this transaction. This could fail if the requested	 * GID is invalid or already in use.	 */	gxact = MarkAsPreparing(xid, prepareGID, prepared_at,							GetUserId(), MyDatabaseId);	prepareGID = NULL;	/*	 * Collect data for the 2PC state file.  Note that in general, no actual	 * state change should happen in the called modules during this step,	 * since it's still possible to fail before commit, and in that case we	 * want transaction abort to be able to clean up.  (In particular, the	 * AtPrepare routines may error out if they find cases they cannot	 * handle.)  State cleanup should happen in the PostPrepare routines	 * below.  However, some modules can go ahead and clear state here because	 * they wouldn't do anything with it during abort anyway.	 *	 * Note: because the 2PC state file records will be replayed in the same	 * order they are made, the order of these calls has to match the order in	 * which we want things to happen during COMMIT PREPARED or ROLLBACK	 * PREPARED; in particular, pay attention to whether things should happen	 * before or after releasing the transaction's locks.	 */	StartPrepare(gxact);	AtPrepare_Notify();	AtPrepare_UpdateFlatFiles();	AtPrepare_Inval();	AtPrepare_Locks();	/*	 * Here is where we really truly prepare.	 *	 * We have to record transaction prepares even if we didn't make any	 * updates, because the transaction manager might get confused if we lose	 * a global transaction.	 */	EndPrepare(gxact);	/*	 * Now we clean up backend-internal state and release internal resources.	 */	/* Break the chain of back-links in the XLOG records I output */	MyLastRecPtr.xrecoff = 0;	MyXactMadeXLogEntry = false;	MyXactMadeTempRelUpdate = false;	/*	 * Let others know about no transaction in progress by me.	This has to be	 * done *after* the prepared transaction has been marked valid, else	 * someone may think it is unlocked and recyclable.	 */	/* Lock ProcArrayLock because that's what GetSnapshotData uses. */	LWLockAcquire(ProcArrayLock, 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(ProcArrayLock);	/*	 * This is all post-transaction cleanup.  Note that if an error is raised	 * here, it's too late to abort the transaction.  This should be just	 * noncritical resource releasing.	See notes in CommitTransaction.	 */	CallXactCallbacks(XACT_EVENT_PREPARE);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_BEFORE_LOCKS,						 true, true);	/* Check we've released all buffer pins */	AtEOXact_Buffers(true);	/* Clean up the relation cache */	AtEOXact_RelationCache(true);	/* notify and flatfiles don't need a postprepare call */	PostPrepare_Inval();	PostPrepare_smgr();	AtEOXact_MultiXact();	PostPrepare_Locks(xid);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_LOCKS,						 true, true);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_AFTER_LOCKS,						 true, true);	/* Check we've released all catcache entries */	AtEOXact_CatCache(true);	/* PREPARE acts the same as COMMIT as far as GUC is concerned */	AtEOXact_GUC(true, false);	AtEOXact_SPI(true);	AtEOXact_on_commit_actions(true);	AtEOXact_Namespace(true);	/* smgrcommit already done */	AtEOXact_Files();	CurrentResourceOwner = NULL;	ResourceOwnerDelete(TopTransactionResourceOwner);	s->curTransactionOwner = NULL;	CurTransactionResourceOwner = NULL;	TopTransactionResourceOwner = NULL;	AtCommit_Memory();	s->transactionId = InvalidTransactionId;	s->subTransactionId = InvalidSubTransactionId;	s->nestingLevel = 0;	s->childXids = NIL;	/*	 * done with 1st phase commit processing, set current transaction state	 * back to default	 */	s->state = TRANS_DEFAULT;	RESUME_INTERRUPTS();}/* *	AbortTransaction */static voidAbortTransaction(void){	TransactionState s = CurrentTransactionState;	/* Prevent cancel/die interrupt while cleaning up */	HOLD_INTERRUPTS();	/*	 * Release any LW locks we might be holding as quickly as possible.	 * (Regular locks, however, must be held till we finish aborting.)	 * Releasing LW locks is critical since we might try to grab them again	 * while cleaning up!	 */	LWLockReleaseAll();	/* Clean up buffer I/O and buffer context locks, too */	AbortBufferIO();	UnlockBuffers();	/*	 * Also clean up any open wait for lock, since the lock manager will choke	 * if we try to wait for another lock before doing this.	 */	LockWaitCancel();	/*	 * check the current transaction state	 */	if (s->state != TRANS_INPROGRESS && s->state != TRANS_PREPARE)		elog(WARNING, "AbortTransaction while in %s state",			 TransStateAsString(s->state));	Assert(s->parent == NULL);	/*	 * set the current transaction state information appropriately during the	 * abort processing	 */	s->state = TRANS_ABORT;	/* Make sure we have a valid memory context and resource owner */	AtAbort_Memory();	AtAbort_ResourceOwner();	/*	 * Reset user id which might have been changed transiently.  We cannot use	 * s->currentUser, since it may not be set yet; instead rely on internal	 * state of miscinit.c.	 *	 * (Note: it is not necessary to restore session authorization here	 * because that can only be changed via GUC, and GUC will take care of	 * rolling it back if need be.	However, an error within a SECURITY	 * DEFINER function could send control here with the wrong current	 * userid.)	 */	AtAbort_UserId();	/*	 * do abort processing	 */	AfterTriggerEndXact(false);	AtAbort_Portals();	AtEOXact_LargeObject(false);	/* 'false' means it's abort */	AtAbort_Notify();	AtEOXact_UpdateFlatFiles(false);	/*	 * Advertise the fact that we aborted in pg_clog (assuming that we got as	 * far as assigning an XID to advertise).	 */	if (TransactionIdIsValid(s->transactionId))		RecordTransactionAbort();	/*	 * Let others know about no transaction in progress by me. Note that this	 * must be done _before_ releasing locks we hold and _after_	 * RecordTransactionAbort.	 */	if (MyProc != NULL)	{		/* Lock ProcArrayLock because that's what GetSnapshotData uses. */		LWLockAcquire(ProcArrayLock, 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(ProcArrayLock);	}	/*	 * Post-abort cleanup.	See notes in CommitTransaction() concerning	 * ordering.	 */	CallXactCallbacks(XACT_EVENT_ABORT);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_BEFORE_LOCKS,						 false, true);	AtEOXact_Buffers(false);	AtEOXact_RelationCache(false);	AtEOXact_Inval(false);	smgrDoPendingDeletes(false);	AtEOXact_MultiXact();	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_LOCKS,						 false, true);	ResourceOwnerRelease(TopTransactionResourceOwner,						 RESOURCE_RELEASE_AFTER_LOCKS,						 false, true);	AtEOXact_CatCache(false);	AtEOXact_GUC(false, false);	AtEOXact_SPI(false);	AtEOXact_on_commit_actions(false);	AtEOXact_Namespace(false);	smgrabort();	AtEOXact_Files();	pgstat_count_xact_rollback();	/*	 * State remains TRANS_ABORT until CleanupTransaction().	 */	RESUME_INTERRUPTS();}/* *	CleanupTransaction */static voidCleanupTransaction(void){

⌨️ 快捷键说明

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