diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2006-01-06 00:04:33 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2006-01-06 00:04:33 +0000 |
commit | 718d3232af9cee59c7e0a0452cc7d02935c557ea (patch) | |
tree | a7ee34d382dada103a172c64af29c50a9833d123 | |
parent | 0add52b4f660dd2d90eb00450d38c6d0e41679fa (diff) | |
download | postgresql-718d3232af9cee59c7e0a0452cc7d02935c557ea.tar.gz postgresql-718d3232af9cee59c7e0a0452cc7d02935c557ea.zip |
Fix ReadBuffer() to correctly handle the case where it's trying to extend
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.)
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 457d23b0e02..81fec698377 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.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); + } } /* |