mirror of
https://github.com/postgres/postgres.git
synced 2025-08-18 12:22:09 +03:00
Make large sequential scans and VACUUMs work in a limited-size "ring" of
buffers, rather than blowing out the whole shared-buffer arena. Aside from avoiding cache spoliation, this fixes the problem that VACUUM formerly tended to cause a WAL flush for every page it modified, because we had it hacked to use only a single buffer. Those flushes will now occur only once per ring-ful. The exact ring size, and the threshold for seqscans to switch into the ring usage pattern, remain under debate; but the infrastructure seems done. The key bit of infrastructure is a new optional BufferAccessStrategy object that can be passed to ReadBuffer operations; this replaces the former StrategyHintVacuum API. This patch also changes the buffer usage-count methodology a bit: we now advance usage_count when first pinning a buffer, rather than when last unpinning it. To preserve the behavior that a buffer's lifetime starts to decrease when it's released, the clock sweep code is modified to not decrement usage_count of pinned buffers. Work not done in this commit: teach GiST and GIN indexes to use the vacuum BufferAccessStrategy for vacuum-driven fetches. Original patch by Simon, reworked by Heikki and again by Tom.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.76 2007/01/05 22:19:37 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.77 2007/05/30 20:11:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -57,7 +57,8 @@ static Block GetLocalBufferStorage(void);
|
||||
*
|
||||
* API is similar to bufmgr.c's BufferAlloc, except that we do not need
|
||||
* to do any locking since this is all local. Also, IO_IN_PROGRESS
|
||||
* does not get set.
|
||||
* does not get set. Lastly, we support only default access strategy
|
||||
* (hence, usage_count is always advanced).
|
||||
*/
|
||||
BufferDesc *
|
||||
LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
@@ -88,7 +89,12 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
fprintf(stderr, "LB ALLOC (%u,%d) %d\n",
|
||||
RelationGetRelid(reln), blockNum, -b - 1);
|
||||
#endif
|
||||
|
||||
/* this part is equivalent to PinBuffer for a shared buffer */
|
||||
if (LocalRefCount[b] == 0)
|
||||
{
|
||||
if (bufHdr->usage_count < BM_MAX_USAGE_COUNT)
|
||||
bufHdr->usage_count++;
|
||||
}
|
||||
LocalRefCount[b]++;
|
||||
ResourceOwnerRememberBuffer(CurrentResourceOwner,
|
||||
BufferDescriptorGetBuffer(bufHdr));
|
||||
@@ -121,18 +127,21 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
|
||||
bufHdr = &LocalBufferDescriptors[b];
|
||||
|
||||
if (LocalRefCount[b] == 0 && bufHdr->usage_count == 0)
|
||||
if (LocalRefCount[b] == 0)
|
||||
{
|
||||
LocalRefCount[b]++;
|
||||
ResourceOwnerRememberBuffer(CurrentResourceOwner,
|
||||
BufferDescriptorGetBuffer(bufHdr));
|
||||
break;
|
||||
}
|
||||
|
||||
if (bufHdr->usage_count > 0)
|
||||
{
|
||||
bufHdr->usage_count--;
|
||||
trycounter = NLocBuffer;
|
||||
if (bufHdr->usage_count > 0)
|
||||
{
|
||||
bufHdr->usage_count--;
|
||||
trycounter = NLocBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Found a usable buffer */
|
||||
LocalRefCount[b]++;
|
||||
ResourceOwnerRememberBuffer(CurrentResourceOwner,
|
||||
BufferDescriptorGetBuffer(bufHdr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (--trycounter == 0)
|
||||
ereport(ERROR,
|
||||
@@ -199,7 +208,7 @@ LocalBufferAlloc(Relation reln, BlockNumber blockNum, bool *foundPtr)
|
||||
bufHdr->tag = newTag;
|
||||
bufHdr->flags &= ~(BM_VALID | BM_DIRTY | BM_JUST_DIRTIED | BM_IO_ERROR);
|
||||
bufHdr->flags |= BM_TAG_VALID;
|
||||
bufHdr->usage_count = 0;
|
||||
bufHdr->usage_count = 1;
|
||||
|
||||
*foundPtr = FALSE;
|
||||
return bufHdr;
|
||||
|
Reference in New Issue
Block a user