aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/buffer/localbuf.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/localbuf.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/localbuf.c')
-rw-r--r--src/backend/storage/buffer/localbuf.c129
1 files changed, 45 insertions, 84 deletions
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index d5edc570b6e..50168c8b306 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -1,48 +1,37 @@
/*-------------------------------------------------------------------------
*
* localbuf.c
- * local buffer manager. Fast buffer manager for temporary tables
- * or special cases when the operation is not visible to other backends.
- *
- * When a relation is being created, the descriptor will have rd_islocal
- * set to indicate that the local buffer manager should be used. During
- * the same transaction the relation is being created, any inserts or
- * selects from the newly created relation will use the local buffer
- * pool. rd_islocal is reset at the end of a transaction (commit/abort).
- * This is useful for queries like SELECT INTO TABLE and create index.
+ * local buffer manager. Fast buffer manager for temporary tables,
+ * which never need to be WAL-logged or checkpointed, etc.
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.44 2002/06/20 20:29:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/localbuf.c,v 1.45 2002/08/06 02:36:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include <sys/types.h>
-#include <sys/file.h>
-#include <math.h>
-#include <signal.h>
-
-#include "executor/execdebug.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "storage/smgr.h"
#include "utils/relcache.h"
-extern long int LocalBufferFlushCount;
+/*#define LBDEBUG*/
+
+/* should be a GUC parameter some day */
int NLocBuffer = 64;
+
BufferDesc *LocalBufferDescriptors = NULL;
Block *LocalBufferBlockPointers = NULL;
long *LocalRefCount = NULL;
static int nextFreeLocalBuf = 0;
-/*#define LBDEBUG*/
/*
* LocalBufferAlloc -
@@ -61,11 +50,11 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
reln->rd_node.relNode &&
LocalBufferDescriptors[i].tag.blockNum == blockNum)
{
-
#ifdef LBDEBUG
fprintf(stderr, "LB ALLOC (%u,%d) %d\n",
RelationGetRelid(reln), blockNum, -i - 1);
#endif
+
LocalRefCount[i]++;
*foundPtr = TRUE;
return &LocalBufferDescriptors[i];
@@ -94,14 +83,17 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
elog(ERROR, "no empty local buffer.");
/*
- * this buffer is not referenced but it might still be dirty (the last
- * transaction to touch it doesn't need its contents but has not
- * flushed it). if that's the case, write it out before reusing it!
+ * this buffer is not referenced but it might still be dirty.
+ * if that's the case, write it out before reusing it!
*/
if (bufHdr->flags & BM_DIRTY || bufHdr->cntxDirty)
{
Relation bufrel = RelationNodeCacheGetRelation(bufHdr->tag.rnode);
+ /*
+ * The relcache is not supposed to throw away temp rels, so this
+ * should always succeed.
+ */
Assert(bufrel != NULL);
/* flush this page */
@@ -114,25 +106,18 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
}
/*
- * it's all ours now.
- *
- * We need not in tblNode currently but will in future I think, when
- * we'll give up rel->rd_fd to fmgr cache.
- */
- bufHdr->tag.rnode = reln->rd_node;
- bufHdr->tag.blockNum = blockNum;
- bufHdr->flags &= ~BM_DIRTY;
- bufHdr->cntxDirty = false;
-
- /*
* lazy memory allocation: allocate space on first use of a buffer.
+ *
+ * Note this path cannot be taken for a buffer that was previously
+ * in use, so it's okay to do it (and possibly error out) before
+ * marking the buffer as valid.
*/
if (bufHdr->data == (SHMEM_OFFSET) 0)
{
char *data = (char *) malloc(BLCKSZ);
if (data == NULL)
- elog(FATAL, "Out of memory in LocalBufferAlloc");
+ elog(ERROR, "Out of memory in LocalBufferAlloc");
/*
* This is a bit of a hack: bufHdr->data needs to be a shmem
@@ -147,13 +132,24 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
LocalBufferBlockPointers[-(bufHdr->buf_id + 2)] = (Block) data;
}
+ /*
+ * it's all ours now.
+ *
+ * We need not in tblNode currently but will in future I think, when
+ * we'll give up rel->rd_fd to fmgr cache.
+ */
+ bufHdr->tag.rnode = reln->rd_node;
+ bufHdr->tag.blockNum = blockNum;
+ bufHdr->flags &= ~BM_DIRTY;
+ bufHdr->cntxDirty = false;
+
*foundPtr = FALSE;
return bufHdr;
}
/*
* WriteLocalBuffer -
- * writes out a local buffer
+ * writes out a local buffer (actually, just marks it dirty)
*/
void
WriteLocalBuffer(Buffer buffer, bool release)
@@ -180,7 +176,7 @@ WriteLocalBuffer(Buffer buffer, bool release)
* InitLocalBuffer -
* init the local buffer cache. Since most queries (esp. multi-user ones)
* don't involve local buffers, we delay allocating actual memory for the
- * buffer until we need it.
+ * buffers until we need them; just make the buffer headers here.
*/
void
InitLocalBuffer(void)
@@ -211,65 +207,30 @@ InitLocalBuffer(void)
}
/*
- * LocalBufferSync
- *
- * Flush all dirty buffers in the local buffer cache at commit time.
- * Since the buffer cache is only used for keeping relations visible
- * during a transaction, we will not need these buffers again.
+ * AtEOXact_LocalBuffers - clean up at end of transaction.
*
- * Note that we have to *flush* local buffers because of them are not
- * visible to checkpoint makers. But we can skip XLOG flush check.
+ * This is just like AtEOXact_Buffers, but for local buffers.
*/
void
-LocalBufferSync(void)
+AtEOXact_LocalBuffers(bool isCommit)
{
int i;
for (i = 0; i < NLocBuffer; i++)
{
- BufferDesc *buf = &LocalBufferDescriptors[i];
- Relation bufrel;
-
- if (buf->flags & BM_DIRTY || buf->cntxDirty)
+ if (LocalRefCount[i] != 0)
{
-#ifdef LBDEBUG
- fprintf(stderr, "LB SYNC %d\n", -i - 1);
-#endif
- bufrel = RelationNodeCacheGetRelation(buf->tag.rnode);
-
- Assert(bufrel != NULL);
+ BufferDesc *buf = &(LocalBufferDescriptors[i]);
- smgrwrite(DEFAULT_SMGR, bufrel, buf->tag.blockNum,
- (char *) MAKE_PTR(buf->data));
- smgrmarkdirty(DEFAULT_SMGR, bufrel, buf->tag.blockNum);
- LocalBufferFlushCount++;
+ if (isCommit)
+ elog(WARNING,
+ "Local Buffer Leak: [%03d] (rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%d %ld)",
+ i,
+ buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
+ buf->tag.blockNum, buf->flags,
+ buf->refcount, LocalRefCount[i]);
- /* drop relcache refcount from RelationNodeCacheGetRelation */
- RelationDecrementReferenceCount(bufrel);
-
- buf->flags &= ~BM_DIRTY;
- buf->cntxDirty = false;
+ LocalRefCount[i] = 0;
}
}
-
- MemSet(LocalRefCount, 0, sizeof(long) * NLocBuffer);
- nextFreeLocalBuf = 0;
-}
-
-void
-ResetLocalBufferPool(void)
-{
- int i;
-
- for (i = 0; i < NLocBuffer; i++)
- {
- BufferDesc *buf = &LocalBufferDescriptors[i];
-
- buf->tag.rnode.relNode = InvalidOid;
- buf->flags &= ~BM_DIRTY;
- buf->cntxDirty = false;
- }
-
- MemSet(LocalRefCount, 0, sizeof(long) * NLocBuffer);
- nextFreeLocalBuf = 0;
}