aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/buffer/bufmgr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r--src/backend/storage/buffer/bufmgr.c177
1 files changed, 97 insertions, 80 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index b435dd53cac..e0327c678f2 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.62 1999/09/18 19:07:26 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.63 1999/09/24 00:24:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -89,9 +89,6 @@ static void BufferSync(void);
static int BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld);
void PrintBufferDescs(void);
-/* not static but used by vacuum only ... */
-int BlowawayRelationBuffers(Relation rel, BlockNumber block);
-
/* ---------------------------------------------------
* RelationGetBufferWithBuffer
* see if the given buffer is what we want
@@ -146,9 +143,6 @@ RelationGetBufferWithBuffer(Relation relation,
* opened already.
*/
-extern int ShowPinTrace;
-
-
#undef ReadBuffer /* conflicts with macro when BUFMGR_DEBUG
* defined */
@@ -499,6 +493,7 @@ BufferAlloc(Relation reln,
SignalIO(buf);
#endif /* !HAS_TEST_AND_SET */
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
+ Assert(buf->refcount > 0);
buf->refcount--;
if (buf->refcount == 0)
{
@@ -575,10 +570,14 @@ BufferAlloc(Relation reln,
SignalIO(buf);
#endif /* !HAS_TEST_AND_SET */
/* give up the buffer since we don't need it any more */
- buf->refcount--;
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
- AddBufferToFreelist(buf);
- buf->flags |= BM_FREE;
+ Assert(buf->refcount > 0);
+ buf->refcount--;
+ if (buf->refcount == 0)
+ {
+ AddBufferToFreelist(buf);
+ buf->flags |= BM_FREE;
+ }
buf->flags &= ~BM_IO_IN_PROGRESS;
}
@@ -791,7 +790,7 @@ FlushBuffer(Buffer buffer, bool release)
int status;
if (BufferIsLocal(buffer))
- return FlushLocalBuffer(buffer, release);
+ return FlushLocalBuffer(buffer, release) ? STATUS_OK : STATUS_ERROR;
if (BAD_BUFFER_ID(buffer))
return STATUS_ERROR;
@@ -813,7 +812,7 @@ FlushBuffer(Buffer buffer, bool release)
status = smgrflush(DEFAULT_SMGR, bufrel, bufHdr->tag.blockNum,
(char *) MAKE_PTR(bufHdr->data));
- /* drop relcache refcount incremented by RelationIdCacheGetRelation */
+ /* drop relcache refcnt incremented by RelationIdCacheGetRelation */
RelationDecrementReferenceCount(bufrel);
if (status == SM_FAIL)
@@ -908,15 +907,10 @@ ReleaseAndReadBuffer(Buffer buffer,
bufHdr = &BufferDescriptors[buffer - 1];
Assert(PrivateRefCount[buffer - 1] > 0);
PrivateRefCount[buffer - 1]--;
- if (PrivateRefCount[buffer - 1] == 0 &&
- LastRefCount[buffer - 1] == 0)
+ if (PrivateRefCount[buffer - 1] == 0)
{
-
- /*
- * only release buffer if it is not pinned in previous
- * ExecMain level
- */
SpinAcquire(BufMgrLock);
+ Assert(bufHdr->refcount > 0);
bufHdr->refcount--;
if (bufHdr->refcount == 0)
{
@@ -994,7 +988,7 @@ BufferSync()
elog(ERROR, "BufferSync: write error %u for %s",
bufHdr->tag.blockNum, bufHdr->sb_relname);
}
- /* drop refcount from RelationIdCacheGetRelation */
+ /* drop refcnt from RelationIdCacheGetRelation */
if (reln != (Relation) NULL)
RelationDecrementReferenceCount(reln);
continue;
@@ -1049,7 +1043,7 @@ BufferSync()
*/
if (!(bufHdr->flags & BM_JUST_DIRTIED))
bufHdr->flags &= ~BM_DIRTY;
- /* drop refcount from RelationIdCacheGetRelation */
+ /* drop refcnt from RelationIdCacheGetRelation */
if (reln != (Relation) NULL)
RelationDecrementReferenceCount(reln);
}
@@ -1175,7 +1169,7 @@ ResetBufferUsage()
* ResetBufferPool
*
* this routine is supposed to be called when a transaction aborts.
- * it will release all the buffer pins held by the transaciton.
+ * it will release all the buffer pins held by the transaction.
*
* ----------------------------------------------
*/
@@ -1184,15 +1178,24 @@ ResetBufferPool()
{
int i;
- for (i = 1; i <= NBuffers; i++)
+ for (i = 0; i < NBuffers; i++)
{
- CommitInfoNeedsSave[i - 1] = 0;
- if (BufferIsValid(i))
+ if (PrivateRefCount[i] != 0)
{
- while (PrivateRefCount[i - 1] > 0)
- ReleaseBuffer(i);
+ BufferDesc *buf = &BufferDescriptors[i];
+
+ SpinAcquire(BufMgrLock);
+ Assert(buf->refcount > 0);
+ buf->refcount--;
+ if (buf->refcount == 0)
+ {
+ AddBufferToFreelist(buf);
+ buf->flags |= BM_FREE;
+ }
+ SpinRelease(BufMgrLock);
}
- LastRefCount[i - 1] = 0;
+ PrivateRefCount[i] = 0;
+ CommitInfoNeedsSave[i] = 0;
}
ResetLocalBufferPool();
@@ -1213,7 +1216,7 @@ BufferPoolCheckLeak()
for (i = 1; i <= NBuffers; i++)
{
- if (BufferIsValid(i))
+ if (PrivateRefCount[i - 1] != 0)
{
BufferDesc *buf = &(BufferDescriptors[i - 1]);
@@ -1226,7 +1229,7 @@ relname=%s, blockNum=%d, flags=0x%x, refcount=%d %d)",
result = 1;
}
}
- return (result);
+ return result;
}
/* ------------------------------------------------
@@ -1287,7 +1290,7 @@ BufferGetRelation(Buffer buffer)
relation = RelationIdGetRelation(relid);
Assert(relation);
- /* drop relcache refcount incremented by RelationIdGetRelation */
+ /* drop relcache refcnt incremented by RelationIdGetRelation */
RelationDecrementReferenceCount(relation);
if (RelationHasReferenceCountZero(relation))
@@ -1354,7 +1357,7 @@ BufferReplace(BufferDesc *bufHdr, bool bufferLockHeld)
(char *) MAKE_PTR(bufHdr->data));
}
- /* drop relcache refcount incremented by RelationIdCacheGetRelation */
+ /* drop relcache refcnt incremented by RelationIdCacheGetRelation */
if (reln != (Relation) NULL)
RelationDecrementReferenceCount(reln);
@@ -1549,10 +1552,27 @@ BufferPoolBlowaway()
#endif
/* ---------------------------------------------------------------------
- * BlowawayRelationBuffers
+ * FlushRelationBuffers
+ *
+ * This function removes from the buffer pool all pages of a relation
+ * that have blocknumber >= specified block. If doFlush is true,
+ * dirty buffers are written out --- otherwise it's an error for any
+ * of the buffers to be dirty.
+ *
+ * This is used by VACUUM before truncating the relation to the given
+ * number of blocks. For VACUUM, we pass doFlush = false since it would
+ * mean a bug in VACUUM if any of the unwanted pages were still dirty.
+ * (TRUNCATE TABLE also uses it in the same way.)
*
- * This function blowaway all the pages with blocknumber >= passed
- * of a relation in the buffer pool. Used by vacuum before truncation...
+ * This is also used by RENAME TABLE (with block = 0 and doFlush = true)
+ * to clear out the buffer cache before renaming the physical files of
+ * a relation. Without that, some other backend might try to do a
+ * blind write of a buffer page (relying on the sb_relname of the buffer)
+ * and fail because it's not got the right filename anymore.
+ *
+ * In both cases, the caller should be holding AccessExclusiveLock on
+ * the target relation to ensure that no other backend is busy reading
+ * more blocks of the relation...
*
* Returns: 0 - Ok, -1 - DIRTY, -2 - PINNED
*
@@ -1561,7 +1581,7 @@ BufferPoolBlowaway()
* --------------------------------------------------------------------
*/
int
-BlowawayRelationBuffers(Relation rel, BlockNumber block)
+FlushRelationBuffers(Relation rel, BlockNumber block, bool doFlush)
{
int i;
BufferDesc *buf;
@@ -1576,13 +1596,25 @@ BlowawayRelationBuffers(Relation rel, BlockNumber block)
{
if (buf->flags & BM_DIRTY)
{
- elog(NOTICE, "BlowawayRelationBuffers(%s (local), %u): block %u is dirty",
- rel->rd_rel->relname.data, block, buf->tag.blockNum);
- return -1;
+ if (doFlush)
+ {
+ if (FlushBuffer(-i-1, false) != STATUS_OK)
+ {
+ elog(NOTICE, "FlushRelationBuffers(%s (local), %u): block %u is dirty, could not flush it",
+ rel->rd_rel->relname.data, block, buf->tag.blockNum);
+ return -1;
+ }
+ }
+ else
+ {
+ elog(NOTICE, "FlushRelationBuffers(%s (local), %u): block %u is dirty",
+ rel->rd_rel->relname.data, block, buf->tag.blockNum);
+ return -1;
+ }
}
if (LocalRefCount[i] > 0)
{
- elog(NOTICE, "BlowawayRelationBuffers(%s (local), %u): block %u is referenced (%d)",
+ elog(NOTICE, "FlushRelationBuffers(%s (local), %u): block %u is referenced (%d)",
rel->rd_rel->relname.data, block,
buf->tag.blockNum, LocalRefCount[i]);
return -2;
@@ -1603,18 +1635,33 @@ BlowawayRelationBuffers(Relation rel, BlockNumber block)
{
if (buf->flags & BM_DIRTY)
{
- elog(NOTICE, "BlowawayRelationBuffers(%s, %u): block %u is dirty (private %d, last %d, global %d)",
- buf->sb_relname, block, buf->tag.blockNum,
- PrivateRefCount[i], LastRefCount[i], buf->refcount);
- SpinRelease(BufMgrLock);
- return -1;
+ if (doFlush)
+ {
+ SpinRelease(BufMgrLock);
+ if (FlushBuffer(i+1, false) != STATUS_OK)
+ {
+ elog(NOTICE, "FlushRelationBuffers(%s, %u): block %u is dirty (private %d, global %d), could not flush it",
+ buf->sb_relname, block, buf->tag.blockNum,
+ PrivateRefCount[i], buf->refcount);
+ return -1;
+ }
+ SpinAcquire(BufMgrLock);
+ }
+ else
+ {
+ SpinRelease(BufMgrLock);
+ elog(NOTICE, "FlushRelationBuffers(%s, %u): block %u is dirty (private %d, global %d)",
+ buf->sb_relname, block, buf->tag.blockNum,
+ PrivateRefCount[i], buf->refcount);
+ return -1;
+ }
}
if (!(buf->flags & BM_FREE))
{
- elog(NOTICE, "BlowawayRelationBuffers(%s, %u): block %u is referenced (private %d, last %d, global %d)",
- buf->sb_relname, block, buf->tag.blockNum,
- PrivateRefCount[i], LastRefCount[i], buf->refcount);
SpinRelease(BufMgrLock);
+ elog(NOTICE, "FlushRelationBuffers(%s, %u): block %u is referenced (private %d, global %d)",
+ buf->sb_relname, block, buf->tag.blockNum,
+ PrivateRefCount[i], buf->refcount);
return -2;
}
BufTableDelete(buf);
@@ -1650,14 +1697,10 @@ ReleaseBuffer(Buffer buffer)
Assert(PrivateRefCount[buffer - 1] > 0);
PrivateRefCount[buffer - 1]--;
- if (PrivateRefCount[buffer - 1] == 0 && LastRefCount[buffer - 1] == 0)
+ if (PrivateRefCount[buffer - 1] == 0)
{
-
- /*
- * only release buffer if it is not pinned in previous ExecMain
- * levels
- */
SpinAcquire(BufMgrLock);
+ Assert(bufHdr->refcount > 0);
bufHdr->refcount--;
if (bufHdr->refcount == 0)
{
@@ -1892,32 +1935,6 @@ _bm_die(Oid dbId, Oid relId, int blkNo, int bufNo,
#endif /* BMTRACE */
-void
-BufferRefCountReset(int *refcountsave)
-{
- int i;
-
- for (i = 0; i < NBuffers; i++)
- {
- refcountsave[i] = PrivateRefCount[i];
- LastRefCount[i] += PrivateRefCount[i];
- PrivateRefCount[i] = 0;
- }
-}
-
-void
-BufferRefCountRestore(int *refcountsave)
-{
- int i;
-
- for (i = 0; i < NBuffers; i++)
- {
- PrivateRefCount[i] = refcountsave[i];
- LastRefCount[i] -= refcountsave[i];
- refcountsave[i] = 0;
- }
-}
-
int
SetBufferWriteMode(int mode)
{