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