From: Tom Lane Date: Thu, 17 Nov 2005 17:42:24 +0000 (+0000) Subject: DropRelFileNodeBuffers failed to fix the state of the lookup hash table X-Git-Url: http://waps.l3s.uni-hannover.de/gitweb/?a=commitdiff_plain;h=b0d6ee4d91b6b0646462eb2fc69320919d144fcb;p=users%2Fbernd%2Fpostgres.git DropRelFileNodeBuffers failed to fix the state of the lookup hash table that was added to localbuf.c in 8.1; therefore, applying it to a temp table left corrupt lookup state in memory. The only case where this had a significant chance of causing problems was an ON COMMIT DELETE ROWS temp table; the other possible paths left bogus state that was unlikely to be used again. Per report from Csaba Nagy. --- diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index bbcc429a89..730cc84c18 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -1384,34 +1384,17 @@ DropRelFileNodeBuffers(RelFileNode rnode, bool istemp, BlockNumber firstDelBlock) { int i; - volatile BufferDesc *bufHdr; if (istemp) { - for (i = 0; i < NLocBuffer; i++) - { - bufHdr = &LocalBufferDescriptors[i]; - if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) && - bufHdr->tag.blockNum >= firstDelBlock) - { - if (LocalRefCount[i] != 0) - elog(ERROR, "block %u of %u/%u/%u is still referenced (local %u)", - bufHdr->tag.blockNum, - bufHdr->tag.rnode.spcNode, - bufHdr->tag.rnode.dbNode, - bufHdr->tag.rnode.relNode, - LocalRefCount[i]); - CLEAR_BUFFERTAG(bufHdr->tag); - bufHdr->flags = 0; - bufHdr->usage_count = 0; - } - } + DropRelFileNodeLocalBuffers(rnode, firstDelBlock); return; } for (i = 0; i < NBuffers; i++) { - bufHdr = &BufferDescriptors[i]; + volatile BufferDesc *bufHdr = &BufferDescriptors[i]; + LockBufHdr(bufHdr); if (RelFileNodeEquals(bufHdr->tag.rnode, rnode) && bufHdr->tag.blockNum >= firstDelBlock) diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 463b126051..95eb359c8d 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -241,6 +241,52 @@ WriteLocalBuffer(Buffer buffer, bool release) } } +/* + * DropRelFileNodeLocalBuffers + * This function removes from the buffer pool all the pages of the + * specified relation that have block numbers >= firstDelBlock. + * (In particular, with firstDelBlock = 0, all pages are removed.) + * Dirty pages are simply dropped, without bothering to write them + * out first. Therefore, this is NOT rollback-able, and so should be + * used only with extreme caution! + * + * See DropRelFileNodeBuffers in bufmgr.c for more notes. + */ +void +DropRelFileNodeLocalBuffers(RelFileNode rnode, BlockNumber firstDelBlock) +{ + int i; + + for (i = 0; i < NLocBuffer; i++) + { + BufferDesc *bufHdr = &LocalBufferDescriptors[i]; + LocalBufferLookupEnt *hresult; + + if ((bufHdr->flags & BM_TAG_VALID) && + RelFileNodeEquals(bufHdr->tag.rnode, rnode) && + bufHdr->tag.blockNum >= firstDelBlock) + { + if (LocalRefCount[i] != 0) + elog(ERROR, "block %u of %u/%u/%u is still referenced (local %u)", + bufHdr->tag.blockNum, + bufHdr->tag.rnode.spcNode, + bufHdr->tag.rnode.dbNode, + bufHdr->tag.rnode.relNode, + LocalRefCount[i]); + /* Remove entry from hashtable */ + hresult = (LocalBufferLookupEnt *) + hash_search(LocalBufHash, (void *) &bufHdr->tag, + HASH_REMOVE, NULL); + if (!hresult) /* shouldn't happen */ + elog(ERROR, "local buffer hash table corrupted"); + /* Mark buffer invalid */ + CLEAR_BUFFERTAG(bufHdr->tag); + bufHdr->flags = 0; + bufHdr->usage_count = 0; + } + } +} + /* * InitLocalBuffers - * init the local buffer cache. Since most queries (esp. multi-user ones) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index 47b0cfe6c2..8618a9c7e3 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -198,6 +198,8 @@ extern void BufTableDelete(BufferTag *tagPtr); extern BufferDesc *LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr); extern void WriteLocalBuffer(Buffer buffer, bool release); +extern void DropRelFileNodeLocalBuffers(RelFileNode rnode, + BlockNumber firstDelBlock); extern void AtEOXact_LocalBuffers(bool isCommit); #endif /* BUFMGR_INTERNALS_H */