DropRelFileNodeBuffers failed to fix the state of the lookup hash table
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 17 Nov 2005 17:42:02 +0000 (17:42 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 17 Nov 2005 17:42:02 +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 4d2c869860fcd87804b50ac7011d070adff55e1c..b7331f9abe6af68131e204484393209f0e1d3734 100644 (file)
@@ -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)
index ca80255e15ea62535900712ba47bd5b56a11a570..acaf4b9b6e258bf141bb1af0a91c343105dab84c 100644 (file)
@@ -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)
index b2cbf3049e6b94e23ff372bc4acd720654c214ef..c55ce699bcd972ab51808094f08e4c48bf8aab5e 100644 (file)
@@ -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 */