diff options
Diffstat (limited to 'src/backend/storage/buffer/localbuf.c')
-rw-r--r-- | src/backend/storage/buffer/localbuf.c | 129 |
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; } |