aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xact.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r--src/backend/access/transam/xact.c180
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();