aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/buffer/bufmgr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-08-06 02:36:35 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-08-06 02:36:35 +0000
commit5df307c7782518c4a3c19ffd05c7cb591b97e23c (patch)
tree0ff988dc5b7b115e9f6bbf29852dd4bad7fcaeea /src/backend/storage/buffer/bufmgr.c
parent35cd432b185938c33967c9fa48223ce33e1c66bd (diff)
downloadpostgresql-5df307c7782518c4a3c19ffd05c7cb591b97e23c.tar.gz
postgresql-5df307c7782518c4a3c19ffd05c7cb591b97e23c.zip
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.
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r--src/backend/storage/buffer/bufmgr.c292
1 files changed, 94 insertions, 198 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index b2c19e99f47..1ca7af3b775 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.127 2002/07/02 05:47:37 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.128 2002/08/06 02:36:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -57,16 +57,9 @@
#include "pgstat.h"
#define BufferGetLSN(bufHdr) \
- (*((XLogRecPtr*)MAKE_PTR((bufHdr)->data)))
+ (*((XLogRecPtr*) MAKE_PTR((bufHdr)->data)))
-extern long int ReadBufferCount;
-extern long int ReadLocalBufferCount;
-extern long int BufferHitCount;
-extern long int LocalBufferHitCount;
-extern long int BufferFlushCount;
-extern long int LocalBufferFlushCount;
-
static void WaitIO(BufferDesc *buf);
static void StartBufferIO(BufferDesc *buf, bool forInput);
static void TerminateBufferIO(BufferDesc *buf);
@@ -82,16 +75,12 @@ static Buffer ReadBufferInternal(Relation reln, BlockNumber blockNum,
bool bufferLockHeld);
static BufferDesc *BufferAlloc(Relation reln, BlockNumber blockNum,
bool *foundPtr);
-static int ReleaseBufferWithBufferLock(Buffer buffer);
static int BufferReplace(BufferDesc *bufHdr);
#ifdef NOT_USED
void PrintBufferDescs(void);
#endif
static void write_buffer(Buffer buffer, bool unpin);
-static void drop_relfilenode_buffers(RelFileNode rnode,
- bool do_local, bool do_both);
-static int release_buffer(Buffer buffer, bool havelock);
/*
* ReadBuffer -- returns a buffer containing the requested
@@ -140,7 +129,7 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
bool isLocalBuf;
isExtend = (blockNum == P_NEW);
- isLocalBuf = reln->rd_myxactonly;
+ isLocalBuf = reln->rd_istemp;
if (isLocalBuf)
{
@@ -684,10 +673,10 @@ ReleaseAndReadBuffer(Buffer buffer,
/*
* BufferSync -- Write all dirty buffers in the pool.
*
- * This is called at checkpoint time and write out all dirty buffers.
+ * This is called at checkpoint time and writes out all dirty shared buffers.
*/
void
-BufferSync()
+BufferSync(void)
{
int i;
BufferDesc *bufHdr;
@@ -780,8 +769,7 @@ BufferSync()
status = smgrblindwrt(DEFAULT_SMGR,
bufHdr->tag.rnode,
bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data),
- true); /* must fsync */
+ (char *) MAKE_PTR(bufHdr->data));
}
else
{
@@ -908,19 +896,16 @@ ResetBufferUsage(void)
NDirectFileWrite = 0;
}
-/* ----------------------------------------------
- * ResetBufferPool
- *
- * This routine is supposed to be called when a transaction aborts.
- * It will release all the buffer pins held by the transaction.
- * Currently, we also call it during commit if BufferPoolCheckLeak
- * detected a problem --- in that case, isCommit is TRUE, and we
- * only clean up buffer pin counts.
+/*
+ * AtEOXact_Buffers - clean up at end of transaction.
*
- * ----------------------------------------------
+ * During abort, we need to release any buffer pins we're holding
+ * (this cleans up in case elog interrupted a routine that pins a
+ * buffer). During commit, we shouldn't need to do that, but check
+ * anyway to see if anyone leaked a buffer reference count.
*/
void
-ResetBufferPool(bool isCommit)
+AtEOXact_Buffers(bool isCommit)
{
int i;
@@ -928,7 +913,16 @@ ResetBufferPool(bool isCommit)
{
if (PrivateRefCount[i] != 0)
{
- BufferDesc *buf = &BufferDescriptors[i];
+ BufferDesc *buf = &(BufferDescriptors[i]);
+
+ if (isCommit)
+ elog(WARNING,
+ "Buffer Leak: [%03d] (freeNext=%d, freePrev=%d, "
+ "rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%d %ld)",
+ i, buf->freeNext, buf->freePrev,
+ buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
+ buf->tag.blockNum, buf->flags,
+ buf->refcount, PrivateRefCount[i]);
PrivateRefCount[i] = 1; /* make sure we release shared pin */
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
@@ -938,48 +932,15 @@ ResetBufferPool(bool isCommit)
}
}
- ResetLocalBufferPool();
-
- if (!isCommit)
- smgrabort();
+ AtEOXact_LocalBuffers(isCommit);
}
/*
- * BufferPoolCheckLeak
- *
- * check if there is buffer leak
- */
-bool
-BufferPoolCheckLeak(void)
-{
- int i;
- bool result = false;
-
- for (i = 0; i < NBuffers; i++)
- {
- if (PrivateRefCount[i] != 0)
- {
- BufferDesc *buf = &(BufferDescriptors[i]);
-
- elog(WARNING,
- "Buffer Leak: [%03d] (freeNext=%d, freePrev=%d, \
-rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%d %ld)",
- i, buf->freeNext, buf->freePrev,
- buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
- buf->tag.blockNum, buf->flags,
- buf->refcount, PrivateRefCount[i]);
- result = true;
- }
- }
- return result;
-}
-
-/* ------------------------------------------------
* FlushBufferPool
*
- * Flush all dirty blocks in buffer pool to disk
- * at the checkpoint time
- * ------------------------------------------------
+ * Flush all dirty blocks in buffer pool to disk at the checkpoint time.
+ * Local relations do not participate in checkpoints, so they don't need to be
+ * flushed.
*/
void
FlushBufferPool(void)
@@ -989,16 +950,13 @@ FlushBufferPool(void)
}
/*
- * At the commit time we have to flush local buffer pool only
+ * Do whatever is needed to prepare for commit at the bufmgr and smgr levels
*/
void
BufmgrCommit(void)
{
- LocalBufferSync();
+ /* Nothing to do in bufmgr anymore... */
- /*
- * All files created in current transaction will be fsync-ed
- */
smgrcommit();
}
@@ -1051,15 +1009,15 @@ BufferReplace(BufferDesc *bufHdr)
if (reln != (Relation) NULL)
{
- status = smgrwrite(DEFAULT_SMGR, reln, bufHdr->tag.blockNum,
+ status = smgrwrite(DEFAULT_SMGR, reln,
+ bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data));
}
else
{
status = smgrblindwrt(DEFAULT_SMGR, bufHdr->tag.rnode,
bufHdr->tag.blockNum,
- (char *) MAKE_PTR(bufHdr->data),
- false); /* no fsync */
+ (char *) MAKE_PTR(bufHdr->data));
}
/* drop relcache refcnt incremented by RelationNodeCacheGetRelation */
@@ -1091,31 +1049,55 @@ RelationGetNumberOfBlocks(Relation relation)
{
/*
* relation->rd_nblocks should be accurate already if the relation is
- * myxactonly. (XXX how safe is that really?) Don't call smgr on a
- * view, either.
+ * new or temp, because no one else should be modifying it. Otherwise
+ * we need to ask the smgr for the current physical file length.
+ *
+ * Don't call smgr on a view, either.
*/
if (relation->rd_rel->relkind == RELKIND_VIEW)
relation->rd_nblocks = 0;
- else if (!relation->rd_myxactonly)
+ else if (!relation->rd_isnew && !relation->rd_istemp)
relation->rd_nblocks = smgrnblocks(DEFAULT_SMGR, relation);
return relation->rd_nblocks;
}
-/*
- * drop_relfilenode_buffers -- common functionality for
- * DropRelationBuffers and
- * DropRelFileNodeBuffers
+/* ---------------------------------------------------------------------
+ * DropRelationBuffers
*
- * XXX currently it sequentially searches the buffer pool, should be
- * changed to more clever ways of searching.
+ * This function removes all the buffered pages for a relation
+ * from the buffer pool. Dirty pages are simply dropped, without
+ * bothering to write them out first. This is NOT rollback-able,
+ * and so should be used only with extreme caution!
+ *
+ * We assume that the caller holds an exclusive lock on the relation,
+ * which should assure that no new buffers will be acquired for the rel
+ * meanwhile.
+ * --------------------------------------------------------------------
*/
-static void
-drop_relfilenode_buffers(RelFileNode rnode, bool do_local, bool do_both)
+void
+DropRelationBuffers(Relation rel)
+{
+ DropRelFileNodeBuffers(rel->rd_node, rel->rd_istemp);
+}
+
+/* ---------------------------------------------------------------------
+ * DropRelFileNodeBuffers
+ *
+ * This is the same as DropRelationBuffers, except that the target
+ * relation is specified by RelFileNode and temp status.
+ *
+ * This is NOT rollback-able. One legitimate use is to clear the
+ * buffer cache of buffers for a relation that is being deleted
+ * during transaction abort.
+ * --------------------------------------------------------------------
+ */
+void
+DropRelFileNodeBuffers(RelFileNode rnode, bool istemp)
{
int i;
BufferDesc *bufHdr;
- if (do_local)
+ if (istemp)
{
for (i = 0; i < NLocBuffer; i++)
{
@@ -1128,8 +1110,7 @@ drop_relfilenode_buffers(RelFileNode rnode, bool do_local, bool do_both)
bufHdr->tag.rnode.relNode = InvalidOid;
}
}
- if (!do_both)
- return;
+ return;
}
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
@@ -1160,18 +1141,19 @@ recheck:
bufHdr->cntxDirty = false;
/*
- * Release any refcount we may have.
- *
- * This is very probably dead code, and if it isn't then it's
- * probably wrong. I added the Assert to find out --- tgl
- * 11/99.
+ * Release any refcount we may have. If someone else has a
+ * pin on the buffer, we got trouble.
*/
if (!(bufHdr->flags & BM_FREE))
{
- /* Assert checks that buffer will actually get freed! */
- Assert(PrivateRefCount[i - 1] == 1 &&
- bufHdr->refcount == 1);
- ReleaseBufferWithBufferLock(i);
+ /* the sole pin should be ours */
+ if (bufHdr->refcount != 1 || PrivateRefCount[i - 1] == 0)
+ elog(FATAL, "DropRelFileNodeBuffers: block %u is referenced (private %ld, global %d)",
+ bufHdr->tag.blockNum,
+ PrivateRefCount[i - 1], bufHdr->refcount);
+ /* Make sure it will be released */
+ PrivateRefCount[i - 1] = 1;
+ UnpinBuffer(bufHdr);
}
/*
@@ -1185,43 +1167,6 @@ recheck:
}
/* ---------------------------------------------------------------------
- * DropRelationBuffers
- *
- * This function removes all the buffered pages for a relation
- * from the buffer pool. Dirty pages are simply dropped, without
- * bothering to write them out first. This is NOT rollback-able,
- * and so should be used only with extreme caution!
- *
- * We assume that the caller holds an exclusive lock on the relation,
- * which should assure that no new buffers will be acquired for the rel
- * meanwhile.
- * --------------------------------------------------------------------
- */
-void
-DropRelationBuffers(Relation rel)
-{
- drop_relfilenode_buffers(rel->rd_node, rel->rd_myxactonly, false);
-}
-
-/* ---------------------------------------------------------------------
- * DropRelFileNodeBuffers
- *
- * This is the same as DropRelationBuffers, except that the target
- * relation is specified by RelFileNode.
- *
- * This is NOT rollback-able. One legitimate use is to clear the
- * buffer cache of buffers for a relation that is being deleted
- * during transaction abort.
- * --------------------------------------------------------------------
- */
-void
-DropRelFileNodeBuffers(RelFileNode rnode)
-{
- /* We have to search both local and shared buffers... */
- drop_relfilenode_buffers(rnode, true, true);
-}
-
-/* ---------------------------------------------------------------------
* DropBuffers
*
* This function removes all the buffers in the buffer cache for a
@@ -1296,7 +1241,7 @@ recheck:
*/
#ifdef NOT_USED
void
-PrintBufferDescs()
+PrintBufferDescs(void)
{
int i;
BufferDesc *buf = BufferDescriptors;
@@ -1331,7 +1276,7 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)",
#ifdef NOT_USED
void
-PrintPinnedBufs()
+PrintPinnedBufs(void)
{
int i;
BufferDesc *buf = BufferDescriptors;
@@ -1351,33 +1296,6 @@ blockNum=%u, flags=0x%x, refcount=%d %ld)",
}
#endif
-/*
- * BufferPoolBlowaway
- *
- * this routine is solely for the purpose of experiments -- sometimes
- * you may want to blowaway whatever is left from the past in buffer
- * pool and start measuring some performance with a clean empty buffer
- * pool.
- */
-#ifdef NOT_USED
-void
-BufferPoolBlowaway()
-{
- int i;
-
- BufferSync();
- for (i = 1; i <= NBuffers; i++)
- {
- if (BufferIsValid(i))
- {
- while (BufferIsValid(i))
- ReleaseBuffer(i);
- }
- BufTableDelete(&BufferDescriptors[i - 1]);
- }
-}
-#endif
-
/* ---------------------------------------------------------------------
* FlushRelationBuffers
*
@@ -1428,7 +1346,7 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
XLogRecPtr recptr;
int status;
- if (rel->rd_myxactonly)
+ if (rel->rd_istemp)
{
for (i = 0; i < NLocBuffer; i++)
{
@@ -1544,12 +1462,14 @@ FlushRelationBuffers(Relation rel, BlockNumber firstDelBlock)
return 0;
}
+#undef ReleaseBuffer
+
/*
- * release_buffer -- common functionality for
- * ReleaseBuffer and ReleaseBufferWithBufferLock
+ * ReleaseBuffer -- remove the pin on a buffer without
+ * marking it dirty.
*/
-static int
-release_buffer(Buffer buffer, bool havelock)
+int
+ReleaseBuffer(Buffer buffer)
{
BufferDesc *bufHdr;
@@ -1570,41 +1490,14 @@ release_buffer(Buffer buffer, bool havelock)
PrivateRefCount[buffer - 1]--;
else
{
- if (!havelock)
- LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
-
+ LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
UnpinBuffer(bufHdr);
-
- if (!havelock)
- LWLockRelease(BufMgrLock);
+ LWLockRelease(BufMgrLock);
}
return STATUS_OK;
}
-#undef ReleaseBuffer
-
-/*
- * ReleaseBuffer -- remove the pin on a buffer without
- * marking it dirty.
- */
-int
-ReleaseBuffer(Buffer buffer)
-{
- return release_buffer(buffer, false);
-}
-
-/*
- * ReleaseBufferWithBufferLock
- * Same as ReleaseBuffer except we hold the bufmgr lock
- */
-static int
-ReleaseBufferWithBufferLock(Buffer buffer)
-{
- return release_buffer(buffer, true);
-}
-
-
#ifdef NOT_USED
void
IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
@@ -1847,10 +1740,13 @@ SetBufferCommitInfoNeedsSave(Buffer buffer)
BufferDesc *bufHdr;
if (BufferIsLocal(buffer))
+ {
+ WriteLocalBuffer(buffer, false);
return;
+ }
if (BAD_BUFFER_ID(buffer))
- return;
+ elog(ERROR, "SetBufferCommitInfoNeedsSave: bad buffer %d", buffer);
bufHdr = &BufferDescriptors[buffer - 1];