]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix ReadBuffer() to correctly handle the case where it's trying to extend
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 6 Jan 2006 00:04:33 +0000 (00:04 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 6 Jan 2006 00:04:33 +0000 (00:04 +0000)
the relation but it finds a pre-existing valid buffer.  The buffer does not
correspond to any page known to the kernel, so we *must* do smgrextend to
ensure that the space becomes allocated.  The 7.x branches all do this
correctly, but the corner case got lost somewhere during 8.0 bufmgr rewrites.
(My fault no doubt :-( ... I think I assumed that such a buffer must be
not-BM_VALID, which is not so.)

src/backend/storage/buffer/bufmgr.c

index 457d23b0e0225296659c19db9e04b9c2233bd505..81fec6983776ddf07d1030cc1e40ff1143bd78e7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.185 2005/01/10 20:02:21 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.185.4.1 2006/01/06 00:04:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -166,13 +166,41 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
        /* if it was already in the buffer pool, we're done */
        if (found)
        {
-               /* Just need to update stats before we exit */
-               pgstat_count_buffer_hit(&reln->pgstat_info, reln);
+               if (!isExtend)
+               {
+                       /* Just need to update stats before we exit */
+                       pgstat_count_buffer_hit(&reln->pgstat_info, reln);
+
+                       if (VacuumCostActive)
+                               VacuumCostBalance += VacuumCostPageHit;
 
-               if (VacuumCostActive)
-                       VacuumCostBalance += VacuumCostPageHit;
+                       return BufferDescriptorGetBuffer(bufHdr);
+               }
 
-               return BufferDescriptorGetBuffer(bufHdr);
+               /*
+                * We get here only in the corner case where we are trying to extend
+                * the relation but we found a pre-existing buffer marked BM_VALID.
+                * (This can happen because mdread doesn't complain about reads
+                * beyond EOF --- which is arguably bogus, but changing it seems
+                * tricky.)  We *must* do smgrextend before succeeding, else the
+                * page will not be reserved by the kernel, and the next P_NEW call
+                * will decide to return the same page.  Clear the BM_VALID bit,
+                * do the StartBufferIO call that BufferAlloc didn't, and proceed.
+                */
+               if (isLocalBuf)
+               {
+                       /* Only need to adjust flags */
+                       Assert(bufHdr->flags & BM_VALID);
+                       bufHdr->flags &= ~BM_VALID;
+               }
+               else
+               {
+                       LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
+                       Assert(bufHdr->flags & BM_VALID);
+                       bufHdr->flags &= ~BM_VALID;
+                       StartBufferIO(bufHdr, true);
+                       LWLockRelease(BufMgrLock);
+               }
        }
 
        /*