mirror of
https://github.com/postgres/postgres.git
synced 2025-07-21 16:02:15 +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:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.233 2007/05/27 03:50:38 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.234 2007/05/30 20:11:53 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -83,6 +83,24 @@ initscan(HeapScanDesc scan, ScanKey key)
|
||||
*/
|
||||
scan->rs_nblocks = RelationGetNumberOfBlocks(scan->rs_rd);
|
||||
|
||||
/*
|
||||
* If the table is large relative to NBuffers, use a bulk-read access
|
||||
* strategy, else use the default random-access strategy. During a
|
||||
* rescan, don't make a new strategy object if we don't have to.
|
||||
*/
|
||||
if (scan->rs_nblocks > NBuffers / 4 &&
|
||||
!scan->rs_rd->rd_istemp)
|
||||
{
|
||||
if (scan->rs_strategy == NULL)
|
||||
scan->rs_strategy = GetAccessStrategy(BAS_BULKREAD);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (scan->rs_strategy != NULL)
|
||||
FreeAccessStrategy(scan->rs_strategy);
|
||||
scan->rs_strategy = NULL;
|
||||
}
|
||||
|
||||
scan->rs_inited = false;
|
||||
scan->rs_ctup.t_data = NULL;
|
||||
ItemPointerSetInvalid(&scan->rs_ctup.t_self);
|
||||
@ -123,9 +141,17 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
|
||||
|
||||
Assert(page < scan->rs_nblocks);
|
||||
|
||||
scan->rs_cbuf = ReleaseAndReadBuffer(scan->rs_cbuf,
|
||||
scan->rs_rd,
|
||||
page);
|
||||
/* release previous scan buffer, if any */
|
||||
if (BufferIsValid(scan->rs_cbuf))
|
||||
{
|
||||
ReleaseBuffer(scan->rs_cbuf);
|
||||
scan->rs_cbuf = InvalidBuffer;
|
||||
}
|
||||
|
||||
/* read page using selected strategy */
|
||||
scan->rs_cbuf = ReadBufferWithStrategy(scan->rs_rd,
|
||||
page,
|
||||
scan->rs_strategy);
|
||||
scan->rs_cblock = page;
|
||||
|
||||
if (!scan->rs_pageatatime)
|
||||
@ -938,6 +964,7 @@ heap_beginscan(Relation relation, Snapshot snapshot,
|
||||
scan->rs_rd = relation;
|
||||
scan->rs_snapshot = snapshot;
|
||||
scan->rs_nkeys = nkeys;
|
||||
scan->rs_strategy = NULL; /* set in initscan */
|
||||
|
||||
/*
|
||||
* we can use page-at-a-time mode if it's an MVCC-safe snapshot
|
||||
@ -1007,6 +1034,9 @@ heap_endscan(HeapScanDesc scan)
|
||||
if (scan->rs_key)
|
||||
pfree(scan->rs_key);
|
||||
|
||||
if (scan->rs_strategy != NULL)
|
||||
FreeAccessStrategy(scan->rs_strategy);
|
||||
|
||||
pfree(scan);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user