📄 xact.c
字号:
static voidAtCleanup_Memory(void){ Assert(CurrentTransactionState->parent == NULL); /* * 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); /* * Clear the special abort context for next time. */ if (TransactionAbortContext != NULL) MemoryContextResetAndDeleteChildren(TransactionAbortContext); /* * 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; /* * Clear the special abort context for next time. */ if (TransactionAbortContext != NULL) MemoryContextResetAndDeleteChildren(TransactionAbortContext); /* * 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; VirtualTransactionId vxid; /* * 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; forceSyncCommit = false; MyXactAccessedTempRel = false; /* * reinitialize within-transaction counters */ s->subTransactionId = TopSubTransactionId; currentSubTransactionId = TopSubTransactionId; currentCommandId = FirstCommandId; currentCommandIdUsed = false; /* * must initialize resource-management stuff first */ AtStart_Memory(); AtStart_ResourceOwner(); /* * Assign a new LocalTransactionId, and combine it with the backendId to * form a virtual transaction id. */ vxid.backendId = MyBackendId; vxid.localTransactionId = GetNextLocalTransactionId(); /* * Lock the virtual transaction id before we announce it in the proc array */ VirtualXactLockTableInsert(vxid); /* * Advertise it in the proc array. We assume assignment of * LocalTransactionID is atomic, and the backendId should be set already. */ Assert(MyProc->backendId == vxid.backendId); MyProc->lxid = vxid.localTransactionId; PG_TRACE1(transaction__start, vxid.localTransactionId); /* * set transaction_timestamp() (a/k/a now()). We want this to be the same * as the first command's statement_timestamp(), so don't do a fresh * GetCurrentTimestamp() call (which'd be expensive anyway). Also, mark * xactStopTimestamp as unset. */ xactStartTimestamp = stmtStartTimestamp; xactStopTimestamp = 0; pgstat_report_xact_timestamp(xactStartTimestamp); /* * initialize current transaction state fields * * note: prevXactReadOnly is not used at the outermost level */ s->nestingLevel = 1; s->gucNestLevel = 1; s->childXids = NULL; s->nChildXids = 0; s->maxChildXids = 0; GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt); /* SecurityDefinerContext should never be set outside a transaction */ Assert(!s->prevSecDefCxt); /* * initialize other subsystems for new transaction */ AtStart_GUC(); 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; TransactionId latestXid; 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(); /* * 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. */ latestXid = RecordTransactionCommit(); PG_TRACE1(transaction__commit, MyProc->lxid); /* * Let others know about no transaction in progress by me. Note that this * must be done _before_ releasing locks we hold and _after_ * RecordTransactionCommit. */ ProcArrayEndTransaction(MyProc, latestXid); /* * 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, 1); AtEOXact_SPI(true); AtEOXact_xml(); AtEOXact_on_commit_actions(true); AtEOXact_Namespace(true); /* smgrcommit already done */ AtEOXact_Files(); AtEOXact_ComboCid(); AtEOXact_HashTables(true); AtEOXact_PgStat(true); pgstat_report_xact_timestamp(0); CurrentResourceOwner = NULL; ResourceOwnerDelete(TopTransactionResourceOwner); s->curTransactionOwner = NULL; CurTransactionResourceOwner = NULL; TopTransactionResourceOwner = NULL; AtCommit_Memory(); s->transactionId = InvalidTransactionId; s->subTransactionId = InvalidSubTransactionId; s->nestingLevel = 0; s->gucNestLevel = 0; s->childXids = NULL; s->nChildXids = 0; s->maxChildXids = 0; /* * 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 */ /* * Don't allow PREPARE TRANSACTION if we've accessed a temporary table * in this transaction. Having the prepared xact hold locks on another * backend's temp table seems a bad idea --- for instance it would prevent * the backend from exiting. There are other problems too, such as how * to clean up the source backend's local buffers and ON COMMIT state * if the prepared xact includes a DROP of a temp table. * * We must check this after executing any ON COMMIT actions, because * they might still access a temp relation. * * XXX In principle this could be relaxed to allow some useful special * cases, such as a temp table created and dropped all within the * transaction. That seems to require much more bookkeeping though. */ if (MyXactAccessedTempRel) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot PREPARE a transaction that has operated on temporary tables"))); /* 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -