From d526575f893c1a4e05ebd307e80203536b213a6d Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 30 May 2007 20:12:03 +0000 Subject: 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. --- src/backend/storage/buffer/localbuf.c | 39 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) (limited to 'src/backend/storage/buffer/localbuf.c') diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c index 306ffe45769..ad2bcf8dac6 100644 --- a/src/backend/storage/buffer/localbuf.c +++ b/src/backend/storage/buffer/localbuf.c @@ -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) - { - LocalRefCount[b]++; - ResourceOwnerRememberBuffer(CurrentResourceOwner, - BufferDescriptorGetBuffer(bufHdr)); - break; - } - - if (bufHdr->usage_count > 0) + if (LocalRefCount[b] == 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; -- cgit v1.2.3