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 + -
显示快捷键?