diff options
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r-- | src/backend/access/transam/xact.c | 180 |
1 files changed, 99 insertions, 81 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 3a992f6ccfe..c9b60daef56 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.129 2002/08/02 22:36:05 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.130 2002/08/06 02:36:33 tgl Exp $ * * NOTES * Transaction aborts can now occur two ways: @@ -505,44 +505,32 @@ AtStart_Memory(void) * ---------------------------------------------------------------- */ -/* -------------------------------- +/* * RecordTransactionCommit - * - * Note: the two calls to BufferManagerFlush() exist to ensure - * that data pages are written before log pages. These - * explicit calls should be replaced by a more efficient - * ordered page write scheme in the buffer manager - * -cim 3/18/90 - * -------------------------------- */ void RecordTransactionCommit(void) { - TransactionId xid; - bool leak; - - leak = BufferPoolCheckLeak(); - - xid = GetCurrentTransactionId(); - /* - * We only need to log the commit in xlog and clog if the transaction made - * any transaction-controlled XLOG entries. (Otherwise, its XID appears - * nowhere in permanent storage, so no one will ever care if it - * committed.) However, we must flush XLOG 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. + * If we made neither any XLOG entries nor any temp-rel updates, + * we can omit recording the transaction commit at all. */ - if (MyXactMadeXLogEntry) + if (MyXactMadeXLogEntry || MyXactMadeTempRelUpdate) { + TransactionId xid = GetCurrentTransactionId(); XLogRecPtr recptr; + /* Tell bufmgr and smgr to prepare for commit */ BufmgrCommit(); START_CRIT_SECTION(); + /* + * We only need to log the commit in xlog if the transaction made any + * transaction-controlled XLOG entries. (Otherwise, its XID appears + * nowhere in permanent storage, so no one else will ever care if it + * committed.) + */ if (MyLastRecPtr.xrecoff != 0) { /* Need to emit a commit record */ @@ -567,30 +555,48 @@ RecordTransactionCommit(void) } /* - * 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. + * 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. */ - if (CommitDelay > 0 && enableFsync && - CountActiveBackends() >= CommitSiblings) + if (MyXactMadeXLogEntry) { - struct timeval delay; + /* + * 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) + { + struct timeval delay; - delay.tv_sec = 0; - delay.tv_usec = CommitDelay; - (void) select(0, NULL, NULL, NULL, &delay); - } + delay.tv_sec = 0; + delay.tv_usec = CommitDelay; + (void) select(0, NULL, NULL, NULL, &delay); + } - XLogFlush(recptr); + XLogFlush(recptr); + } - /* Mark the transaction committed in clog, if needed */ - if (MyLastRecPtr.xrecoff != 0) + /* + * 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 (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate) TransactionIdCommit(xid); END_CRIT_SECTION(); @@ -599,12 +605,10 @@ RecordTransactionCommit(void) /* Break the chain of back-links in the XLOG records I output */ MyLastRecPtr.xrecoff = 0; MyXactMadeXLogEntry = false; + MyXactMadeTempRelUpdate = false; /* Show myself as out of the transaction in PGPROC array */ MyProc->logRec.xrecoff = 0; - - if (leak) - ResetBufferPool(true); } @@ -615,8 +619,10 @@ RecordTransactionCommit(void) static void AtCommit_Cache(void) { - /* Check for relcache reference-count leaks */ - AtEOXactRelationCache(true); + /* + * Clean up the relation cache. + */ + AtEOXact_RelationCache(true); /* * Make catalog changes visible to all backends. */ @@ -679,45 +685,60 @@ AtCommit_Memory(void) * ---------------------------------------------------------------- */ -/* -------------------------------- +/* * RecordTransactionAbort - * -------------------------------- */ static void RecordTransactionAbort(void) { - TransactionId xid = GetCurrentTransactionId(); - /* - * We only need to log the abort in xlog and clog if the transaction made - * any transaction-controlled XLOG entries. (Otherwise, its XID appears - * nowhere in permanent storage, so no one will ever care if it - * committed.) We do not flush XLOG to disk in any case, since the - * default assumption after a crash would be that we aborted, anyway. - * - * Extra check here is to catch case that we aborted partway through - * RecordTransactionCommit ... + * If we made neither any transaction-controlled XLOG entries nor any + * temp-rel updates, we can omit recording the transaction abort at all. + * No one will ever care that it aborted. */ - if (MyLastRecPtr.xrecoff != 0 && !TransactionIdDidCommit(xid)) + if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate) { - XLogRecData rdata; - xl_xact_abort xlrec; - XLogRecPtr recptr; + TransactionId xid = GetCurrentTransactionId(); - xlrec.xtime = time(NULL); - rdata.buffer = InvalidBuffer; - rdata.data = (char *) (&xlrec); - rdata.len = SizeOfXactAbort; - rdata.next = NULL; + /* + * Catch the scenario where we aborted partway through + * RecordTransactionCommit ... + */ + if (TransactionIdDidCommit(xid)) + elog(PANIC, "RecordTransactionAbort: xact %u already committed", + xid); START_CRIT_SECTION(); /* - * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP + * We only need to log the abort in XLOG if the transaction made any + * transaction-controlled XLOG entries. (Otherwise, its XID appears + * nowhere in permanent storage, so no one else will ever care if it + * committed.) We do not flush XLOG to disk in any case, since the + * default assumption after a crash would be that we aborted, anyway. */ - recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata); + if (MyLastRecPtr.xrecoff != 0) + { + XLogRecData rdata; + xl_xact_abort xlrec; + XLogRecPtr recptr; + + xlrec.xtime = time(NULL); + rdata.buffer = InvalidBuffer; + rdata.data = (char *) (&xlrec); + rdata.len = SizeOfXactAbort; + rdata.next = NULL; + + /* + * SHOULD SAVE ARRAY OF RELFILENODE-s TO DROP + */ + recptr = XLogInsert(RM_XACT_ID, XLOG_XACT_ABORT, &rdata); + } - /* Mark the transaction aborted in clog */ + /* + * Mark the transaction aborted in clog. This is not absolutely + * necessary but we may as well do it while we are here. + */ TransactionIdAbort(xid); END_CRIT_SECTION(); @@ -726,14 +747,10 @@ RecordTransactionAbort(void) /* Break the chain of back-links in the XLOG records I output */ MyLastRecPtr.xrecoff = 0; MyXactMadeXLogEntry = false; + MyXactMadeTempRelUpdate = false; /* Show myself as out of the transaction in PGPROC array */ MyProc->logRec.xrecoff = 0; - - /* - * Tell bufmgr and smgr to release resources. - */ - ResetBufferPool(false); /* false -> is abort */ } /* -------------------------------- @@ -743,7 +760,7 @@ RecordTransactionAbort(void) static void AtAbort_Cache(void) { - AtEOXactRelationCache(false); + AtEOXact_RelationCache(false); AtEOXactInvalidationMessages(false); } @@ -975,7 +992,6 @@ CommitTransaction(void) * noncritical resource releasing. */ - RelationPurgeLocalRelation(true); smgrDoPendingDeletes(true); AtEOXact_GUC(true); @@ -989,6 +1005,8 @@ CommitTransaction(void) AtCommit_Locks(); AtEOXact_CatCache(true); AtCommit_Memory(); + AtEOXact_Buffers(true); + smgrabort(); AtEOXact_Files(); /* Count transaction commit in statistics collector */ @@ -1076,7 +1094,6 @@ AbortTransaction(void) LWLockRelease(SInvalLock); } - RelationPurgeLocalRelation(false); smgrDoPendingDeletes(false); AtEOXact_GUC(false); @@ -1089,6 +1106,7 @@ AbortTransaction(void) AtAbort_Cache(); AtEOXact_CatCache(false); AtAbort_Memory(); + AtEOXact_Buffers(false); AtEOXact_Files(); AtAbort_Locks(); |