From c859308aba7edef428994e6de90ff35f35a328c5 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 17 Nov 2005 17:42:02 +0000 Subject: [PATCH] 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. --- src/backend/storage/buffer/bufmgr.c | 25 +++----------- src/backend/storage/buffer/localbuf.c | 48 ++++++++++++++++++++++++++- src/include/storage/buf_internals.h | 4 ++- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 4d2c869860f..b7331f9abe6 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.198 2005/10/27 17:07:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.199 2005/11/17 17:42:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 ca80255e15e..acaf4b9b6e2 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.70 2005/10/15 02:49:25 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.71 2005/11/17 17:42:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 b2cbf3049e6..c55ce699bcd 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.81 2005/10/15 02:49:46 momjian Exp $ + * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.82 2005/11/17 17:42:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 */