DropRelFileNodeBuffers failed to fix the state of the lookup hash table
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 17 Nov 2005 17:42:24 +0000 (17:42 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 17 Nov 2005 17:42:24 +0000 (17:42 +0000)
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
src/backend/storage/buffer/localbuf.c
src/include/storage/buf_internals.h

index bbcc429a89f49e77f2a5974d22422ba2a3af97ef..730cc84c18df5bf80c41c7cbaa65e829e3f3ac03 100644 (file)
@@ -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)
index 463b126051072da5f9f477c5b57bdf4ef82a6976..95eb359c8da33ac67055475d189d68346622cfd0 100644 (file)
@@ -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)
index 47b0cfe6c276c36b8d9cf61efed7a73ebc67e72c..8618a9c7e3ba89a2db144c82f56fbdea72198d32 100644 (file)
@@ -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 */