diff options
Diffstat (limited to 'src/backend/storage/buffer')
-rw-r--r-- | src/backend/storage/buffer/buf_init.c | 4 | ||||
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 292 | ||||
-rw-r--r-- | src/backend/storage/buffer/localbuf.c | 129 |
3 files changed, 141 insertions, 284 deletions
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c index 6132b732f86..a8c56562f2d 100644 --- a/src/backend/storage/buffer/buf_init.c +++ b/src/backend/storage/buffer/buf_init.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.49 2002/06/20 20:29:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/buf_init.c,v 1.50 2002/08/06 02:36:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -258,7 +258,7 @@ ShutdownBufferPoolAccess(void) /* Release any buffer context locks we are holding */ UnlockBuffers(); /* Release any buffer reference counts we are holding */ - ResetBufferPool(false); + AtEOXact_Buffers(false); } /* ----------------------------------------------------- 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]; 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; } |