diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-09-24 00:25:33 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-09-24 00:25:33 +0000 |
commit | e812458b273be00bde34fb74991ab4a99c24ab30 (patch) | |
tree | e7460ae5c0344782f6f6068399f6f7eab5be96f6 /src/backend/storage/buffer/bufmgr.c | |
parent | ad791c1d140af97d93ee98883e2c45413d6f9836 (diff) | |
download | postgresql-e812458b273be00bde34fb74991ab4a99c24ab30.tar.gz postgresql-e812458b273be00bde34fb74991ab4a99c24ab30.zip |
Several changes here, not very related but touching some of the same files.
* Buffer refcount cleanup (per my "progress report" to pghackers, 9/22).
* Add links to backend PROC structs to sinval's array of per-backend info,
and use these links for routines that need to check the state of all
backends (rather than the slow, complicated search of the ShmemIndex
hashtable that was used before). Add databaseOID to PROC structs.
* Use this to implement an interlock that prevents DESTROY DATABASE of
a database containing running backends. (It's a little tricky to prevent
a concurrently-starting backend from getting in there, since the new
backend is not able to lock anything at the time it tries to look up
its database in pg_database. My solution is to recheck that the DB is
OK at the end of InitPostgres. It may not be a 100% solution, but it's
a lot better than no interlock at all...)
* In ALTER TABLE RENAME, flush buffers for the relation before doing the
rename of the physical files, to ensure we don't get failures later from
mdblindwrt().
* Update TRUNCATE patch so that it actually compiles against current
sources :-(.
You should do "make clean all" after pulling these changes.
Diffstat (limited to 'src/backend/storage/buffer/bufmgr.c')
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 177 |
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) { |