1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +03:00

Restructure local-buffer handling per recent pghackers discussion.

The local buffer manager is no longer used for newly-created relations
(unless they are TEMP); a new non-TEMP relation goes through the shared
bufmgr and thus will participate normally in checkpoints.  But TEMP relations
use the local buffer manager throughout their lifespan.  Also, operations
in TEMP relations are not logged in WAL, thus improving performance.
Since it's no longer necessary to fsync relations as they move out of the
local buffers into shared buffers, quite a lot of smgr.c/md.c/fd.c code
is no longer needed and has been removed: there's no concept of a dirty
relation anymore in md.c/fd.c, and we never fsync anything but WAL.
Still TODO: improve local buffer management algorithms so that it would
be reasonable to increase NLocBuffer.
This commit is contained in:
Tom Lane
2002-08-06 02:36:35 +00:00
parent 35cd432b18
commit 5df307c778
28 changed files with 543 additions and 955 deletions

View File

@ -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;
/* Mark the transaction aborted in clog */
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. 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();