📄 xact.c
字号:
TimestampTzGetCurrentTransactionStartTimestamp(void){ return xactStartTimestamp;}/* * GetCurrentStatementStartTimestamp */TimestampTzGetCurrentStatementStartTimestamp(void){ return stmtStartTimestamp;}/* * GetCurrentTransactionStopTimestamp * * We return current time if the transaction stop time hasn't been set * (which can happen if we decide we don't need to log an XLOG record). */TimestampTzGetCurrentTransactionStopTimestamp(void){ if (xactStopTimestamp != 0) return xactStopTimestamp; return GetCurrentTimestamp();}/* * SetCurrentStatementStartTimestamp */voidSetCurrentStatementStartTimestamp(void){ stmtStartTimestamp = GetCurrentTimestamp();}/* * SetCurrentTransactionStopTimestamp */static inline voidSetCurrentTransactionStopTimestamp(void){ xactStopTimestamp = GetCurrentTimestamp();}/* * GetCurrentTransactionNestLevel * * Note: this will return zero when not inside any transaction, one when * inside a top-level transaction, etc. */intGetCurrentTransactionNestLevel(void){ TransactionState s = CurrentTransactionState; return s->nestingLevel;}/* * TransactionIdIsCurrentTransactionId */boolTransactionIdIsCurrentTransactionId(TransactionId xid){ TransactionState s; /* * We always say that BootstrapTransactionId is "not my transaction ID" * even when it is (ie, during bootstrap). Along with the fact that * transam.c always treats BootstrapTransactionId as already committed, * this causes the tqual.c routines to see all tuples as committed, which * is what we need during bootstrap. (Bootstrap mode only inserts tuples, * it never updates or deletes them, so all tuples can be presumed good * immediately.) * * Likewise, InvalidTransactionId and FrozenTransactionId are certainly * not my transaction ID, so we can just return "false" immediately for * any non-normal XID. */ if (!TransactionIdIsNormal(xid)) return false; /* * We will return true for the Xid of the current subtransaction, any of * its subcommitted children, any of its parents, or any of their * previously subcommitted children. However, a transaction being aborted * is no longer "current", even though it may still have an entry on the * state stack. */ for (s = CurrentTransactionState; s != NULL; s = s->parent) { int low, high; if (s->state == TRANS_ABORT) continue; if (!TransactionIdIsValid(s->transactionId)) continue; /* it can't have any child XIDs either */ if (TransactionIdEquals(xid, s->transactionId)) return true; /* As the childXids array is ordered, we can use binary search */ low = 0; high = s->nChildXids - 1; while (low <= high) { int middle; TransactionId probe; middle = low + (high - low) / 2; probe = s->childXids[middle]; if (TransactionIdEquals(probe, xid)) return true; else if (TransactionIdPrecedes(probe, xid)) low = middle + 1; else high = middle - 1; } } return false;}/* * CommandCounterIncrement */voidCommandCounterIncrement(void){ /* * If the current value of the command counter hasn't been "used" to * mark tuples, we need not increment it, since there's no need to * distinguish a read-only command from others. This helps postpone * command counter overflow, and keeps no-op CommandCounterIncrement * operations cheap. */ if (currentCommandIdUsed) { 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"))); } currentCommandIdUsed = false; /* Propagate new command ID into static snapshots, if set */ if (SerializableSnapshot) SerializableSnapshot->curcid = currentCommandId; if (LatestSnapshot) LatestSnapshot->curcid = currentCommandId; /* * Make any catalog changes done by the just-completed command * visible in the local syscache. We obviously don't need to do * this after a read-only command. (But see hacks in inval.c * to make real sure we don't think a command that queued inval * messages was read-only.) */ AtCommit_LocalCache(); } /* * Make any other backends' catalog changes visible to me. * * XXX this is probably in the wrong place: CommandCounterIncrement * should be purely a local operation, most likely. However fooling * with this will affect asynchronous cross-backend interactions, * which doesn't seem like a wise thing to do in late beta, so save * improving this for another day - tgl 2007-11-30 */ AtStart_Cache();}/* * ForceSyncCommit * * Interface routine to allow commands to force a synchronous commit of the * current top-level transaction */voidForceSyncCommit(void){ forceSyncCommit = true;}/* ---------------------------------------------------------------- * StartTransaction stuff * ---------------------------------------------------------------- *//* * AtStart_Cache */static voidAtStart_Cache(void){ AcceptInvalidationMessages();}/* * AtStart_Memory */static voidAtStart_Memory(void){ TransactionState s = CurrentTransactionState; /* * If this is the first time through, create a private context for * AbortTransaction to work in. By reserving some space now, we can * insulate AbortTransaction from out-of-memory scenarios. Like * ErrorContext, we set it up with slow growth rate and a nonzero minimum * size, so that space will be reserved immediately. */ if (TransactionAbortContext == NULL) TransactionAbortContext = AllocSetContextCreate(TopMemoryContext, "TransactionAbortContext", 32 * 1024, 32 * 1024, 32 * 1024); /* * 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 * * Returns latest XID among xact and its children, or InvalidTransactionId * if the xact has no XID. (We compute that here just because it's easier.) * * This is exported only to support an ugly hack in VACUUM FULL. */TransactionIdRecordTransactionCommit(void){ TransactionId xid = GetTopTransactionIdIfAny(); bool markXidCommitted = TransactionIdIsValid(xid); TransactionId latestXid = InvalidTransactionId; int nrels; RelFileNode *rels; bool haveNonTemp; int nchildren; TransactionId *children; /* Get data needed for commit record */ nrels = smgrGetPendingDeletes(true, &rels, &haveNonTemp); nchildren = xactGetCommittedChildren(&children); /* * If we haven't been assigned an XID yet, we neither can, nor do we want * to write a COMMIT record. */ if (!markXidCommitted) { /* * We expect that every smgrscheduleunlink is followed by a catalog * update, and hence XID assignment, so we shouldn't get here with any * pending deletes. Use a real test not just an Assert to check this, * since it's a bit fragile. */ if (nrels != 0) elog(ERROR, "cannot commit a transaction that deleted files but has no xid"); /* Can't have child XIDs either; AssignTransactionId enforces this */ Assert(nchildren == 0); /* * If we didn't create XLOG entries, we're done here; otherwise we * should flush those entries the same as a commit record. (An * example of a possible record that wouldn't cause an XID to be * assigned is a sequence advance record due to nextval() --- we want * to flush that to disk before reporting commit.) */ if (XactLastRecEnd.xrecoff == 0) goto cleanup; } else { /* * Begin commit critical section and insert the commit XLOG record. */ XLogRecData rdata[3]; int lastrdata = 0; xl_xact_commit xlrec; /* Tell bufmgr and smgr to prepare for commit */ BufmgrCommit(); /* * Mark ourselves as within our "commit critical section". This * forces any concurrent checkpoint to wait until we've updated * pg_clog. Without this, 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 the system * crashes a little later. * * Note: we could, but don't bother to, set this flag in * RecordTransactionAbort. That's because loss of a transaction abort * is noncritical; the presumption would be that it aborted, anyway. * * It's safe to change the inCommit flag of our own backend without * holding the ProcArrayLock, since we're the only one modifying it. * This makes checkpoint's determination of which xacts are inCommit a * bit fuzzy, but it doesn't matter. */ START_CRIT_SECTION(); MyProc->inCommit = true; SetCurrentTransactionStopTimestamp(); xlrec.xact_time = xactStopTimestamp; 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; (void) XLogInsert(RM_XACT_ID, XLOG_XACT_COMMIT, rdata); } /* * Check if we want to commit asynchronously. If the user has set * synchronous_commit = off, and we're not doing cleanup of any non-temp * rels nor committing any command that wanted to force sync commit, then * we can defer flushing XLOG. (We must not allow asynchronous commit if * there are any non-temp tables to be deleted, because we might delete * the files before the COMMIT record is flushed to disk. We do allow * asynchronous commit if all to-be-deleted tables are temporary though, * since they are lost anyway if we crash.) */ if (XactSyncCommit || forceSyncCommit || haveNonTemp) { /* * Synchronous commit case. * * 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.)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -