diff --git a/contrib/amcheck/expected/check_heap.out b/contrib/amcheck/expected/check_heap.out
index 979e5e84e723d..569b0202f1cf1 100644
--- a/contrib/amcheck/expected/check_heap.out
+++ b/contrib/amcheck/expected/check_heap.out
@@ -67,11 +67,11 @@ INSERT INTO heaptest (a, b)
(SELECT gs, repeat('x', gs)
FROM generate_series(1,50) gs);
-- pg_stat_io test:
--- verify_heapam always uses a BAS_BULKREAD BufferAccessStrategy, whereas a
--- sequential scan does so only if the table is large enough when compared to
--- shared buffers (see initscan()). CREATE DATABASE ... also unconditionally
--- uses a BAS_BULKREAD strategy, but we have chosen to use a tablespace and
--- verify_heapam to provide coverage instead of adding another expensive
+-- verify_heapam reads the heap through the buffer manager; with the
+-- cooling-stage clock sweep there are no per-strategy IO contexts, so the
+-- reads are counted in the 'normal' context. CREATE DATABASE ... likewise
+-- reads through the normal context, but we have chosen to use a tablespace
+-- and verify_heapam to provide coverage instead of adding another expensive
-- operation to the main regression test suite.
--
-- Create an alternative tablespace and move the heaptest table to it, causing
@@ -83,7 +83,7 @@ INSERT INTO heaptest (a, b)
SET allow_in_place_tablespaces = true;
CREATE TABLESPACE regress_test_stats_tblspc LOCATION '';
SELECT sum(reads) AS stats_bulkreads_before
- FROM pg_stat_io WHERE context = 'bulkread' \gset
+ FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
BEGIN;
ALTER TABLE heaptest SET TABLESPACE regress_test_stats_tblspc;
-- Check that valid options are not rejected nor corruption reported
@@ -111,7 +111,7 @@ SELECT * FROM verify_heapam(relation := 'heaptest', startblock := 0, endblock :=
COMMIT;
-- verify_heapam should have read in the page written out by
-- ALTER TABLE ... SET TABLESPACE ...
--- causing an additional bulkread, which should be reflected in pg_stat_io.
+-- causing additional reads, which should be reflected in pg_stat_io.
SELECT pg_stat_force_next_flush();
pg_stat_force_next_flush
--------------------------
@@ -119,7 +119,7 @@ SELECT pg_stat_force_next_flush();
(1 row)
SELECT sum(reads) AS stats_bulkreads_after
- FROM pg_stat_io WHERE context = 'bulkread' \gset
+ FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
SELECT :stats_bulkreads_after > :stats_bulkreads_before;
?column?
----------
diff --git a/contrib/amcheck/sql/check_heap.sql b/contrib/amcheck/sql/check_heap.sql
index 1745bae634e56..61f710dbedafd 100644
--- a/contrib/amcheck/sql/check_heap.sql
+++ b/contrib/amcheck/sql/check_heap.sql
@@ -27,11 +27,11 @@ INSERT INTO heaptest (a, b)
FROM generate_series(1,50) gs);
-- pg_stat_io test:
--- verify_heapam always uses a BAS_BULKREAD BufferAccessStrategy, whereas a
--- sequential scan does so only if the table is large enough when compared to
--- shared buffers (see initscan()). CREATE DATABASE ... also unconditionally
--- uses a BAS_BULKREAD strategy, but we have chosen to use a tablespace and
--- verify_heapam to provide coverage instead of adding another expensive
+-- verify_heapam reads the heap through the buffer manager; with the
+-- cooling-stage clock sweep there are no per-strategy IO contexts, so the
+-- reads are counted in the 'normal' context. CREATE DATABASE ... likewise
+-- reads through the normal context, but we have chosen to use a tablespace
+-- and verify_heapam to provide coverage instead of adding another expensive
-- operation to the main regression test suite.
--
-- Create an alternative tablespace and move the heaptest table to it, causing
@@ -43,7 +43,7 @@ INSERT INTO heaptest (a, b)
SET allow_in_place_tablespaces = true;
CREATE TABLESPACE regress_test_stats_tblspc LOCATION '';
SELECT sum(reads) AS stats_bulkreads_before
- FROM pg_stat_io WHERE context = 'bulkread' \gset
+ FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
BEGIN;
ALTER TABLE heaptest SET TABLESPACE regress_test_stats_tblspc;
-- Check that valid options are not rejected nor corruption reported
@@ -56,10 +56,10 @@ COMMIT;
-- verify_heapam should have read in the page written out by
-- ALTER TABLE ... SET TABLESPACE ...
--- causing an additional bulkread, which should be reflected in pg_stat_io.
+-- causing additional reads, which should be reflected in pg_stat_io.
SELECT pg_stat_force_next_flush();
SELECT sum(reads) AS stats_bulkreads_after
- FROM pg_stat_io WHERE context = 'bulkread' \gset
+ FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
SELECT :stats_bulkreads_after > :stats_bulkreads_before;
CREATE ROLE regress_heaptest_role;
diff --git a/contrib/amcheck/verify_gin.c b/contrib/amcheck/verify_gin.c
index fa06689ed5b29..ef2e64475c661 100644
--- a/contrib/amcheck/verify_gin.c
+++ b/contrib/amcheck/verify_gin.c
@@ -63,8 +63,7 @@ static void gin_check_parent_keys_consistency(Relation rel,
static void check_index_page(Relation rel, Buffer buffer, BlockNumber blockNo);
static IndexTuple gin_refind_parent(Relation rel,
BlockNumber parentblkno,
- BlockNumber childblkno,
- BufferAccessStrategy strategy);
+ BlockNumber childblkno);
static ItemId PageGetItemIdCareful(Relation rel, BlockNumber block, Page page,
OffsetNumber offset);
@@ -133,7 +132,6 @@ ginReadTupleWithoutState(IndexTuple itup, int *nitems)
static void
gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting_tree_root)
{
- BufferAccessStrategy strategy = GetAccessStrategy(BAS_BULKREAD);
GinPostingTreeScanItem *stack;
MemoryContext mctx;
MemoryContext oldcontext;
@@ -171,8 +169,7 @@ gin_check_posting_tree_parent_keys_consistency(Relation rel, BlockNumber posting
CHECK_FOR_INTERRUPTS();
- buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
- RBM_NORMAL, strategy);
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno, RBM_NORMAL);
LockBuffer(buffer, GIN_SHARE);
page = BufferGetPage(buffer);
@@ -391,7 +388,6 @@ gin_check_parent_keys_consistency(Relation rel,
void *callback_state,
bool readonly)
{
- BufferAccessStrategy strategy = GetAccessStrategy(BAS_BULKREAD);
GinScanItem *stack;
MemoryContext mctx;
MemoryContext oldcontext;
@@ -430,8 +426,7 @@ gin_check_parent_keys_consistency(Relation rel,
CHECK_FOR_INTERRUPTS();
- buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno,
- RBM_NORMAL, strategy);
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, stack->blkno, RBM_NORMAL);
LockBuffer(buffer, GIN_SHARE);
page = BufferGetPage(buffer);
maxoff = PageGetMaxOffsetNumber(page);
@@ -567,7 +562,7 @@ gin_check_parent_keys_consistency(Relation rel,
*/
pfree(stack->parenttup);
stack->parenttup = gin_refind_parent(rel, stack->parentblk,
- stack->blkno, strategy);
+ stack->blkno);
/* We found it - make a final check before failing */
if (!stack->parenttup)
@@ -719,7 +714,7 @@ check_index_page(Relation rel, Buffer buffer, BlockNumber blockNo)
*/
static IndexTuple
gin_refind_parent(Relation rel, BlockNumber parentblkno,
- BlockNumber childblkno, BufferAccessStrategy strategy)
+ BlockNumber childblkno)
{
Buffer parentbuf;
Page parentpage;
@@ -727,8 +722,7 @@ gin_refind_parent(Relation rel, BlockNumber parentblkno,
parent_maxoff;
IndexTuple result = NULL;
- parentbuf = ReadBufferExtended(rel, MAIN_FORKNUM, parentblkno, RBM_NORMAL,
- strategy);
+ parentbuf = ReadBufferExtended(rel, MAIN_FORKNUM, parentblkno, RBM_NORMAL);
LockBuffer(parentbuf, GIN_SHARE);
parentpage = BufferGetPage(parentbuf);
diff --git a/contrib/amcheck/verify_heapam.c b/contrib/amcheck/verify_heapam.c
index 20ff58aa78259..e4336eb5fc2a4 100644
--- a/contrib/amcheck/verify_heapam.c
+++ b/contrib/amcheck/verify_heapam.c
@@ -126,7 +126,6 @@ typedef struct HeapCheckContext
* recent block in the buffer yielded by the read stream API.
*/
BlockNumber blkno;
- BufferAccessStrategy bstrategy;
Buffer buffer;
Page page;
@@ -374,7 +373,6 @@ verify_heapam(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
}
- ctx.bstrategy = GetAccessStrategy(BAS_BULKREAD);
ctx.buffer = InvalidBuffer;
ctx.page = NULL;
@@ -472,7 +470,6 @@ verify_heapam(PG_FUNCTION_ARGS)
}
stream = read_stream_begin_relation(stream_flags,
- ctx.bstrategy,
ctx.rel,
MAIN_FORKNUM,
stream_cb,
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index 3ef2d66f82675..18cd8928fdd85 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -88,8 +88,6 @@ typedef struct BtreeCheckState
bool checkunique;
/* Per-page context */
MemoryContext targetcontext;
- /* Buffer access strategy */
- BufferAccessStrategy checkstrategy;
/*
* Info for uniqueness checking. Fill this field and the one below once
@@ -490,7 +488,6 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
state->targetcontext = AllocSetContextCreate(CurrentMemoryContext,
"amcheck context",
ALLOCSET_DEFAULT_SIZES);
- state->checkstrategy = GetAccessStrategy(BAS_BULKREAD);
/* Get true root block from meta-page */
metapage = palloc_btree_page(state, BTREE_METAPAGE);
@@ -1115,7 +1112,7 @@ bt_recheck_sibling_links(BtreeCheckState *state,
/* Couple locks in the usual order for nbtree: Left to right */
lbuf = ReadBufferExtended(state->rel, MAIN_FORKNUM, leftcurrent,
- RBM_NORMAL, state->checkstrategy);
+ RBM_NORMAL);
LockBuffer(lbuf, BT_READ);
_bt_checkpage(state->rel, lbuf);
page = BufferGetPage(lbuf);
@@ -1138,8 +1135,7 @@ bt_recheck_sibling_links(BtreeCheckState *state,
if (newtargetblock != leftcurrent)
{
newtargetbuf = ReadBufferExtended(state->rel, MAIN_FORKNUM,
- newtargetblock, RBM_NORMAL,
- state->checkstrategy);
+ newtargetblock, RBM_NORMAL);
LockBuffer(newtargetbuf, BT_READ);
_bt_checkpage(state->rel, newtargetbuf);
page = BufferGetPage(newtargetbuf);
@@ -3300,8 +3296,7 @@ palloc_btree_page(BtreeCheckState *state, BlockNumber blocknum)
* We copy the page into local storage to avoid holding pin on the buffer
* longer than we must.
*/
- buffer = ReadBufferExtended(state->rel, MAIN_FORKNUM, blocknum, RBM_NORMAL,
- state->checkstrategy);
+ buffer = ReadBufferExtended(state->rel, MAIN_FORKNUM, blocknum, RBM_NORMAL);
LockBuffer(buffer, BT_READ);
/*
diff --git a/contrib/bloom/blscan.c b/contrib/bloom/blscan.c
index 1a0e42021ec1e..ed62d5c04e6e0 100644
--- a/contrib/bloom/blscan.c
+++ b/contrib/bloom/blscan.c
@@ -80,7 +80,6 @@ blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
BlockNumber blkno,
npages;
int i;
- BufferAccessStrategy bas;
BloomScanOpaque so = (BloomScanOpaque) scan->opaque;
BlockRangeReadStreamPrivate p;
ReadStream *stream;
@@ -113,11 +112,6 @@ blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
}
}
- /*
- * We're going to read the whole index. This is why we use appropriate
- * buffer access strategy.
- */
- bas = GetAccessStrategy(BAS_BULKREAD);
npages = RelationGetNumberOfBlocks(scan->indexRelation);
pgstat_count_index_scan(scan->indexRelation);
if (scan->instrument)
@@ -133,7 +127,6 @@ blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
*/
stream = read_stream_begin_relation(READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- bas,
scan->indexRelation,
MAIN_FORKNUM,
block_range_read_stream_cb,
@@ -184,7 +177,6 @@ blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer);
read_stream_end(stream);
- FreeAccessStrategy(bas);
return ntids;
}
diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
index 5111cdc6dd62f..6c1ec15c59ce9 100644
--- a/contrib/bloom/blutils.c
+++ b/contrib/bloom/blutils.c
@@ -392,7 +392,7 @@ BloomNewBuffer(Relation index)
}
/* Must extend the file */
- buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM, NULL,
+ buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM,
EB_LOCK_FIRST);
return buffer;
@@ -460,7 +460,7 @@ BloomInitMetapage(Relation index, ForkNumber forknum)
* block number 0 (BLOOM_METAPAGE_BLKNO). No need to hold the extension
* lock because there cannot be concurrent inserters yet.
*/
- metaBuffer = ReadBufferExtended(index, forknum, P_NEW, RBM_NORMAL, NULL);
+ metaBuffer = ReadBufferExtended(index, forknum, P_NEW, RBM_NORMAL);
LockBuffer(metaBuffer, BUFFER_LOCK_EXCLUSIVE);
Assert(BufferGetBlockNumber(metaBuffer) == BLOOM_METAPAGE_BLKNO);
diff --git a/contrib/bloom/blvacuum.c b/contrib/bloom/blvacuum.c
index 6beb1c20ebb0d..08d7705e36500 100644
--- a/contrib/bloom/blvacuum.c
+++ b/contrib/bloom/blvacuum.c
@@ -66,7 +66,6 @@ blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- info->strategy,
index,
MAIN_FORKNUM,
block_range_read_stream_cb,
@@ -219,7 +218,6 @@ blvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- info->strategy,
index,
MAIN_FORKNUM,
block_range_read_stream_cb,
diff --git a/contrib/pageinspect/rawpage.c b/contrib/pageinspect/rawpage.c
index d136593edb267..bbe8edf916113 100644
--- a/contrib/pageinspect/rawpage.c
+++ b/contrib/pageinspect/rawpage.c
@@ -188,7 +188,7 @@ get_raw_page_internal(text *relname, ForkNumber forknum, BlockNumber blkno)
/* Take a verbatim copy of the page */
- buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL, NULL);
+ buf = ReadBufferExtended(rel, forknum, blkno, RBM_NORMAL);
LockBuffer(buf, BUFFER_LOCK_SHARE);
memcpy(raw_page_data, BufferGetPage(buf), BLCKSZ);
diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c
index 510455998aa74..b94e6f6fda80b 100644
--- a/contrib/pg_buffercache/pg_buffercache_pages.c
+++ b/contrib/pg_buffercache/pg_buffercache_pages.c
@@ -161,7 +161,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
reldatabase = bufHdr->tag.dbOid;
forknum = BufTagGetForkNum(&bufHdr->tag);
blocknum = bufHdr->tag.blockNum;
- usagecount = BUF_STATE_GET_USAGECOUNT(buf_state);
+ usagecount = BUF_STATE_GET_COOLSTATE(buf_state);
pinning_backends = BUF_STATE_GET_REFCOUNT(buf_state);
if (buf_state & BM_DIRTY)
@@ -605,7 +605,7 @@ pg_buffercache_summary(PG_FUNCTION_ARGS)
if (buf_state & BM_VALID)
{
buffers_used++;
- usagecount_total += BUF_STATE_GET_USAGECOUNT(buf_state);
+ usagecount_total += BUF_STATE_GET_COOLSTATE(buf_state);
if (buf_state & BM_DIRTY)
buffers_dirty++;
@@ -655,7 +655,7 @@ pg_buffercache_usage_counts(PG_FUNCTION_ARGS)
CHECK_FOR_INTERRUPTS();
- usage_count = BUF_STATE_GET_USAGECOUNT(buf_state);
+ usage_count = BUF_STATE_GET_COOLSTATE(buf_state);
usage_counts[usage_count]++;
if (buf_state & BM_DIRTY)
diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index deb4c2671b5d8..33ad88ea8b12c 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -630,7 +630,6 @@ autoprewarm_database_main(Datum main_arg)
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_DEFAULT |
READ_STREAM_USE_BATCHING,
- NULL,
rel,
p.forknum,
apw_read_stream_next_block,
diff --git a/contrib/pg_prewarm/pg_prewarm.c b/contrib/pg_prewarm/pg_prewarm.c
index c2716086693d9..716a6754a7e20 100644
--- a/contrib/pg_prewarm/pg_prewarm.c
+++ b/contrib/pg_prewarm/pg_prewarm.c
@@ -251,7 +251,6 @@ pg_prewarm(PG_FUNCTION_ARGS)
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- NULL,
rel,
forkNumber,
block_range_read_stream_cb,
diff --git a/contrib/pg_visibility/pg_visibility.c b/contrib/pg_visibility/pg_visibility.c
index dfab0b64cf50b..ccb829a09eb89 100644
--- a/contrib/pg_visibility/pg_visibility.c
+++ b/contrib/pg_visibility/pg_visibility.c
@@ -488,7 +488,6 @@ collect_visibility_data(Oid relid, bool include_pd)
vbits *info;
BlockNumber blkno;
Buffer vmbuffer = InvalidBuffer;
- BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
BlockRangeReadStreamPrivate p;
ReadStream *stream = NULL;
@@ -514,7 +513,6 @@ collect_visibility_data(Oid relid, bool include_pd)
*/
stream = read_stream_begin_relation(READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- bstrategy,
rel,
MAIN_FORKNUM,
block_range_read_stream_cb,
@@ -538,8 +536,7 @@ collect_visibility_data(Oid relid, bool include_pd)
/*
* Page-level data requires reading every block, so only get it if the
- * caller needs it. Use a buffer access strategy, too, to prevent
- * cache-trashing.
+ * caller needs it.
*/
if (include_pd)
{
@@ -700,7 +697,6 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
Relation rel;
corrupt_items *items;
Buffer vmbuffer = InvalidBuffer;
- BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
TransactionId OldestXmin = InvalidTransactionId;
struct collect_corrupt_items_read_stream_private p;
ReadStream *stream;
@@ -734,7 +730,6 @@ collect_corrupt_items(Oid relid, bool all_visible, bool all_frozen)
p.all_frozen = all_frozen;
p.all_visible = all_visible;
stream = read_stream_begin_relation(READ_STREAM_FULL,
- bstrategy,
rel,
MAIN_FORKNUM,
collect_corrupt_items_read_stream_next_block,
diff --git a/contrib/pgstattuple/pgstatapprox.c b/contrib/pgstattuple/pgstatapprox.c
index 21e0b50fb4bd4..8e17d48991e47 100644
--- a/contrib/pgstattuple/pgstatapprox.c
+++ b/contrib/pgstattuple/pgstatapprox.c
@@ -116,13 +116,11 @@ static void
statapprox_heap(Relation rel, output_type *stat)
{
BlockNumber nblocks;
- BufferAccessStrategy bstrategy;
TransactionId OldestXmin;
StatApproxReadStreamPrivate p;
ReadStream *stream;
OldestXmin = GetOldestNonRemovableTransactionId(rel);
- bstrategy = GetAccessStrategy(BAS_BULKREAD);
nblocks = RelationGetNumberOfBlocks(rel);
@@ -141,7 +139,6 @@ statapprox_heap(Relation rel, output_type *stat)
* caution.
*/
stream = read_stream_begin_relation(READ_STREAM_FULL,
- bstrategy,
rel,
MAIN_FORKNUM,
statapprox_heap_read_stream_next,
diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index 8951ad0aac472..a0922b386a00a 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -217,7 +217,6 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
BlockNumber nblocks;
BlockNumber blkno;
BTIndexStat indexStat;
- BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
BlockRangeReadStreamPrivate p;
ReadStream *stream;
BlockNumber startblk;
@@ -254,7 +253,7 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
* Read metapage
*/
{
- Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy);
+ Buffer buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL);
Page page = BufferGetPage(buffer);
BTMetaPageData *metad = BTPageGetMeta(page);
@@ -291,7 +290,6 @@ pgstatindex_impl(Relation rel, FunctionCallInfo fcinfo)
*/
stream = read_stream_begin_relation(READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- bstrategy,
rel,
MAIN_FORKNUM,
block_range_read_stream_cb,
@@ -612,7 +610,6 @@ pgstathashindex(PG_FUNCTION_ARGS)
BlockNumber blkno;
Relation rel;
HashIndexStat stats;
- BufferAccessStrategy bstrategy;
HeapTuple tuple;
TupleDesc tupleDesc;
Datum values[8];
@@ -665,9 +662,6 @@ pgstathashindex(PG_FUNCTION_ARGS)
/* Get the current relation length */
nblocks = RelationGetNumberOfBlocks(rel);
- /* prepare access strategy for this index */
- bstrategy = GetAccessStrategy(BAS_BULKREAD);
-
/* Scan all blocks except the metapage (0th page) using streaming reads */
startblk = HASH_METAPAGE + 1;
@@ -680,7 +674,6 @@ pgstathashindex(PG_FUNCTION_ARGS)
*/
stream = read_stream_begin_relation(READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- bstrategy,
rel,
MAIN_FORKNUM,
block_range_read_stream_cb,
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 6a7f8cb4a7ca5..90f7938e95313 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -64,22 +64,18 @@ typedef struct pgstattuple_type
uint64 free_space; /* free/reusable space in bytes */
} pgstattuple_type;
-typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber,
- BufferAccessStrategy);
+typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber);
static Datum build_pgstattuple_type(pgstattuple_type *stat,
FunctionCallInfo fcinfo);
static Datum pgstat_relation(Relation rel, FunctionCallInfo fcinfo);
static Datum pgstat_heap(Relation rel, FunctionCallInfo fcinfo);
static void pgstat_btree_page(pgstattuple_type *stat,
- Relation rel, BlockNumber blkno,
- BufferAccessStrategy bstrategy);
+ Relation rel, BlockNumber blkno);
static void pgstat_hash_page(pgstattuple_type *stat,
- Relation rel, BlockNumber blkno,
- BufferAccessStrategy bstrategy);
+ Relation rel, BlockNumber blkno);
static void pgstat_gist_page(pgstattuple_type *stat,
- Relation rel, BlockNumber blkno,
- BufferAccessStrategy bstrategy);
+ Relation rel, BlockNumber blkno);
static Datum pgstat_index(Relation rel, BlockNumber start,
pgstat_page pagefn, FunctionCallInfo fcinfo);
static void pgstat_index_page(pgstattuple_type *stat, Page page,
@@ -376,7 +372,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
CHECK_FOR_INTERRUPTS();
buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block,
- RBM_NORMAL, hscan->rs_strategy);
+ RBM_NORMAL);
LockBuffer(buffer, BUFFER_LOCK_SHARE);
stat.free_space += PageGetExactFreeSpace(BufferGetPage(buffer));
UnlockReleaseBuffer(buffer);
@@ -389,7 +385,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
CHECK_FOR_INTERRUPTS();
buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block,
- RBM_NORMAL, hscan->rs_strategy);
+ RBM_NORMAL);
LockBuffer(buffer, BUFFER_LOCK_SHARE);
stat.free_space += PageGetExactFreeSpace(BufferGetPage(buffer));
UnlockReleaseBuffer(buffer);
@@ -408,13 +404,12 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
* pgstat_btree_page -- check tuples in a btree page
*/
static void
-pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
- BufferAccessStrategy bstrategy)
+pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
{
Buffer buf;
Page page;
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL);
LockBuffer(buf, BT_READ);
page = BufferGetPage(buf);
@@ -452,13 +447,12 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
* pgstat_hash_page -- check tuples in a hash page
*/
static void
-pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
- BufferAccessStrategy bstrategy)
+pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
{
Buffer buf;
Page page;
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL);
LockBuffer(buf, HASH_READ);
page = BufferGetPage(buf);
@@ -500,13 +494,12 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
* pgstat_gist_page -- check tuples in a gist page
*/
static void
-pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
- BufferAccessStrategy bstrategy)
+pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
{
Buffer buf;
Page page;
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL);
LockBuffer(buf, GIST_SHARE);
page = BufferGetPage(buf);
if (PageIsNew(page))
@@ -539,12 +532,8 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
{
BlockNumber nblocks;
BlockNumber blkno;
- BufferAccessStrategy bstrategy;
pgstattuple_type stat = {0};
- /* prepare access strategy for this index */
- bstrategy = GetAccessStrategy(BAS_BULKREAD);
-
blkno = start;
for (;;)
{
@@ -565,7 +554,7 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
{
CHECK_FOR_INTERRUPTS();
- pagefn(&stat, rel, blkno, bstrategy);
+ pagefn(&stat, rel, blkno);
}
}
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 0848c18d329e3..7cb8839245c7d 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2107,36 +2107,6 @@ include_dir 'conf.d'
-
-
- vacuum_buffer_usage_limit (integer)
-
- vacuum_buffer_usage_limit configuration parameter
-
-
-
-
- Specifies the size of the
- Buffer Access Strategy
- used by the VACUUM and ANALYZE
- commands. A setting of 0 will allow the operation
- to use any number of shared_buffers. Otherwise
- valid sizes range from 128 kB to
- 16 GB. If the specified size would exceed 1/8 the
- size of shared_buffers, the size is silently capped
- to that value. The default value is 2MB. If
- this value is specified without units, it is taken as kilobytes. This
- parameter can be set at any time. It can be overridden for
- and
- when passing the option. Higher
- settings can allow VACUUM and
- ANALYZE to run more quickly, but having too large a
- setting may cause too many other useful pages to be evicted from
- shared buffers.
-
-
-
-
logical_decoding_work_mem (integer)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index d1a20d001e9c8..18d17540430db 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2993,28 +2993,6 @@ description | Waiting for a newly initialized WAL file to reach durable storage
init.
-
-
- vacuum: I/O operations performed outside of shared
- buffers while vacuuming and analyzing permanent relations. Temporary
- table vacuums use the same local buffer pool as other temporary table
- I/O operations and are tracked in context
- normal.
-
-
-
-
- bulkread: Certain large read I/O operations
- done outside of shared buffers, for example, a sequential scan of a
- large table.
-
-
-
-
- bulkwrite: Certain large write I/O operations
- done outside of shared buffers, such as COPY.
-
-
@@ -3180,13 +3158,8 @@ description | Waiting for a newly initialized WAL file to reach durable storage
buffer in order to make it available for another use.
- In contextnormal, this counts
- the number of times a block was evicted from a buffer and replaced with
- another block. In contexts
- bulkwrite, bulkread, and
- vacuum, this counts the number of times a block was
- evicted from shared buffers in order to add the shared buffer to a
- separate, size-limited ring buffer for use in a bulk I/O operation.
+ This counts the number of times a block was evicted from a buffer and
+ replaced with another block.
@@ -3197,10 +3170,9 @@ description | Waiting for a newly initialized WAL file to reach durable storage
reusesbigint
- The number of times an existing buffer in a size-limited ring buffer
- outside of shared buffers was reused as part of an I/O operation in the
- bulkread, bulkwrite, or
- vacuumcontexts.
+ Always zero. This column previously counted reuses of buffers in a
+ size-limited ring buffer (buffer access strategy); ring buffers have
+ been removed, so no reuses are tracked.
diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml
index ec81f00fecf87..7f5159111d888 100644
--- a/doc/src/sgml/ref/analyze.sgml
+++ b/doc/src/sgml/ref/analyze.sgml
@@ -27,7 +27,6 @@ ANALYZE [ ( option [, ...] ) ] [ boolean ]
SKIP_LOCKED [ boolean ]
- BUFFER_USAGE_LIMIT sizeand table_and_columns is:
@@ -88,26 +87,6 @@ ANALYZE [ ( option [, ...] ) ] [
-
- BUFFER_USAGE_LIMIT
-
-
- Specifies the
- Buffer Access Strategy
- ring buffer size for ANALYZE. This size is used to
- calculate the number of shared buffers which will be reused as part of
- this strategy. 0 disables use of a
- Buffer Access Strategy. When this option is not
- specified, ANALYZE uses the value from
- . Higher settings can
- allow ANALYZE to run more quickly, but having too
- large a setting may cause too many other useful pages to be evicted from
- shared buffers. The minimum value is 128 kB and the
- maximum value is 16 GB.
-
-
-
-
boolean
diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml
index 38ee973ea05d6..d44a49f8efe3f 100644
--- a/doc/src/sgml/ref/vacuum.sgml
+++ b/doc/src/sgml/ref/vacuum.sgml
@@ -37,7 +37,6 @@ VACUUM [ ( option [, ...] ) ] [ integer
SKIP_DATABASE_STATS [ boolean ]
ONLY_DATABASE_STATS [ boolean ]
- BUFFER_USAGE_LIMIT size
FULL [ boolean ]
and table_and_columns is:
@@ -309,30 +308,6 @@ VACUUM [ ( option [, ...] ) ] [
-
- BUFFER_USAGE_LIMIT
-
-
- Specifies the
- Buffer Access Strategy
- ring buffer size for VACUUM. This size is used to
- calculate the number of shared buffers which will be reused as part of
- this strategy. 0 disables use of a
- Buffer Access Strategy. If
- is also specified, the value is used
- for both the vacuum and analyze stages. This option can't be used with
- the option except if is
- also specified. When this option is not specified,
- VACUUM uses the value from
- . Higher settings can
- allow VACUUM to run more quickly, but having too
- large a setting may cause too many other useful pages to be evicted from
- shared buffers. The minimum value is 128 kB and the
- maximum value is 16 GB.
-
-
-
-
FULL
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
index bdb30752e098c..5d6539f548357 100644
--- a/src/backend/access/brin/brin.c
+++ b/src/backend/access/brin/brin.c
@@ -224,7 +224,7 @@ static void form_and_insert_tuple(BrinBuildState *state);
static void form_and_spill_tuple(BrinBuildState *state);
static void union_tuples(BrinDesc *bdesc, BrinMemTuple *a,
BrinTuple *b);
-static void brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy);
+static void brin_vacuum_scan(Relation idxrel);
static bool add_values_to_range(Relation idxRel, BrinDesc *bdesc,
BrinMemTuple *dtup, const Datum *values, const bool *nulls);
static bool check_null_keys(BrinValues *bval, ScanKey *nullkeys, int nnullkeys);
@@ -1129,7 +1129,7 @@ brinbuild(Relation heap, Relation index, IndexInfo *indexInfo)
* whole relation will be rolled back.
*/
- meta = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM, NULL,
+ meta = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM,
EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
Assert(BufferGetBlockNumber(meta) == BRIN_METAPAGE_BLKNO);
@@ -1281,7 +1281,7 @@ brinbuildempty(Relation index)
Buffer metabuf;
/* An empty BRIN index has a metapage only. */
- metabuf = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
+ metabuf = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM,
EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
/* Initialize and xlog metabuffer. */
@@ -1336,7 +1336,7 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
heapRel = table_open(IndexGetRelation(RelationGetRelid(info->index), false),
AccessShareLock);
- brin_vacuum_scan(info->index, info->strategy);
+ brin_vacuum_scan(info->index);
brinsummarize(info->index, heapRel, BRIN_ALL_BLOCKRANGES, false,
&stats->num_index_tuples, &stats->num_index_tuples);
@@ -2171,7 +2171,7 @@ union_tuples(BrinDesc *bdesc, BrinMemTuple *a, BrinTuple *b)
* and such.
*/
static void
-brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy)
+brin_vacuum_scan(Relation idxrel)
{
BlockRangeReadStreamPrivate p;
ReadStream *stream;
@@ -2187,7 +2187,6 @@ brin_vacuum_scan(Relation idxrel, BufferAccessStrategy strategy)
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- strategy,
idxrel,
MAIN_FORKNUM,
block_range_read_stream_cb,
diff --git a/src/backend/access/brin/brin_revmap.c b/src/backend/access/brin/brin_revmap.c
index 233355cb2d5d1..01c4104ac88dd 100644
--- a/src/backend/access/brin/brin_revmap.c
+++ b/src/backend/access/brin/brin_revmap.c
@@ -559,7 +559,7 @@ revmap_physical_extend(BrinRevmap *revmap)
}
else
{
- buf = ExtendBufferedRel(BMR_REL(irel), MAIN_FORKNUM, NULL,
+ buf = ExtendBufferedRel(BMR_REL(irel), MAIN_FORKNUM,
EB_LOCK_FIRST);
if (BufferGetBlockNumber(buf) != mapBlk)
{
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index cb9ed3b563c6f..32ad65cc95ff2 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -815,9 +815,9 @@ ginbuildempty(Relation index)
MetaBuffer;
/* An empty GIN index has two pages. */
- MetaBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
+ MetaBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM,
EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
- RootBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
+ RootBuffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM,
EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
/* Initialize and xlog metabuffer and root buffer. */
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index e7cba81d47709..2d7394aedd5d3 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -336,7 +336,7 @@ GinNewBuffer(Relation index)
}
/* Must extend the file */
- buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM, NULL,
+ buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM,
EB_LOCK_FIRST);
return buffer;
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index 840543eb6642b..86538de39d628 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -32,7 +32,6 @@ struct GinVacuumState
IndexBulkDeleteCallback callback;
void *callback_state;
GinState ginstate;
- BufferAccessStrategy strategy;
MemoryContext tmpCxt;
};
@@ -289,7 +288,7 @@ ginScanPostingTreeToDelete(GinVacuumState *gvs, DataPageDeleteStack *myStackItem
childBuffer = ReadBufferExtended(gvs->index,
MAIN_FORKNUM,
PostingItemGetBlockNumber(pitem),
- RBM_NORMAL, gvs->strategy);
+ RBM_NORMAL);
LockBuffer(childBuffer, GIN_EXCLUSIVE);
/* Allocate a child stack entry on first use; reuse thereafter */
@@ -389,7 +388,7 @@ ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno)
PostingItem *pitem;
buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
- RBM_NORMAL, gvs->strategy);
+ RBM_NORMAL);
LockBuffer(buffer, GIN_SHARE);
page = BufferGetPage(buffer);
@@ -430,7 +429,7 @@ ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno)
break;
buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, blkno,
- RBM_NORMAL, gvs->strategy);
+ RBM_NORMAL);
LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer);
}
@@ -454,7 +453,7 @@ ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
bool deleted PG_USED_FOR_ASSERTS_ONLY;
buffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, rootBlkno,
- RBM_NORMAL, gvs->strategy);
+ RBM_NORMAL);
/*
* Lock posting tree root for cleanup to ensure there are no
@@ -615,7 +614,6 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
gvs.index = index;
gvs.callback = callback;
gvs.callback_state = callback_state;
- gvs.strategy = info->strategy;
initGinState(&gvs.ginstate, index);
/* first time through? */
@@ -636,7 +634,7 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
gvs.result = stats;
buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
- RBM_NORMAL, info->strategy);
+ RBM_NORMAL);
/* find leaf page */
for (;;)
@@ -669,7 +667,7 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
UnlockReleaseBuffer(buffer);
buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
- RBM_NORMAL, info->strategy);
+ RBM_NORMAL);
}
/* right now we found leftmost page in entry's BTree */
@@ -712,7 +710,7 @@ ginbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
break;
buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
- RBM_NORMAL, info->strategy);
+ RBM_NORMAL);
LockBuffer(buffer, GIN_EXCLUSIVE);
}
@@ -794,7 +792,6 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- info->strategy,
index,
MAIN_FORKNUM,
block_range_read_stream_cb,
diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c
index 8565e225be7fd..ae494742a4b8f 100644
--- a/src/backend/access/gist/gist.c
+++ b/src/backend/access/gist/gist.c
@@ -142,7 +142,7 @@ gistbuildempty(Relation index)
Buffer buffer;
/* Initialize the root page */
- buffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM, NULL,
+ buffer = ExtendBufferedRel(BMR_REL(index), INIT_FORKNUM,
EB_SKIP_EXTENSION_LOCK | EB_LOCK_FIRST);
/* Initialize and xlog buffer */
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 0f58f61879fb0..170174f62fd56 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -877,7 +877,7 @@ gistNewBuffer(Relation r, Relation heaprel)
}
/* Must extend the file */
- buffer = ExtendBufferedRel(BMR_REL(r), MAIN_FORKNUM, NULL,
+ buffer = ExtendBufferedRel(BMR_REL(r), MAIN_FORKNUM,
EB_LOCK_FIRST);
return buffer;
diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index 686a04180546b..c366ed35ea876 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -218,7 +218,6 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- info->strategy,
rel,
MAIN_FORKNUM,
block_range_read_stream_cb,
@@ -491,8 +490,7 @@ gistvacuumpage(GistVacState *vstate, Buffer buffer)
/* check for vacuum delay while not holding any buffer lock */
vacuum_delay_point(false);
- buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
- info->strategy);
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL);
goto restart;
}
}
@@ -524,8 +522,7 @@ gistvacuum_delete_empty_pages(IndexVacuumInfo *info, GistVacState *vstate)
int ntodelete;
int deleted;
- buffer = ReadBufferExtended(rel, MAIN_FORKNUM, (BlockNumber) blkno,
- RBM_NORMAL, info->strategy);
+ buffer = ReadBufferExtended(rel, MAIN_FORKNUM, (BlockNumber) blkno, RBM_NORMAL);
LockBuffer(buffer, GIST_SHARE);
page = BufferGetPage(buffer);
@@ -590,8 +587,7 @@ gistvacuum_delete_empty_pages(IndexVacuumInfo *info, GistVacState *vstate)
if (PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
break;
- leafbuf = ReadBufferExtended(rel, MAIN_FORKNUM, leafs_to_delete[i],
- RBM_NORMAL, info->strategy);
+ leafbuf = ReadBufferExtended(rel, MAIN_FORKNUM, leafs_to_delete[i], RBM_NORMAL);
LockBuffer(leafbuf, GIST_EXCLUSIVE);
gistcheckpage(rel, leafbuf);
diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index 8d8cd30dc386b..1bbb7224bfcba 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -542,7 +542,6 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
*/
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_USE_BATCHING,
- info->strategy,
rel,
MAIN_FORKNUM,
hash_bulkdelete_read_stream_cb,
@@ -616,7 +615,7 @@ hashbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
bucket_buf = buf;
- hashbucketcleanup(rel, cur_bucket, bucket_buf, blkno, info->strategy,
+ hashbucketcleanup(rel, cur_bucket, bucket_buf, blkno,
cachedmetap->hashm_maxbucket,
cachedmetap->hashm_highmask,
cachedmetap->hashm_lowmask, &tuples_removed,
@@ -765,7 +764,7 @@ hashvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
*/
void
hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
- BlockNumber bucket_blkno, BufferAccessStrategy bstrategy,
+ BlockNumber bucket_blkno,
uint32 maxbucket, uint32 highmask, uint32 lowmask,
double *tuples_removed, double *num_index_tuples,
bool split_cleanup,
@@ -935,9 +934,8 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
if (!BlockNumberIsValid(blkno))
break;
- next_buf = _hash_getbuf_with_strategy(rel, blkno, HASH_WRITE,
- LH_OVERFLOW_PAGE,
- bstrategy);
+ next_buf = _hash_getbuf(rel, blkno, HASH_WRITE,
+ LH_OVERFLOW_PAGE);
/*
* release the lock on previous page after acquiring the lock on next
@@ -1004,8 +1002,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf,
* ordering of tuples for a scan that has started before it.
*/
if (bucket_dirty && IsBufferCleanupOK(bucket_buf))
- _hash_squeezebucket(rel, cur_bucket, bucket_blkno, bucket_buf,
- bstrategy);
+ _hash_squeezebucket(rel, cur_bucket, bucket_blkno, bucket_buf);
else
LockBuffer(bucket_buf, BUFFER_LOCK_UNLOCK);
}
diff --git a/src/backend/access/hash/hashovfl.c b/src/backend/access/hash/hashovfl.c
index dbc57ef958c0d..5b35fed33f9e1 100644
--- a/src/backend/access/hash/hashovfl.c
+++ b/src/backend/access/hash/hashovfl.c
@@ -491,8 +491,7 @@ _hash_firstfreebit(uint32 map)
BlockNumber
_hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets,
- Size *tups_size, uint16 nitups,
- BufferAccessStrategy bstrategy)
+ Size *tups_size, uint16 nitups)
{
HashMetaPage metap;
Buffer metabuf;
@@ -539,20 +538,16 @@ _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
if (prevblkno == writeblkno)
prevbuf = wbuf;
else
- prevbuf = _hash_getbuf_with_strategy(rel,
- prevblkno,
- HASH_WRITE,
- LH_BUCKET_PAGE | LH_OVERFLOW_PAGE,
- bstrategy);
+ prevbuf = _hash_getbuf(rel,
+ prevblkno,
+ HASH_WRITE,
+ LH_BUCKET_PAGE | LH_OVERFLOW_PAGE);
}
if (BlockNumberIsValid(nextblkno))
- nextbuf = _hash_getbuf_with_strategy(rel,
- nextblkno,
- HASH_WRITE,
- LH_OVERFLOW_PAGE,
- bstrategy);
-
- /* Note: bstrategy is intentionally not used for metapage and bitmap */
+ nextbuf = _hash_getbuf(rel,
+ nextblkno,
+ HASH_WRITE,
+ LH_OVERFLOW_PAGE);
/* Read the metapage so we can determine which bitmap page to use */
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ, LH_META_PAGE);
@@ -843,8 +838,7 @@ void
_hash_squeezebucket(Relation rel,
Bucket bucket,
BlockNumber bucket_blkno,
- Buffer bucket_buf,
- BufferAccessStrategy bstrategy)
+ Buffer bucket_buf)
{
BlockNumber wblkno;
BlockNumber rblkno;
@@ -886,11 +880,10 @@ _hash_squeezebucket(Relation rel,
rblkno = ropaque->hasho_nextblkno;
if (rbuf != InvalidBuffer)
_hash_relbuf(rel, rbuf);
- rbuf = _hash_getbuf_with_strategy(rel,
- rblkno,
- HASH_WRITE,
- LH_OVERFLOW_PAGE,
- bstrategy);
+ rbuf = _hash_getbuf(rel,
+ rblkno,
+ HASH_WRITE,
+ LH_OVERFLOW_PAGE);
rpage = BufferGetPage(rbuf);
ropaque = HashPageGetOpaque(rpage);
Assert(ropaque->hasho_bucket == bucket);
@@ -952,11 +945,10 @@ _hash_squeezebucket(Relation rel,
/* don't need to move to next page if we reached the read page */
if (wblkno != rblkno)
- next_wbuf = _hash_getbuf_with_strategy(rel,
- wblkno,
- HASH_WRITE,
- LH_OVERFLOW_PAGE,
- bstrategy);
+ next_wbuf = _hash_getbuf(rel,
+ wblkno,
+ HASH_WRITE,
+ LH_OVERFLOW_PAGE);
if (nitups > 0)
{
@@ -1098,7 +1090,7 @@ _hash_squeezebucket(Relation rel,
/* free this overflow page (releases rbuf) */
_hash_freeovflpage(rel, bucket_buf, rbuf, wbuf, itups, itup_offsets,
- tups_size, nitups, bstrategy);
+ tups_size, nitups);
/* be tidy */
for (i = 0; i < nitups; i++)
@@ -1115,11 +1107,10 @@ _hash_squeezebucket(Relation rel,
return;
}
- rbuf = _hash_getbuf_with_strategy(rel,
- rblkno,
- HASH_WRITE,
- LH_OVERFLOW_PAGE,
- bstrategy);
+ rbuf = _hash_getbuf(rel,
+ rblkno,
+ HASH_WRITE,
+ LH_OVERFLOW_PAGE);
rpage = BufferGetPage(rbuf);
ropaque = HashPageGetOpaque(rpage);
Assert(ropaque->hasho_bucket == bucket);
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 8099b0d021f05..bdf1a255f1fbf 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -139,8 +139,7 @@ _hash_getinitbuf(Relation rel, BlockNumber blkno)
if (blkno == P_NEW)
elog(ERROR, "hash AM does not use P_NEW");
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK,
- NULL);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK);
/* ref count and lock type are correct */
@@ -209,7 +208,7 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
/* smgr insists we explicitly extend the relation */
if (blkno == nblocks)
{
- buf = ExtendBufferedRel(BMR_REL(rel), forkNum, NULL,
+ buf = ExtendBufferedRel(BMR_REL(rel), forkNum,
EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
if (BufferGetBlockNumber(buf) != blkno)
elog(ERROR, "unexpected hash relation size: %u, should be %u",
@@ -217,8 +216,7 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
}
else
{
- buf = ReadBufferExtended(rel, forkNum, blkno, RBM_ZERO_AND_LOCK,
- NULL);
+ buf = ReadBufferExtended(rel, forkNum, blkno, RBM_ZERO_AND_LOCK);
}
/* ref count and lock type are correct */
@@ -229,34 +227,6 @@ _hash_getnewbuf(Relation rel, BlockNumber blkno, ForkNumber forkNum)
return buf;
}
-/*
- * _hash_getbuf_with_strategy() -- Get a buffer with nondefault strategy.
- *
- * This is identical to _hash_getbuf() but also allows a buffer access
- * strategy to be specified. We use this for VACUUM operations.
- */
-Buffer
-_hash_getbuf_with_strategy(Relation rel, BlockNumber blkno,
- int access, int flags,
- BufferAccessStrategy bstrategy)
-{
- Buffer buf;
-
- if (blkno == P_NEW)
- elog(ERROR, "hash AM does not use P_NEW");
-
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
-
- if (access != HASH_NOLOCK)
- LockBuffer(buf, access);
-
- /* ref count and lock type are correct */
-
- _hash_checkpage(rel, buf, flags);
-
- return buf;
-}
-
/*
* _hash_relbuf() -- release a locked buffer.
*
@@ -758,7 +728,7 @@ _hash_expandtable(Relation rel, Buffer metabuf)
/* Release the metapage lock. */
LockBuffer(metabuf, BUFFER_LOCK_UNLOCK);
- hashbucketcleanup(rel, old_bucket, buf_oblkno, start_oblkno, NULL,
+ hashbucketcleanup(rel, old_bucket, buf_oblkno, start_oblkno,
maxbucket, highmask, lowmask, NULL, NULL, true,
NULL, NULL);
@@ -1333,7 +1303,7 @@ _hash_splitbucket(Relation rel,
{
LockBuffer(bucket_nbuf, BUFFER_LOCK_UNLOCK);
hashbucketcleanup(rel, obucket, bucket_obuf,
- BufferGetBlockNumber(bucket_obuf), NULL,
+ BufferGetBlockNumber(bucket_obuf),
maxbucket, highmask, lowmask, NULL, NULL, true,
NULL, NULL);
}
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 9cdc221675b2d..48e7c421bf497 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -359,7 +359,6 @@ static void
initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
{
ParallelBlockTableScanDesc bpscan = NULL;
- bool allow_strat;
bool allow_sync;
/*
@@ -396,24 +395,10 @@ initscan(HeapScanDesc scan, ScanKey key, bool keep_startblock)
if (!RelationUsesLocalBuffers(scan->rs_base.rs_rd) &&
scan->rs_nblocks > NBuffers / 4)
{
- allow_strat = (scan->rs_base.rs_flags & SO_ALLOW_STRAT) != 0;
allow_sync = (scan->rs_base.rs_flags & SO_ALLOW_SYNC) != 0;
}
else
- allow_strat = allow_sync = false;
-
- if (allow_strat)
- {
- /* During a rescan, keep the previous strategy object. */
- 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;
- }
+ allow_sync = false;
if (scan->rs_base.rs_parallel != NULL)
{
@@ -1202,7 +1187,6 @@ heap_beginscan(Relation relation, Snapshot snapshot,
scan->rs_base.rs_flags = flags;
scan->rs_base.rs_parallel = parallel_scan;
scan->rs_base.rs_instrument = NULL;
- scan->rs_strategy = NULL; /* set in initscan */
scan->rs_cbuf = InvalidBuffer;
/*
@@ -1273,8 +1257,7 @@ heap_beginscan(Relation relation, Snapshot snapshot,
/*
* Set up a read stream for sequential scans and TID range scans. This
- * should be done after initscan() because initscan() allocates the
- * BufferAccessStrategy object passed to the read stream API.
+ * should be done after initscan().
*/
if (scan->rs_base.rs_flags & SO_TYPE_SEQSCAN ||
scan->rs_base.rs_flags & SO_TYPE_TIDRANGESCAN)
@@ -1295,7 +1278,6 @@ heap_beginscan(Relation relation, Snapshot snapshot,
*/
scan->rs_read_stream = read_stream_begin_relation(READ_STREAM_SEQUENTIAL |
READ_STREAM_USE_BATCHING,
- scan->rs_strategy,
scan->rs_base.rs_rd,
MAIN_FORKNUM,
cb,
@@ -1306,7 +1288,6 @@ heap_beginscan(Relation relation, Snapshot snapshot,
{
scan->rs_read_stream = read_stream_begin_relation(READ_STREAM_DEFAULT |
READ_STREAM_USE_BATCHING,
- scan->rs_strategy,
scan->rs_base.rs_rd,
MAIN_FORKNUM,
bitmapheap_stream_read_next,
@@ -1402,9 +1383,6 @@ heap_endscan(TableScanDesc sscan)
if (BufferIsValid(scan->rs_vmbuffer))
ReleaseBuffer(scan->rs_vmbuffer);
- /*
- * Must free the read stream before freeing the BufferAccessStrategy.
- */
if (scan->rs_read_stream)
read_stream_end(scan->rs_read_stream);
@@ -1416,9 +1394,6 @@ heap_endscan(TableScanDesc sscan)
if (scan->rs_base.rs_key)
pfree(scan->rs_base.rs_key);
- if (scan->rs_strategy != NULL)
- FreeAccessStrategy(scan->rs_strategy);
-
if (scan->rs_parallelworkerdata != NULL)
pfree(scan->rs_parallelworkerdata);
@@ -1939,7 +1914,6 @@ GetBulkInsertState(void)
BulkInsertState bistate;
bistate = (BulkInsertState) palloc_object(BulkInsertStateData);
- bistate->strategy = GetAccessStrategy(BAS_BULKWRITE);
bistate->current_buf = InvalidBuffer;
bistate->next_free = InvalidBlockNumber;
bistate->last_free = InvalidBlockNumber;
@@ -1955,7 +1929,6 @@ FreeBulkInsertState(BulkInsertState bistate)
{
if (bistate->current_buf != InvalidBuffer)
ReleaseBuffer(bistate->current_buf);
- FreeAccessStrategy(bistate->strategy);
pfree(bistate);
}
diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c
index bf87430cf0176..d14658d7218d4 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -2213,9 +2213,9 @@ heapam_scan_sample_next_block(TableScanDesc scan, SampleScanState *scanstate)
*/
CHECK_FOR_INTERRUPTS();
- /* Read page using selected strategy */
+ /* Read page */
hscan->rs_cbuf = ReadBufferExtended(hscan->rs_base.rs_rd, MAIN_FORKNUM,
- blockno, RBM_NORMAL, hscan->rs_strategy);
+ blockno, RBM_NORMAL);
/* in pagemode, prune the page and determine visible tuple offsets */
if (hscan->rs_base.rs_flags & SO_ALLOW_PAGEMODE)
diff --git a/src/backend/access/heap/hio.c b/src/backend/access/heap/hio.c
index e96e0f77d9264..9bf7abc247f97 100644
--- a/src/backend/access/heap/hio.c
+++ b/src/backend/access/heap/hio.c
@@ -80,7 +80,8 @@ RelationPutHeapTuple(Relation relation,
}
/*
- * Read in a buffer in mode, using bulk-insert strategy if bistate isn't NULL.
+ * Read in a buffer in mode, using the bistate's pinned target page if
+ * available.
*/
static Buffer
ReadBufferBI(Relation relation, BlockNumber targetBlock,
@@ -91,7 +92,7 @@ ReadBufferBI(Relation relation, BlockNumber targetBlock,
/* If not bulk-insert, exactly like ReadBuffer */
if (!bistate)
return ReadBufferExtended(relation, MAIN_FORKNUM, targetBlock,
- mode, NULL);
+ mode);
/* If we have the desired block already pinned, re-pin and return it */
if (bistate->current_buf != InvalidBuffer)
@@ -113,9 +114,9 @@ ReadBufferBI(Relation relation, BlockNumber targetBlock,
bistate->current_buf = InvalidBuffer;
}
- /* Perform a read using the buffer strategy */
+ /* Perform the read */
buffer = ReadBufferExtended(relation, MAIN_FORKNUM, targetBlock,
- mode, bistate->strategy);
+ mode);
/* Save the selected block as target for future inserts */
IncrBufferRefCount(buffer);
@@ -337,7 +338,6 @@ RelationAddBlocks(Relation relation, BulkInsertState bistate,
* way larger.
*/
first_block = ExtendBufferedRelBy(BMR_REL(relation), MAIN_FORKNUM,
- bistate ? bistate->strategy : NULL,
EB_LOCK_FIRST,
extend_by_pages,
victim_buffers,
@@ -484,8 +484,7 @@ RelationAddBlocks(Relation relation, BulkInsertState bistate,
*
* The caller can also provide a BulkInsertState object to optimize many
* insertions into the same relation. This keeps a pin on the current
- * insertion target page (to save pin/unpin cycles) and also passes a
- * BULKWRITE buffer selection strategy object to the buffer manager.
+ * insertion target page (to save pin/unpin cycles).
* Passing NULL for bistate selects the default behavior.
*
* We don't fill existing pages further than the fillfactor, except for large
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 39395aed0d592..8bc8e470af39f 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -257,7 +257,6 @@ typedef struct LVRelState
int nindexes;
/* Buffer access strategy and parallel vacuum state */
- BufferAccessStrategy bstrategy;
ParallelVacuumState *pvs;
/* Aggressive VACUUM? (must set relfrozenxid >= FreezeLimit) */
@@ -621,8 +620,7 @@ heap_vacuum_eager_scan_setup(LVRelState *vacrel, const VacuumParams *params)
* and locked the relation.
*/
void
-heap_vacuum_rel(Relation rel, const VacuumParams *params,
- BufferAccessStrategy bstrategy)
+heap_vacuum_rel(Relation rel, const VacuumParams *params)
{
LVRelState *vacrel;
bool verbose,
@@ -699,7 +697,6 @@ heap_vacuum_rel(Relation rel, const VacuumParams *params,
vacrel->rel = rel;
vac_open_indexes(vacrel->rel, RowExclusiveLock, &vacrel->nindexes,
&vacrel->indrels);
- vacrel->bstrategy = bstrategy;
if (instrument && vacrel->nindexes > 0)
{
/* Copy index names used by instrumentation (not error reporting) */
@@ -1311,7 +1308,6 @@ lazy_scan_heap(LVRelState *vacrel)
* explicit work in heap_vac_scan_next_block.
*/
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE,
- vacrel->bstrategy,
vacrel->rel,
MAIN_FORKNUM,
heap_vac_scan_next_block,
@@ -2670,7 +2666,6 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
*/
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_USE_BATCHING,
- vacrel->bstrategy,
vacrel->rel,
MAIN_FORKNUM,
vacuum_reap_lp_read_stream_next,
@@ -2904,13 +2899,6 @@ lazy_check_wraparound_failsafe(LVRelState *vacrel)
VacuumFailsafeActive = true;
- /*
- * Abandon use of a buffer access strategy to allow use of all of
- * shared buffers. We assume the caller who allocated the memory for
- * the BufferAccessStrategy will free it.
- */
- vacrel->bstrategy = NULL;
-
/* Disable index vacuuming, index cleanup, and heap rel truncation */
vacrel->do_index_vacuuming = false;
vacrel->do_index_cleanup = false;
@@ -3023,7 +3011,6 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
ivinfo.estimated_count = true;
ivinfo.message_level = DEBUG2;
ivinfo.num_heap_tuples = reltuples;
- ivinfo.strategy = vacrel->bstrategy;
/*
* Update error traceback information.
@@ -3074,7 +3061,6 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
ivinfo.message_level = DEBUG2;
ivinfo.num_heap_tuples = reltuples;
- ivinfo.strategy = vacrel->bstrategy;
/*
* Update error traceback information.
@@ -3354,8 +3340,7 @@ count_nondeletable_pages(LVRelState *vacrel, bool *lock_waiter_detected)
prefetchedUntil = prefetchStart;
}
- buf = ReadBufferExtended(vacrel->rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
- vacrel->bstrategy);
+ buf = ReadBufferExtended(vacrel->rel, MAIN_FORKNUM, blkno, RBM_NORMAL);
/* In this phase we only need shared access to the buffer */
LockBuffer(buf, BUFFER_LOCK_SHARE);
@@ -3446,8 +3431,7 @@ dead_items_alloc(LVRelState *vacrel, int nworkers)
vacrel->pvs = parallel_vacuum_init(vacrel->rel, vacrel->indrels,
vacrel->nindexes, nworkers,
vac_work_mem,
- vacrel->verbose ? INFO : DEBUG2,
- vacrel->bstrategy);
+ vacrel->verbose ? INFO : DEBUG2);
/*
* If parallel mode started, dead_items and dead_items_info spaces are
diff --git a/src/backend/access/heap/visibilitymap.c b/src/backend/access/heap/visibilitymap.c
index 4fd470702aae7..b2612b1f71063 100644
--- a/src/backend/access/heap/visibilitymap.c
+++ b/src/backend/access/heap/visibilitymap.c
@@ -575,7 +575,7 @@ vm_readbuf(Relation rel, BlockNumber blkno, bool extend)
}
else
buf = ReadBufferExtended(rel, VISIBILITYMAP_FORKNUM, blkno,
- RBM_ZERO_ON_ERROR, NULL);
+ RBM_ZERO_ON_ERROR);
/*
* Initializing the page when needed is trickier than it looks, because of
@@ -611,7 +611,7 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
{
Buffer buf;
- buf = ExtendBufferedRelTo(BMR_REL(rel), VISIBILITYMAP_FORKNUM, NULL,
+ buf = ExtendBufferedRelTo(BMR_REL(rel), VISIBILITYMAP_FORKNUM,
EB_CREATE_FORK_IF_NEEDED |
EB_CLEAR_SIZE_CACHE,
vm_nblocks,
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 109017d6b5296..7b5fc16d75c46 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -960,7 +960,7 @@ _bt_allocbuf(Relation rel, Relation heaprel)
* otherwise would make, as we can't use _bt_lockbuf() without introducing
* a race.
*/
- buf = ExtendBufferedRel(BMR_REL(rel), MAIN_FORKNUM, NULL, EB_LOCK_FIRST);
+ buf = ExtendBufferedRel(BMR_REL(rel), MAIN_FORKNUM, EB_LOCK_FIRST);
if (!RelationUsesLocalBuffers(rel))
VALGRIND_MAKE_MEM_DEFINED(BufferGetPage(buf), BLCKSZ);
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 3df2c752eadef..379a2d37def59 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -1324,7 +1324,6 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- info->strategy,
rel,
MAIN_FORKNUM,
block_range_read_stream_cb,
@@ -1730,8 +1729,7 @@ btvacuumpage(BTVacState *vstate, Buffer buf)
* recycle all-zero pages, not fail. Also, we want to use a
* nondefault buffer access strategy.
*/
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
- info->strategy);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL);
goto backtrack;
}
diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c
index f2ee333f60d84..785e385aab635 100644
--- a/src/backend/access/spgist/spgutils.c
+++ b/src/backend/access/spgist/spgutils.c
@@ -432,7 +432,7 @@ SpGistNewBuffer(Relation index)
ReleaseBuffer(buffer);
}
- buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM, NULL,
+ buffer = ExtendBufferedRel(BMR_REL(index), MAIN_FORKNUM,
EB_LOCK_FIRST);
return buffer;
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index c461f8dc02d1b..9f644edaf8242 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -704,8 +704,7 @@ spgprocesspending(spgBulkDeleteState *bds)
/* examine the referenced page */
blkno = ItemPointerGetBlockNumber(&pitem->tid);
- buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno,
- RBM_NORMAL, bds->info->strategy);
+ buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno, RBM_NORMAL);
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
page = BufferGetPage(buffer);
@@ -830,7 +829,6 @@ spgvacuumscan(spgBulkDeleteState *bds)
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- bds->info->strategy,
index,
MAIN_FORKNUM,
block_range_read_stream_cb,
diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c
index f2e10b82b7d3e..0c16b7fef0f4a 100644
--- a/src/backend/access/transam/xloginsert.c
+++ b/src/backend/access/transam/xloginsert.c
@@ -1348,7 +1348,7 @@ log_newpage_range(Relation rel, ForkNumber forknum,
while (nbufs < XLR_MAX_BLOCK_ID && blkno < endblk)
{
Buffer buf = ReadBufferExtended(rel, forknum, blkno,
- RBM_NORMAL, NULL);
+ RBM_NORMAL);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index d8c179c5dccb2..e5be49f8b5db9 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -519,7 +519,7 @@ XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum,
{
/* page exists in file */
buffer = ReadBufferWithoutRelcache(rlocator, forknum, blkno,
- mode, NULL, true);
+ mode, true);
}
else
{
@@ -536,7 +536,6 @@ XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum,
Assert(InRecovery);
buffer = ExtendBufferedRelTo(BMR_SMGR(smgr, RELPERSISTENCE_PERMANENT),
forknum,
- NULL,
EB_PERFORMING_RECOVERY |
EB_SKIP_EXTENSION_LOCK,
blkno + 1,
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 81bba4beac7cb..b0a7b8a33cd02 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -3431,7 +3431,6 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
ivinfo.estimated_count = true;
ivinfo.message_level = DEBUG2;
ivinfo.num_heap_tuples = heapRelation->rd_rel->reltuples;
- ivinfo.strategy = NULL;
/*
* Encode TIDs as int8 values for the sort, rather than directly sorting
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index f66e80b757cbf..9b117a53124c3 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -72,7 +72,6 @@ int default_statistics_target = 100;
/* A few variables that don't seem worth passing around as parameters */
static MemoryContext anl_context = NULL;
-static BufferAccessStrategy vac_strategy;
static void do_analyze_rel(Relation onerel,
@@ -108,8 +107,7 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
*/
void
analyze_rel(Oid relid, RangeVar *relation,
- const VacuumParams *params, List *va_cols, bool in_outer_xact,
- BufferAccessStrategy bstrategy)
+ const VacuumParams *params, List *va_cols, bool in_outer_xact)
{
Relation onerel;
int elevel;
@@ -124,7 +122,6 @@ analyze_rel(Oid relid, RangeVar *relation,
elevel = DEBUG2;
/* Set up static variables */
- vac_strategy = bstrategy;
/*
* Check for user-requested abort.
@@ -730,7 +727,6 @@ do_analyze_rel(Relation onerel, const VacuumParams *params,
ivinfo.estimated_count = true;
ivinfo.message_level = elevel;
ivinfo.num_heap_tuples = onerel->rd_rel->reltuples;
- ivinfo.strategy = vac_strategy;
stats = index_vacuum_cleanup(&ivinfo, NULL);
@@ -1302,7 +1298,6 @@ acquire_sample_rows(Relation onerel, int elevel,
*/
stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
READ_STREAM_USE_BATCHING,
- vac_strategy,
scan->rs_rd,
MAIN_FORKNUM,
block_sampling_read_stream_next,
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index f0819d15ab701..6f65d48b6bd5a 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -262,7 +262,6 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
LockRelId relid;
Snapshot snapshot;
SMgrRelation smgr;
- BufferAccessStrategy bstrategy;
/* Get pg_class relfilenumber. */
relfilenumber = RelationMapOidToFilenumberForDatabase(srcpath,
@@ -282,9 +281,6 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
nblocks = smgrnblocks(smgr, MAIN_FORKNUM);
smgrclose(smgr);
- /* Use a buffer access strategy since this is a bulk read operation. */
- bstrategy = GetAccessStrategy(BAS_BULKREAD);
-
/*
* As explained in the function header comments, we need a snapshot that
* will see all committed transactions as committed, and our transaction
@@ -299,7 +295,7 @@ ScanSourceDatabasePgClass(Oid tbid, Oid dbid, char *srcpath)
CHECK_FOR_INTERRUPTS();
buf = ReadBufferWithoutRelcache(rlocator, MAIN_FORKNUM, blkno,
- RBM_NORMAL, bstrategy, true);
+ RBM_NORMAL, true);
LockBuffer(buf, BUFFER_LOCK_SHARE);
page = BufferGetPage(buf);
diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 02883fe34a485..d8c15a8b1bcad 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -2447,7 +2447,7 @@ process_single_relation(RepackStmt *stmt, LOCKMODE lockmode, bool isTopLevel,
if (params->options & CLUOPT_VERBOSE)
vac_params.options |= VACOPT_VERBOSE;
analyze_rel(tableOid, NULL, &vac_params,
- stmt->relation->va_cols, true, NULL);
+ stmt->relation->va_cols, true);
PopActiveSnapshot();
CommandCounterIncrement();
}
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 551667650ba63..ac1ab9482114f 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -358,7 +358,7 @@ fill_seq_fork_with_data(Relation rel, HeapTuple tuple, ForkNumber forkNum)
/* Initialize first page of relation with special magic number */
- buf = ExtendBufferedRel(BMR_REL(rel), forkNum, NULL,
+ buf = ExtendBufferedRel(BMR_REL(rel), forkNum,
EB_LOCK_FIRST | EB_SKIP_EXTENSION_LOCK);
Assert(BufferGetBlockNumber(buf) == 0);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 38539a6fd3d4e..66acd27bd488d 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -127,32 +127,11 @@ static void vac_truncate_clog(TransactionId frozenXID,
TransactionId lastSaneFrozenXid,
MultiXactId lastSaneMinMulti);
static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
- BufferAccessStrategy bstrategy, bool isTopLevel);
+ bool isTopLevel);
static double compute_parallel_delay(void);
static VacOptValue get_vacoptval_from_boolean(DefElem *def);
static bool vac_tid_reaped(ItemPointer itemptr, void *state);
-/*
- * GUC check function to ensure GUC value specified is within the allowable
- * range.
- */
-bool
-check_vacuum_buffer_usage_limit(int *newval, void **extra,
- GucSource source)
-{
- /* Value upper and lower hard limits are inclusive */
- if (*newval == 0 || (*newval >= MIN_BAS_VAC_RING_SIZE_KB &&
- *newval <= MAX_BAS_VAC_RING_SIZE_KB))
- return true;
-
- /* Value does not fall within any allowable range */
- GUC_check_errdetail("\"%s\" must be 0 or between %d kB and %d kB.",
- "vacuum_buffer_usage_limit",
- MIN_BAS_VAC_RING_SIZE_KB, MAX_BAS_VAC_RING_SIZE_KB);
-
- return false;
-}
-
/*
* Primary entry point for manual VACUUM and ANALYZE commands
*
@@ -163,7 +142,6 @@ void
ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
{
VacuumParams params;
- BufferAccessStrategy bstrategy = NULL;
bool verbose = false;
bool skip_locked = false;
bool analyze = false;
@@ -172,7 +150,6 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
bool disable_page_skipping = false;
bool process_main = true;
bool process_toast = true;
- int ring_size;
bool skip_database_stats = false;
bool only_database_stats = false;
MemoryContext vac_context;
@@ -188,12 +165,6 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
/* Will be set later if we recurse to a TOAST table. */
params.toast_parent = InvalidOid;
- /*
- * Set this to an invalid value so it is clear whether or not a
- * BUFFER_USAGE_LIMIT was specified when making the access strategy.
- */
- ring_size = -1;
-
/* Parse options list */
foreach(lc, vacstmt->options)
{
@@ -204,32 +175,6 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
verbose = defGetBoolean(opt);
else if (strcmp(opt->defname, "skip_locked") == 0)
skip_locked = defGetBoolean(opt);
- else if (strcmp(opt->defname, "buffer_usage_limit") == 0)
- {
- const char *hintmsg;
- int result;
- char *vac_buffer_size;
-
- vac_buffer_size = defGetString(opt);
-
- /*
- * Check that the specified value is valid and the size falls
- * within the hard upper and lower limits if it is not 0.
- */
- if (!parse_int(vac_buffer_size, &result, GUC_UNIT_KB, &hintmsg) ||
- (result != 0 &&
- (result < MIN_BAS_VAC_RING_SIZE_KB || result > MAX_BAS_VAC_RING_SIZE_KB)))
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("%s option must be 0 or between %d kB and %d kB",
- "BUFFER_USAGE_LIMIT",
- MIN_BAS_VAC_RING_SIZE_KB, MAX_BAS_VAC_RING_SIZE_KB),
- hintmsg ? errhint_internal("%s", _(hintmsg)) : 0));
- }
-
- ring_size = result;
- }
else if (!vacstmt->is_vacuumcmd)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
@@ -325,17 +270,6 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("VACUUM FULL cannot be performed in parallel")));
- /*
- * BUFFER_USAGE_LIMIT does nothing for VACUUM (FULL) so just raise an
- * ERROR for that case. VACUUM (FULL, ANALYZE) does make use of it, so
- * we'll permit that.
- */
- if (ring_size != -1 && (params.options & VACOPT_FULL) &&
- !(params.options & VACOPT_ANALYZE))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("BUFFER_USAGE_LIMIT cannot be specified for VACUUM FULL")));
-
/*
* Make sure VACOPT_ANALYZE is specified if any column lists are present.
*/
@@ -431,38 +365,8 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
"Vacuum",
ALLOCSET_DEFAULT_SIZES);
- /*
- * Make a buffer strategy object in the cross-transaction memory context.
- * We needn't bother making this for VACUUM (FULL) or VACUUM
- * (ONLY_DATABASE_STATS) as they'll not make use of it. VACUUM (FULL,
- * ANALYZE) is possible, so we'd better ensure that we make a strategy
- * when we see ANALYZE.
- */
- if ((params.options & (VACOPT_ONLY_DATABASE_STATS |
- VACOPT_FULL)) == 0 ||
- (params.options & VACOPT_ANALYZE) != 0)
- {
-
- MemoryContext old_context = MemoryContextSwitchTo(vac_context);
-
- Assert(ring_size >= -1);
-
- /*
- * If BUFFER_USAGE_LIMIT was specified by the VACUUM or ANALYZE
- * command, it overrides the value of VacuumBufferUsageLimit. Either
- * value may be 0, in which case GetAccessStrategyWithSize() will
- * return NULL, effectively allowing full use of shared buffers.
- */
- if (ring_size == -1)
- ring_size = VacuumBufferUsageLimit;
-
- bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, ring_size);
-
- MemoryContextSwitchTo(old_context);
- }
-
/* Now go through the common routine */
- vacuum(vacstmt->rels, ¶ms, bstrategy, vac_context, isTopLevel);
+ vacuum(vacstmt->rels, ¶ms, vac_context, isTopLevel);
/* Finally, clean up the vacuum memory context */
MemoryContextDelete(vac_context);
@@ -479,19 +383,13 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
* params contains a set of parameters that can be used to customize the
* behavior.
*
- * bstrategy may be passed in as NULL when the caller does not want to
- * restrict the number of shared_buffers that VACUUM / ANALYZE can use,
- * otherwise, the caller must build a BufferAccessStrategy with the number of
- * shared_buffers that VACUUM / ANALYZE should try to limit themselves to
- * using.
- *
* isTopLevel should be passed down from ProcessUtility.
*
* It is the caller's responsibility that all parameters are allocated in a
* memory context that will not disappear at transaction commit.
*/
void
-vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrategy,
+vacuum(List *relations, const VacuumParams *params,
MemoryContext vac_context, bool isTopLevel)
{
static bool in_vacuum = false;
@@ -630,7 +528,7 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
if (params->options & VACOPT_VACUUM)
{
- if (!vacuum_rel(vrel->oid, vrel->relation, *params, bstrategy,
+ if (!vacuum_rel(vrel->oid, vrel->relation, *params,
isTopLevel))
continue;
}
@@ -649,7 +547,7 @@ vacuum(List *relations, const VacuumParams *params, BufferAccessStrategy bstrate
}
analyze_rel(vrel->oid, vrel->relation, params,
- vrel->va_cols, in_outer_xact, bstrategy);
+ vrel->va_cols, in_outer_xact);
if (use_own_xacts)
{
@@ -2010,7 +1908,7 @@ vac_truncate_clog(TransactionId frozenXID,
*/
static bool
vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
- BufferAccessStrategy bstrategy, bool isTopLevel)
+ bool isTopLevel)
{
LOCKMODE lmode;
Relation rel;
@@ -2307,7 +2205,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
rel = NULL;
}
else
- table_relation_vacuum(rel, ¶ms, bstrategy);
+ table_relation_vacuum(rel, ¶ms);
}
/* Roll back any GUC changes executed by index functions */
@@ -2344,7 +2242,7 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params,
toast_vacuum_params.options |= VACOPT_PROCESS_MAIN;
toast_vacuum_params.toast_parent = relid;
- vacuum_rel(toast_relid, NULL, toast_vacuum_params, bstrategy,
+ vacuum_rel(toast_relid, NULL, toast_vacuum_params,
isTopLevel);
}
diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c
index 41cefcfde54fe..8b4b835db9bad 100644
--- a/src/backend/commands/vacuumparallel.c
+++ b/src/backend/commands/vacuumparallel.c
@@ -125,12 +125,6 @@ typedef struct PVShared
*/
int maintenance_work_mem_worker;
- /*
- * The number of buffers each worker's Buffer Access Strategy ring should
- * contain.
- */
- int ring_nbuffers;
-
/*
* Shared vacuum cost balance. During parallel vacuum,
* VacuumSharedCostBalance points to this value and it accumulates the
@@ -257,9 +251,6 @@ struct ParallelVacuumState
int nindexes_parallel_cleanup;
int nindexes_parallel_condcleanup;
- /* Buffer access strategy used by leader process */
- BufferAccessStrategy bstrategy;
-
/*
* Error reporting state. The error callback is set only for workers
* processes during parallel index vacuum.
@@ -304,7 +295,7 @@ static void parallel_vacuum_dsm_detach(dsm_segment *seg, Datum arg);
ParallelVacuumState *
parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes,
int nrequested_workers, int vac_work_mem,
- int elevel, BufferAccessStrategy bstrategy)
+ int elevel)
{
ParallelVacuumState *pvs;
ParallelContext *pcxt;
@@ -345,7 +336,6 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes,
pvs->indrels = indrels;
pvs->nindexes = nindexes;
pvs->will_parallel_vacuum = will_parallel_vacuum;
- pvs->bstrategy = bstrategy;
pvs->heaprel = rel;
EnterParallelMode();
@@ -447,9 +437,6 @@ parallel_vacuum_init(Relation rel, Relation *indrels, int nindexes,
shared->dead_items_handle = TidStoreGetHandle(dead_items);
shared->dead_items_dsa_handle = dsa_get_handle(TidStoreGetDSA(dead_items));
- /* Use the same buffer size for all workers */
- shared->ring_nbuffers = GetAccessStrategyBufferCount(bstrategy);
-
pg_atomic_init_u32(&(shared->cost_balance), 0);
pg_atomic_init_u32(&(shared->active_nworkers), 0);
pg_atomic_init_u32(&(shared->idx), 0);
@@ -1091,7 +1078,6 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel,
ivinfo.message_level = DEBUG2;
ivinfo.estimated_count = pvs->shared->estimated_count;
ivinfo.num_heap_tuples = pvs->shared->reltuples;
- ivinfo.strategy = pvs->bstrategy;
/* Update error traceback information */
pvs->indname = pstrdup(RelationGetRelationName(indrel));
@@ -1294,10 +1280,6 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
pvs.indname = NULL;
pvs.status = PARALLEL_INDVAC_STATUS_INITIAL;
- /* Each parallel VACUUM worker gets its own access strategy. */
- pvs.bstrategy = GetAccessStrategyWithSize(BAS_VACUUM,
- shared->ring_nbuffers * (BLCKSZ / 1024));
-
/* Setup error traceback support for ereport() */
errcallback.callback = parallel_vacuum_error_callback;
errcallback.arg = &pvs;
@@ -1328,7 +1310,6 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
vac_close_indexes(nindexes, indrels, RowExclusiveLock);
table_close(rel, ShareUpdateExclusiveLock);
- FreeAccessStrategy(pvs.bstrategy);
if (shared->is_autovacuum)
pv_shared_cost_params = NULL;
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 45abf48768afd..e021e798805ab 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -386,8 +386,7 @@ static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
bool *dovacuum, bool *doanalyze, bool *wraparound,
AutoVacuumScores *scores);
-static void autovacuum_do_vac_analyze(autovac_table *tab,
- BufferAccessStrategy bstrategy);
+static void autovacuum_do_vac_analyze(autovac_table *tab);
static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
TupleDesc pg_class_desc);
static void perform_work_item(AutoVacuumWorkItem *workitem);
@@ -1936,7 +1935,6 @@ do_autovacuum(void)
HASHCTL ctl;
HTAB *table_toast_map;
ListCell *volatile cell;
- BufferAccessStrategy bstrategy;
ScanKeyData key;
TupleDesc pg_class_desc;
int effective_multixact_freeze_max_age;
@@ -2322,23 +2320,6 @@ do_autovacuum(void)
autovacuum_analyze_score_weight != 0.0)
list_sort(tables_to_process, TableToProcessComparator);
- /*
- * Optionally, create a buffer access strategy object for VACUUM to use.
- * We use the same BufferAccessStrategy object for all tables VACUUMed by
- * this worker to prevent autovacuum from blowing out shared buffers.
- *
- * VacuumBufferUsageLimit being set to 0 results in
- * GetAccessStrategyWithSize returning NULL, effectively meaning we can
- * use up to all of shared buffers.
- *
- * If we later enter failsafe mode on any of the tables being vacuumed, we
- * will cease use of the BufferAccessStrategy only for that table.
- *
- * XXX should we consider adding code to adjust the size of this if
- * VacuumBufferUsageLimit changes?
- */
- bstrategy = GetAccessStrategyWithSize(BAS_VACUUM, VacuumBufferUsageLimit);
-
/*
* create a memory context to act as fake PortalContext, so that the
* contexts created in the vacuum code are cleaned up for each table.
@@ -2516,7 +2497,7 @@ do_autovacuum(void)
MemoryContextSwitchTo(PortalContext);
/* have at it */
- autovacuum_do_vac_analyze(tab, bstrategy);
+ autovacuum_do_vac_analyze(tab);
/*
* Clear a possible query-cancel signal, to avoid a late reaction
@@ -2636,8 +2617,6 @@ do_autovacuum(void)
#ifdef USE_VALGRIND
hash_destroy(table_toast_map);
FreeTupleDesc(pg_class_desc);
- if (bstrategy)
- pfree(bstrategy);
#endif
/* Run the rest in xact context, mainly to avoid Valgrind leak warnings */
@@ -3348,7 +3327,7 @@ relation_needs_vacanalyze(Oid relid,
* disappear at transaction commit.
*/
static void
-autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
+autovacuum_do_vac_analyze(autovac_table *tab)
{
RangeVar *rangevar;
VacuumRelation *rel;
@@ -3371,7 +3350,7 @@ autovacuum_do_vac_analyze(autovac_table *tab, BufferAccessStrategy bstrategy)
rel_list = list_make1(rel);
MemoryContextSwitchTo(old_context);
- vacuum(rel_list, &tab->at_params, bstrategy, vac_context, true);
+ vacuum(rel_list, &tab->at_params, vac_context, true);
MemoryContextDelete(vac_context);
}
diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index 73dc539836b01..b6612f1e51794 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -390,7 +390,7 @@ static List *BuildRelationList(bool temp_relations, bool include_shared);
static void FreeDatabaseList(List *dblist);
static DataChecksumsWorkerResult ProcessDatabase(DataChecksumsWorkerDatabase *db);
static bool ProcessAllDatabases(void);
-static bool ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy);
+static bool ProcessSingleRelationFork(Relation reln, ForkNumber forkNum);
static void ResetDataChecksumsProgressCounters(void);
static void launcher_cancel_handler(SIGNAL_ARGS);
static void WaitForAllTransactionsToFinish(void);
@@ -687,7 +687,7 @@ StartDataChecksumsWorkerLauncher(DataChecksumsWorkerOperation op,
* error is raised in the lower levels.
*/
static bool
-ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrategy strategy)
+ProcessSingleRelationFork(Relation reln, ForkNumber forkNum)
{
BlockNumber numblocks = RelationGetNumberOfBlocksInFork(reln, forkNum);
char activity[NAMEDATALEN * 2 + 128];
@@ -722,7 +722,7 @@ ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrateg
*/
for (BlockNumber blknum = 0; blknum < numblocks; blknum++)
{
- Buffer buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL, strategy);
+ Buffer buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL);
/* Need to get an exclusive lock to mark the buffer as dirty */
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
@@ -808,7 +808,7 @@ ResetDataChecksumsProgressCounters(void)
* error is raised in the lower levels.
*/
static bool
-ProcessSingleRelationByOid(Oid relationId, BufferAccessStrategy strategy)
+ProcessSingleRelationByOid(Oid relationId)
{
Relation rel;
bool aborted = false;
@@ -835,7 +835,7 @@ ProcessSingleRelationByOid(Oid relationId, BufferAccessStrategy strategy)
{
if (smgrexists(rel->rd_smgr, fnum))
{
- if (!ProcessSingleRelationFork(rel, fnum, strategy))
+ if (!ProcessSingleRelationFork(rel, fnum))
{
aborted = true;
break;
@@ -1582,7 +1582,6 @@ DataChecksumsWorkerMain(Datum arg)
Oid dboid;
List *RelationList = NIL;
List *InitialTempTableList = NIL;
- BufferAccessStrategy strategy;
bool aborted = false;
int64 rels_done;
bool process_shared;
@@ -1650,11 +1649,6 @@ DataChecksumsWorkerMain(Datum arg)
VacuumUpdateCosts();
VacuumCostBalance = 0;
- /*
- * Create and set the vacuum strategy as our buffer strategy.
- */
- strategy = GetAccessStrategy(BAS_VACUUM);
-
RelationList = BuildRelationList(false, process_shared);
/* Update the total number of relations to be processed in this DB. */
@@ -1676,9 +1670,7 @@ DataChecksumsWorkerMain(Datum arg)
rels_done = 0;
foreach_oid(reloid, RelationList)
{
- bool costs_updated = false;
-
- if (!ProcessSingleRelationByOid(reloid, strategy))
+ if (!ProcessSingleRelationByOid(reloid))
{
aborted = true;
break;
@@ -1694,8 +1686,7 @@ DataChecksumsWorkerMain(Datum arg)
/*
* Check if the cost settings changed during runtime and if so, update
- * to reflect the new values and signal that the access strategy needs
- * to be refreshed.
+ * to reflect the new values.
*/
LWLockAcquire(DataChecksumsWorkerLock, LW_EXCLUSIVE);
if (DataChecksumState->worker_invocation != worker_invocation)
@@ -1706,7 +1697,6 @@ DataChecksumsWorkerMain(Datum arg)
if ((DataChecksumState->launch_cost_delay != DataChecksumState->cost_delay)
|| (DataChecksumState->launch_cost_limit != DataChecksumState->cost_limit))
{
- costs_updated = true;
VacuumCostDelay = DataChecksumState->launch_cost_delay;
VacuumCostLimit = DataChecksumState->launch_cost_limit;
VacuumUpdateCosts();
@@ -1714,19 +1704,10 @@ DataChecksumsWorkerMain(Datum arg)
DataChecksumState->cost_delay = DataChecksumState->launch_cost_delay;
DataChecksumState->cost_limit = DataChecksumState->launch_cost_limit;
}
- else
- costs_updated = false;
LWLockRelease(DataChecksumsWorkerLock);
-
- if (costs_updated)
- {
- FreeAccessStrategy(strategy);
- strategy = GetAccessStrategy(BAS_VACUUM);
- }
}
list_free(RelationList);
- FreeAccessStrategy(strategy);
if (aborted || abort_requested)
{
diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index a318539e56cbe..08d344f063d5d 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -757,7 +757,6 @@ read_stream_look_ahead(ReadStream *stream)
*/
static ReadStream *
read_stream_begin_impl(int flags,
- BufferAccessStrategy strategy,
Relation rel,
SMgrRelation smgr,
char persistence,
@@ -771,7 +770,6 @@ read_stream_begin_impl(int flags,
int16 queue_size;
int16 queue_overflow;
int max_ios;
- int strategy_pin_limit;
uint32 max_pinned_buffers;
uint32 max_possible_buffer_limit;
Oid tablespace_id;
@@ -835,10 +833,6 @@ read_stream_begin_impl(int flags,
max_pinned_buffers = Min(max_pinned_buffers,
PG_INT16_MAX - queue_overflow - 1);
- /* Give the strategy a chance to limit the number of buffers we pin. */
- strategy_pin_limit = GetAccessStrategyPinLimit(strategy);
- max_pinned_buffers = Min(strategy_pin_limit, max_pinned_buffers);
-
/*
* Also limit our queue to the maximum number of pins we could ever be
* allowed to acquire according to the buffer manager. We may not really
@@ -962,7 +956,6 @@ read_stream_begin_impl(int flags,
stream->ios[i].op.smgr = smgr;
stream->ios[i].op.persistence = persistence;
stream->ios[i].op.forknum = forknum;
- stream->ios[i].op.strategy = strategy;
}
return stream;
@@ -974,7 +967,6 @@ read_stream_begin_impl(int flags,
*/
ReadStream *
read_stream_begin_relation(int flags,
- BufferAccessStrategy strategy,
Relation rel,
ForkNumber forknum,
ReadStreamBlockNumberCB callback,
@@ -982,7 +974,6 @@ read_stream_begin_relation(int flags,
size_t per_buffer_data_size)
{
return read_stream_begin_impl(flags,
- strategy,
rel,
RelationGetSmgr(rel),
rel->rd_rel->relpersistence,
@@ -998,7 +989,6 @@ read_stream_begin_relation(int flags,
*/
ReadStream *
read_stream_begin_smgr_relation(int flags,
- BufferAccessStrategy strategy,
SMgrRelation smgr,
char smgr_persistence,
ForkNumber forknum,
@@ -1007,7 +997,6 @@ read_stream_begin_smgr_relation(int flags,
size_t per_buffer_data_size)
{
return read_stream_begin_impl(flags,
- strategy,
NULL,
smgr,
smgr_persistence,
@@ -1370,13 +1359,11 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
* Transitional support for code that would like to perform or skip reads
* itself, without using the stream. Returns, and consumes, the next block
* number that would be read by the stream's look-ahead algorithm, or
- * InvalidBlockNumber if the end of the stream is reached. Also reports the
- * strategy that would be used to read it.
+ * InvalidBlockNumber if the end of the stream is reached.
*/
BlockNumber
-read_stream_next_block(ReadStream *stream, BufferAccessStrategy *strategy)
+read_stream_next_block(ReadStream *stream)
{
- *strategy = stream->ios[0].op.strategy;
return read_stream_get_block(stream, NULL);
}
diff --git a/src/backend/storage/buffer/README b/src/backend/storage/buffer/README
index b332e002ba13b..58df6bd011aa1 100644
--- a/src/backend/storage/buffer/README
+++ b/src/backend/storage/buffer/README
@@ -203,50 +203,6 @@ have to give up and try another buffer. This however is not a concern
of the basic select-a-victim-buffer algorithm.)
-Buffer Ring Replacement Strategy
----------------------------------
-
-When running a query that needs to access a large number of pages just once,
-such as VACUUM or a large sequential scan, a different strategy is used.
-A page that has been touched only by such a scan is unlikely to be needed
-again soon, so instead of running the normal clock-sweep algorithm and
-blowing out the entire buffer cache, a small ring of buffers is allocated
-using the normal clock-sweep algorithm and those buffers are reused for the
-whole scan. This also implies that much of the write traffic caused by such
-a statement will be done by the backend itself and not pushed off onto other
-processes.
-
-For sequential scans, a 256KB ring is used. That's small enough to fit in L2
-cache, which makes transferring pages from OS cache to shared buffer cache
-efficient. Even less would often be enough, but the ring must be big enough
-to accommodate all pages in the scan that are pinned concurrently. 256KB
-should also be enough to leave a small cache trail for other backends to
-join in a synchronized seq scan. If a ring buffer is dirtied and its LSN
-updated, we would normally have to write and flush WAL before we could
-re-use the buffer; in this case we instead discard the buffer from the ring
-and (later) choose a replacement using the normal clock-sweep algorithm.
-Hence this strategy works best for scans that are read-only (or at worst
-update hint bits). In a scan that modifies every page in the scan, like a
-bulk UPDATE or DELETE, the buffers in the ring will always be dirtied and
-the ring strategy effectively degrades to the normal strategy.
-
-VACUUM uses a ring like sequential scans, however, the size of this ring is
-controlled by the vacuum_buffer_usage_limit GUC. Dirty pages are not removed
-from the ring. Instead, the WAL is flushed if needed to allow reuse of the
-buffers. Before introducing the buffer ring strategy in 8.3, VACUUM's buffers
-were sent to the freelist, which was effectively a buffer ring of 1 buffer,
-resulting in excessive WAL flushing.
-
-Bulk writes work similarly to VACUUM. Currently this applies only to
-COPY IN and CREATE TABLE AS SELECT. (Might it be interesting to make
-seqscan UPDATE and DELETE use the bulkwrite strategy?) For bulk writes
-we use a ring size of 16MB (but not more than 1/8th of shared_buffers).
-Smaller sizes have been shown to result in the COPY blocking too often
-for WAL flushes. While it's okay for a background vacuum to be slowed by
-doing its own WAL flushing, we'd prefer that COPY not be subject to that,
-so we let it use up a bit more of the buffer arena.
-
-
Background Writer's Processing
------------------------------
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 3908529872a31..cc2fab959df5b 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -83,6 +83,7 @@
/* Bits in SyncOneBuffer's return value */
#define BUF_WRITTEN 0x01
#define BUF_REUSABLE 0x02
+#define BUF_COOLED 0x04
#define RELS_BSEARCH_THRESHOLD 20
@@ -611,10 +612,9 @@ ForgetPrivateRefCountEntry(PrivateRefCountEntry *ref)
static Buffer ReadBuffer_common(Relation rel,
SMgrRelation smgr, char smgr_persistence,
ForkNumber forkNum, BlockNumber blockNum,
- ReadBufferMode mode, BufferAccessStrategy strategy);
+ ReadBufferMode mode);
static BlockNumber ExtendBufferedRelCommon(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
uint32 extend_by,
BlockNumber extend_upto,
@@ -622,19 +622,18 @@ static BlockNumber ExtendBufferedRelCommon(BufferManagerRelation bmr,
uint32 *extended_by);
static BlockNumber ExtendBufferedRelShared(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
uint32 extend_by,
BlockNumber extend_upto,
Buffer *buffers,
uint32 *extended_by);
-static bool PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
+static bool PinBuffer(BufferDesc *buf,
bool skip_if_not_valid);
static void PinBuffer_Locked(BufferDesc *buf);
static void UnpinBuffer(BufferDesc *buf);
static void UnpinBufferNoOwner(BufferDesc *buf);
static void BufferSync(int flags);
-static int SyncOneBuffer(int buf_id, bool skip_recently_used,
+static int SyncOneBuffer(int buf_id, bool skip_recently_used, bool cool_if_hot,
WritebackContext *wb_context);
static void WaitIO(BufferDesc *buf);
static void AbortBufferIO(Buffer buffer);
@@ -644,7 +643,6 @@ static inline BufferDesc *BufferAlloc(SMgrRelation smgr,
char relpersistence,
ForkNumber forkNum,
BlockNumber blockNum,
- BufferAccessStrategy strategy,
bool *foundPtr, IOContext io_context);
static bool AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress);
static void CheckReadBuffersOperation(ReadBuffersOperation *operation, bool is_complete);
@@ -653,7 +651,7 @@ static pg_always_inline void TrackBufferHit(IOObject io_object,
IOContext io_context,
Relation rel, char persistence, SMgrRelation smgr,
ForkNumber forknum, BlockNumber blocknum);
-static Buffer GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context);
+static Buffer GetVictimBuffer(IOContext io_context);
static void FlushUnlockedBuffer(BufferDesc *buf, SMgrRelation reln,
IOObject io_object, IOContext io_context);
static void FlushBuffer(BufferDesc *buf, SMgrRelation reln,
@@ -857,7 +855,7 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN
* pin.
*/
if (BufferTagsEqual(&tag, &bufHdr->tag) &&
- PinBuffer(bufHdr, NULL, true))
+ PinBuffer(bufHdr, true))
{
if (BufferTagsEqual(&tag, &bufHdr->tag))
{
@@ -873,12 +871,12 @@ ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum, BlockNumber blockN
/*
* ReadBuffer -- a shorthand for ReadBufferExtended, for reading from main
- * fork with RBM_NORMAL mode and default strategy.
+ * fork with RBM_NORMAL mode.
*/
Buffer
ReadBuffer(Relation reln, BlockNumber blockNum)
{
- return ReadBufferExtended(reln, MAIN_FORKNUM, blockNum, RBM_NORMAL, NULL);
+ return ReadBufferExtended(reln, MAIN_FORKNUM, blockNum, RBM_NORMAL);
}
/*
@@ -918,13 +916,10 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
* a cleanup-strength lock on the page.
*
* RBM_NORMAL_NO_LOG mode is treated the same as RBM_NORMAL here.
- *
- * If strategy is not NULL, a nondefault buffer access strategy is used.
- * See buffer/README for details.
*/
inline Buffer
ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
- ReadBufferMode mode, BufferAccessStrategy strategy)
+ ReadBufferMode mode)
{
Buffer buf;
@@ -934,7 +929,7 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
* ReadBuffer_common().
*/
buf = ReadBuffer_common(reln, RelationGetSmgr(reln), 0,
- forkNum, blockNum, mode, strategy);
+ forkNum, blockNum, mode);
return buf;
}
@@ -953,14 +948,14 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
Buffer
ReadBufferWithoutRelcache(RelFileLocator rlocator, ForkNumber forkNum,
BlockNumber blockNum, ReadBufferMode mode,
- BufferAccessStrategy strategy, bool permanent)
+ bool permanent)
{
SMgrRelation smgr = smgropen(rlocator, INVALID_PROC_NUMBER);
return ReadBuffer_common(NULL, smgr,
permanent ? RELPERSISTENCE_PERMANENT : RELPERSISTENCE_UNLOGGED,
forkNum, blockNum,
- mode, strategy);
+ mode);
}
/*
@@ -969,13 +964,12 @@ ReadBufferWithoutRelcache(RelFileLocator rlocator, ForkNumber forkNum,
Buffer
ExtendBufferedRel(BufferManagerRelation bmr,
ForkNumber forkNum,
- BufferAccessStrategy strategy,
uint32 flags)
{
Buffer buf;
uint32 extend_by = 1;
- ExtendBufferedRelBy(bmr, forkNum, strategy, flags, extend_by,
+ ExtendBufferedRelBy(bmr, forkNum, flags, extend_by,
&buf, &extend_by);
return buf;
@@ -1001,7 +995,6 @@ ExtendBufferedRel(BufferManagerRelation bmr,
BlockNumber
ExtendBufferedRelBy(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
uint32 extend_by,
Buffer *buffers,
@@ -1014,7 +1007,7 @@ ExtendBufferedRelBy(BufferManagerRelation bmr,
if (bmr.relpersistence == '\0')
bmr.relpersistence = bmr.rel->rd_rel->relpersistence;
- return ExtendBufferedRelCommon(bmr, fork, strategy, flags,
+ return ExtendBufferedRelCommon(bmr, fork, flags,
extend_by, InvalidBlockNumber,
buffers, extended_by);
}
@@ -1030,7 +1023,6 @@ ExtendBufferedRelBy(BufferManagerRelation bmr,
Buffer
ExtendBufferedRelTo(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
BlockNumber extend_to,
ReadBufferMode mode)
@@ -1096,7 +1088,7 @@ ExtendBufferedRelTo(BufferManagerRelation bmr,
if ((uint64) current_size + num_pages > extend_to)
num_pages = extend_to - current_size;
- first_block = ExtendBufferedRelCommon(bmr, fork, strategy, flags,
+ first_block = ExtendBufferedRelCommon(bmr, fork, flags,
num_pages, extend_to,
buffers, &extended_by);
@@ -1122,7 +1114,7 @@ ExtendBufferedRelTo(BufferManagerRelation bmr,
{
Assert(extended_by == 0);
buffer = ReadBuffer_common(bmr.rel, BMR_GET_SMGR(bmr), bmr.relpersistence,
- fork, extend_to - 1, mode, strategy);
+ fork, extend_to - 1, mode);
}
return buffer;
@@ -1225,7 +1217,6 @@ PinBufferForBlock(Relation rel,
char persistence,
ForkNumber forkNum,
BlockNumber blockNum,
- BufferAccessStrategy strategy,
IOObject io_object,
IOContext io_context,
bool *foundPtr)
@@ -1249,7 +1240,7 @@ PinBufferForBlock(Relation rel,
bufHdr = LocalBufferAlloc(smgr, forkNum, blockNum, foundPtr);
else
bufHdr = BufferAlloc(smgr, persistence, forkNum, blockNum,
- strategy, foundPtr, io_context);
+ foundPtr, io_context);
if (*foundPtr)
TrackBufferHit(io_object, io_context, rel, persistence, smgr, forkNum, blockNum);
@@ -1275,8 +1266,7 @@ PinBufferForBlock(Relation rel,
static pg_always_inline Buffer
ReadBuffer_common(Relation rel, SMgrRelation smgr, char smgr_persistence,
ForkNumber forkNum,
- BlockNumber blockNum, ReadBufferMode mode,
- BufferAccessStrategy strategy)
+ BlockNumber blockNum, ReadBufferMode mode)
{
ReadBuffersOperation operation;
Buffer buffer;
@@ -1312,7 +1302,7 @@ ReadBuffer_common(Relation rel, SMgrRelation smgr, char smgr_persistence,
if (mode == RBM_ZERO_AND_LOCK || mode == RBM_ZERO_AND_CLEANUP_LOCK)
flags |= EB_LOCK_FIRST;
- return ExtendBufferedRel(BMR_REL(rel), forkNum, strategy, flags);
+ return ExtendBufferedRel(BMR_REL(rel), forkNum, flags);
}
if (rel)
@@ -1334,12 +1324,12 @@ ReadBuffer_common(Relation rel, SMgrRelation smgr, char smgr_persistence,
}
else
{
- io_context = IOContextForStrategy(strategy);
+ io_context = IOCONTEXT_NORMAL;
io_object = IOOBJECT_RELATION;
}
buffer = PinBufferForBlock(rel, smgr, persistence,
- forkNum, blockNum, strategy,
+ forkNum, blockNum,
io_object, io_context, &found);
ZeroAndLockBuffer(buffer, mode, found);
return buffer;
@@ -1357,7 +1347,6 @@ ReadBuffer_common(Relation rel, SMgrRelation smgr, char smgr_persistence,
operation.rel = rel;
operation.persistence = persistence;
operation.forknum = forkNum;
- operation.strategy = strategy;
if (StartReadBuffer(&operation,
&buffer,
blockNum,
@@ -1398,7 +1387,7 @@ StartReadBuffersImpl(ReadBuffersOperation *operation,
}
else
{
- io_context = IOContextForStrategy(operation->strategy);
+ io_context = IOCONTEXT_NORMAL;
io_object = IOOBJECT_RELATION;
}
@@ -1449,7 +1438,6 @@ StartReadBuffersImpl(ReadBuffersOperation *operation,
operation->persistence,
operation->forknum,
blockNum + i,
- operation->strategy,
io_object, io_context,
&found);
}
@@ -1770,7 +1758,7 @@ WaitReadBuffers(ReadBuffersOperation *operation)
}
else
{
- io_context = IOContextForStrategy(operation->strategy);
+ io_context = IOCONTEXT_NORMAL;
io_object = IOOBJECT_RELATION;
}
@@ -1960,7 +1948,7 @@ AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress)
}
else
{
- io_context = IOContextForStrategy(operation->strategy);
+ io_context = IOCONTEXT_NORMAL;
io_object = IOOBJECT_RELATION;
}
@@ -2179,24 +2167,18 @@ AsyncReadBuffers(ReadBuffersOperation *operation, int *nblocks_progress)
* buffer. If no buffer exists already, selects a replacement victim and
* evicts the old page, but does NOT read in new page.
*
- * "strategy" can be a buffer replacement strategy object, or NULL for
- * the default strategy. The selected buffer's usage_count is advanced when
- * using the default strategy, but otherwise possibly not (see PinBuffer).
- *
* The returned buffer is pinned and is already marked as holding the
* desired page. If it already did have the desired page, *foundPtr is
* set true. Otherwise, *foundPtr is set false.
*
- * io_context is passed as an output parameter to avoid calling
- * IOContextForStrategy() when there is a shared buffers hit and no IO
- * statistics need be captured.
+ * io_context is passed as an output parameter to avoid capturing IO
+ * statistics when there is a shared buffers hit and no IO occurs.
*
* No locks are held either at entry or exit.
*/
static pg_always_inline BufferDesc *
BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
BlockNumber blockNum,
- BufferAccessStrategy strategy,
bool *foundPtr, IOContext io_context)
{
BufferTag newTag; /* identity of requested block */
@@ -2234,7 +2216,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
*/
buf = GetBufferDescriptor(existing_buf_id);
- valid = PinBuffer(buf, strategy, false);
+ valid = PinBuffer(buf, false);
/* Can release the mapping lock as soon as we've pinned it */
LWLockRelease(newPartitionLock);
@@ -2265,7 +2247,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
* don't hold any conflicting locks. If so we'll have to undo our work
* later.
*/
- victim_buffer = GetVictimBuffer(strategy, io_context);
+ victim_buffer = GetVictimBuffer(io_context);
victim_buf_hdr = GetBufferDescriptor(victim_buffer - 1);
/*
@@ -2296,7 +2278,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
existing_buf_hdr = GetBufferDescriptor(existing_buf_id);
- valid = PinBuffer(existing_buf_hdr, strategy, false);
+ valid = PinBuffer(existing_buf_hdr, false);
/* Can release the mapping lock as soon as we've pinned it */
LWLockRelease(newPartitionLock);
@@ -2333,7 +2315,13 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
* checkpoints, except for their "init" forks, which need to be treated
* just like permanent relations.
*/
- set_bits |= BM_TAG_VALID | BUF_USAGECOUNT_ONE;
+ set_bits |= BM_TAG_VALID;
+
+ /*
+ * Admit the newly loaded page COOL (probation); a second access via
+ * PinBuffer promotes it to HOT. This is what makes a one-touch scan
+ * self-evicting -- see the cooling-state notes in buf_internals.h.
+ */
if (relpersistence == RELPERSISTENCE_PERMANENT || forkNum == INIT_FORKNUM)
set_bits |= BM_PERMANENT;
@@ -2545,12 +2533,11 @@ InvalidateVictimBuffer(BufferDesc *buf_hdr)
}
static Buffer
-GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context)
+GetVictimBuffer(IOContext io_context)
{
BufferDesc *buf_hdr;
Buffer buf;
uint64 buf_state;
- bool from_ring;
/*
* Ensure, before we pin a victim buffer, that there's a free refcount
@@ -2566,7 +2553,7 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context)
* Select a victim buffer. The buffer is returned pinned and owned by
* this backend.
*/
- buf_hdr = StrategyGetBuffer(strategy, &buf_state, &from_ring);
+ buf_hdr = StrategyGetBuffer(&buf_state);
buf = BufferDescriptorGetBuffer(buf_hdr);
/*
@@ -2610,26 +2597,6 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context)
goto again;
}
- /*
- * If using a nondefault strategy, and this victim came from the
- * strategy ring, let the strategy decide whether to reject it when
- * reusing it would require a WAL flush. This only applies to
- * permanent buffers; unlogged buffers can have fake LSNs, so
- * XLogNeedsFlush() is not meaningful for them.
- *
- * We need to hold the content lock in at least share-exclusive mode
- * to safely inspect the page LSN, so this couldn't have been done
- * inside StrategyGetBuffer().
- */
- if (strategy && from_ring &&
- buf_state & BM_PERMANENT &&
- XLogNeedsFlush(BufferGetLSN(buf_hdr)) &&
- StrategyRejectBuffer(strategy, buf_hdr, from_ring))
- {
- UnlockReleaseBuffer(buf);
- goto again;
- }
-
/* OK, do the I/O */
FlushBuffer(buf_hdr, NULL, IOOBJECT_RELATION, io_context);
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -2642,23 +2609,15 @@ GetVictimBuffer(BufferAccessStrategy strategy, IOContext io_context)
if (buf_state & BM_VALID)
{
/*
- * When a BufferAccessStrategy is in use, blocks evicted from shared
- * buffers are counted as IOOP_EVICT in the corresponding context
- * (e.g. IOCONTEXT_BULKWRITE). Shared buffers are evicted by a
- * strategy in two cases: 1) while initially claiming buffers for the
- * strategy ring 2) to replace an existing strategy ring buffer
- * because it is pinned or in use and cannot be reused.
+ * Blocks evicted from shared buffers are counted as IOOP_EVICT.
*
- * Blocks evicted from buffers already in the strategy ring are
- * counted as IOOP_REUSE in the corresponding strategy context.
- *
- * At this point, we can accurately count evictions and reuses,
- * because we have successfully claimed the valid buffer. Previously,
- * we may have been forced to release the buffer due to concurrent
- * pinners or erroring out.
+ * At this point, we can accurately count evictions, because we have
+ * successfully claimed the valid buffer. Previously, we may have been
+ * forced to release the buffer due to concurrent pinners or erroring
+ * out.
*/
pgstat_count_io_op(IOOBJECT_RELATION, io_context,
- from_ring ? IOOP_REUSE : IOOP_EVICT, 1, 0);
+ IOOP_EVICT, 1, 0);
}
/*
@@ -2750,7 +2709,6 @@ LimitAdditionalPins(uint32 *additional_pins)
static BlockNumber
ExtendBufferedRelCommon(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
uint32 extend_by,
BlockNumber extend_upto,
@@ -2785,7 +2743,7 @@ ExtendBufferedRelCommon(BufferManagerRelation bmr,
buffers, &extend_by);
}
else
- first_block = ExtendBufferedRelShared(bmr, fork, strategy, flags,
+ first_block = ExtendBufferedRelShared(bmr, fork, flags,
extend_by, extend_upto,
buffers, &extend_by);
*extended_by = extend_by;
@@ -2808,7 +2766,6 @@ ExtendBufferedRelCommon(BufferManagerRelation bmr,
static BlockNumber
ExtendBufferedRelShared(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
uint32 extend_by,
BlockNumber extend_upto,
@@ -2816,7 +2773,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
uint32 *extended_by)
{
BlockNumber first_block;
- IOContext io_context = IOContextForStrategy(strategy);
+ IOContext io_context = IOCONTEXT_NORMAL;
instr_time io_start;
LimitAdditionalPins(&extend_by);
@@ -2835,7 +2792,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
{
Block buf_block;
- buffers[i] = GetVictimBuffer(strategy, io_context);
+ buffers[i] = GetVictimBuffer(io_context);
buf_block = BufHdrGetBlock(GetBufferDescriptor(buffers[i] - 1));
/* new buffers are zero-filled */
@@ -2953,7 +2910,7 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
* Pin the existing buffer before releasing the partition lock,
* preventing it from being evicted.
*/
- valid = PinBuffer(existing_hdr, strategy, false);
+ valid = PinBuffer(existing_hdr, false);
LWLockRelease(partition_lock);
UnpinBuffer(victim_buf_hdr);
@@ -3002,7 +2959,12 @@ ExtendBufferedRelShared(BufferManagerRelation bmr,
victim_buf_hdr->tag = tag;
- set_bits |= BM_TAG_VALID | BUF_USAGECOUNT_ONE;
+ set_bits |= BM_TAG_VALID;
+
+ /*
+ * Admit COOL (probation); see the comment at the other admission
+ * site and the cooling-state notes in buf_internals.h.
+ */
if (bmr.relpersistence == RELPERSISTENCE_PERMANENT || fork == INIT_FORKNUM)
set_bits |= BM_PERMANENT;
@@ -3269,13 +3231,8 @@ ReleaseAndReadBuffer(Buffer buffer,
/*
* PinBuffer -- make buffer unavailable for replacement.
*
- * For the default access strategy, the buffer's usage_count is incremented
- * when we first pin it; for other strategies we just make sure the usage_count
- * isn't zero. (The idea of the latter is that we don't want synchronized
- * heap scans to inflate the count, but we need it to not be zero to discourage
- * other backends from stealing buffers from our ring. As long as we cycle
- * through the ring faster than the global clock-sweep cycles, buffers in
- * our ring won't be chosen as victims for replacement by other backends.)
+ * The buffer's cooling state is promoted to HOT (the 2Q rescue) when we pin
+ * it; see the cooling-state notes in buf_internals.h.
*
* This should be applied only to shared buffers, never local ones.
*
@@ -3292,7 +3249,7 @@ ReleaseAndReadBuffer(Buffer buffer,
* (recently) invalid and has not been pinned.
*/
static bool
-PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
+PinBuffer(BufferDesc *buf,
bool skip_if_not_valid)
{
Buffer b = BufferDescriptorGetBuffer(buf);
@@ -3332,21 +3289,17 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
/* increase refcount */
buf_state += BUF_REFCOUNT_ONE;
- if (strategy == NULL)
- {
- /* Default case: increase usagecount unless already max. */
- if (BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
- buf_state += BUF_USAGECOUNT_ONE;
- }
- else
- {
- /*
- * Ring buffers shouldn't evict others from pool. Thus we
- * don't make usagecount more than 1.
- */
- if (BUF_STATE_GET_USAGECOUNT(buf_state) == 0)
- buf_state += BUF_USAGECOUNT_ONE;
- }
+ /*
+ * Accessing a resident buffer promotes it to HOT (the 2Q rescue):
+ * a page loaded COOL on probation becomes part of the hot working
+ * set on its second touch. BM_MAX_USAGE_COUNT is
+ * BUF_COOLSTATE_HOT (1), so this saturates at HOT and never
+ * overflows the field. We also set the second-chance ref bit so
+ * the bgwriter's next cooling pass spares this recently-used buffer.
+ */
+ if (BUF_STATE_GET_COOLSTATE(buf_state) < BUF_COOLSTATE_HOT)
+ buf_state += BUF_COOLSTATE_ONE;
+ buf_state |= BUF_REFBIT;
if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state,
buf_state))
@@ -3394,7 +3347,7 @@ PinBuffer(BufferDesc *buf, BufferAccessStrategy strategy,
* ResourceOwnerEnlarge(CurrentResourceOwner);
*
* Currently, no callers of this function want to modify the buffer's
- * usage_count at all, so there's no need for a strategy parameter.
+ * cooling state at all.
* Also we don't bother with a BM_VALID test (the caller could check that for
* itself).
*
@@ -3785,7 +3738,7 @@ BufferSync(int flags)
*/
if (pg_atomic_read_u64(&bufHdr->state) & BM_CHECKPOINT_NEEDED)
{
- if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN)
+ if (SyncOneBuffer(buf_id, false, false, &wb_context) & BUF_WRITTEN)
{
TRACE_POSTGRESQL_BUFFER_SYNC_WRITTEN(buf_id);
PendingCheckpointerStats.buffers_written++;
@@ -3876,6 +3829,19 @@ BgBufferSync(WritebackContext *wb_context)
float smoothing_samples = 16;
float scan_whole_pool_milliseconds = 120000.0;
+ /*
+ * The cleaner scan directly observes the reusable (COOL, unpinned) buffer
+ * density over the region it walks, which -- with the cooling-stage
+ * evictor -- is exactly the sweep's victim predicate. That observation is
+ * ground truth for the buffers about to be reused, whereas the strategy
+ * scan's positional proxy (strategy_delta/recent_alloc) blurs a pool whose
+ * COOL population is spatially clustered (a scan burst leaves whole regions
+ * COOL, hot OLTP regions not). So we let the cleaner's own sample adapt on
+ * a shorter window than the strategy proxy, tracking a burst of
+ * probationary/scan COOL pages within a cycle or two instead of lagging it.
+ */
+ float cleaner_smoothing_samples = 4;
+
/* Used to compute how far we scan ahead */
long strategy_delta;
int bufs_to_lap;
@@ -3889,6 +3855,7 @@ BgBufferSync(WritebackContext *wb_context)
int num_to_scan;
int num_written;
int reusable_buffers;
+ int write_limit;
/* Variables for final smoothed_density update */
long new_strategy_delta;
@@ -4063,8 +4030,22 @@ BgBufferSync(WritebackContext *wb_context)
* Now write out dirty reusable buffers, working forward from the
* next_to_clean point, until we have lapped the strategy scan, or cleaned
* enough buffers to match our estimate of the next cycle's allocation
- * requirements, or hit the bgwriter_lru_maxpages limit.
- */
+ * requirements, or hit the write limit.
+ *
+ * The per-cycle write cap is normally bgwriter_lru_maxpages. But under a
+ * bulk-dirtying workload (COPY, bulk UPDATE, VACUUM) the pool fills with
+ * dirty COOL buffers faster than that fixed cap can clean, so the
+ * foreground clock sweep is forced to flush dirty victims inline -- the
+ * very cost the cooling-stage evictor is meant to keep off the critical
+ * path. When predicted demand (upcoming_alloc_est) exceeds the fixed cap,
+ * raise the limit to meet demand so the bgwriter stays ahead and supplies
+ * clean victims. This stays bounded (by demand and by lapping the
+ * strategy point), so it cannot run away, and normal workloads are
+ * unaffected because there upcoming_alloc_est <= bgwriter_lru_maxpages.
+ */
+ write_limit = bgwriter_lru_maxpages;
+ if (upcoming_alloc_est > write_limit)
+ write_limit = upcoming_alloc_est;
num_to_scan = bufs_to_lap;
num_written = 0;
@@ -4073,7 +4054,7 @@ BgBufferSync(WritebackContext *wb_context)
/* Execute the LRU scan */
while (num_to_scan > 0 && reusable_buffers < upcoming_alloc_est)
{
- int sync_state = SyncOneBuffer(next_to_clean, true,
+ int sync_state = SyncOneBuffer(next_to_clean, true, true,
wb_context);
if (++next_to_clean >= NBuffers)
@@ -4086,7 +4067,7 @@ BgBufferSync(WritebackContext *wb_context)
if (sync_state & BUF_WRITTEN)
{
reusable_buffers++;
- if (++num_written >= bgwriter_lru_maxpages)
+ if (++num_written >= write_limit)
{
PendingBgWriterStats.maxwritten_clean++;
break;
@@ -4121,7 +4102,7 @@ BgBufferSync(WritebackContext *wb_context)
{
scans_per_alloc = (float) new_strategy_delta / (float) new_recent_alloc;
smoothed_density += (scans_per_alloc - smoothed_density) /
- smoothing_samples;
+ cleaner_smoothing_samples;
#ifdef BGW_DEBUG
elog(DEBUG2, "bgwriter: cleaner density alloc=%u scan=%ld density=%.2f new smoothed=%.2f",
@@ -4140,16 +4121,26 @@ BgBufferSync(WritebackContext *wb_context)
* If skip_recently_used is true, we don't write currently-pinned buffers, nor
* buffers marked recently used, as these are not replacement candidates.
*
+ * If cool_if_hot is true (the bgwriter's LRU scan), an unpinned HOT buffer is
+ * demoted HOT -> COOL as we pass it, pre-staging eviction candidates so the
+ * foreground clock sweep finds a COOL victim in a single pass instead of
+ * having to cool buffers itself (force_cool). The demotion is done under the
+ * buffer header lock we already hold, so it needs no CAS and cannot race a
+ * concurrent demotion. A concurrent PinBuffer promotes it back to HOT, which
+ * is the intended 2Q behavior (a re-accessed buffer is rescued).
+ *
* Returns a bitmask containing the following flag bits:
* BUF_WRITTEN: we wrote the buffer.
* BUF_REUSABLE: buffer is available for replacement, ie, it has
- * pin count 0 and usage count 0.
+ * pin count 0 and is COOL (an eviction candidate).
+ * BUF_COOLED: we demoted this buffer HOT -> COOL this call.
*
* (BUF_WRITTEN could be set in error if FlushBuffer finds the buffer clean
* after locking it, but we don't care all that much.)
*/
static int
-SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context)
+SyncOneBuffer(int buf_id, bool skip_recently_used, bool cool_if_hot,
+ WritebackContext *wb_context)
{
BufferDesc *bufHdr = GetBufferDescriptor(buf_id);
int result = 0;
@@ -4171,8 +4162,38 @@ SyncOneBuffer(int buf_id, bool skip_recently_used, WritebackContext *wb_context)
*/
buf_state = LockBufHdr(bufHdr);
+ /*
+ * Pre-cool with a second chance: if asked, act on an unpinned HOT buffer.
+ * If its ref bit is set (accessed since our last pass), clear the ref bit
+ * and leave it HOT -- a recently-used buffer earns one reprieve, keeping
+ * the hot working set out of the COOL stage under scan pressure. Only a
+ * HOT buffer whose ref bit is already clear is demoted HOT -> COOL,
+ * pre-staging it as an eviction candidate for the foreground sweep. We
+ * hold the header lock, so each transition is a plain masked store applied
+ * atomically by UnlockBufHdrExt; we re-lock to continue the dirty-write
+ * inspection below.
+ */
+ if (cool_if_hot &&
+ BUF_STATE_GET_REFCOUNT(buf_state) == 0 &&
+ BUF_STATE_GET_COOLSTATE(buf_state) != BUF_COOLSTATE_COOL)
+ {
+ if (BUF_STATE_GET_REFBIT(buf_state))
+ {
+ /* second chance: consume the ref bit, stay HOT */
+ UnlockBufHdrExt(bufHdr, buf_state, 0, BUF_REFBIT, 0);
+ buf_state = LockBufHdr(bufHdr);
+ }
+ else
+ {
+ /* not re-accessed since last pass: demote to COOL */
+ UnlockBufHdrExt(bufHdr, buf_state, 0, BUF_USAGECOUNT_MASK, 0);
+ buf_state = LockBufHdr(bufHdr);
+ result |= BUF_COOLED;
+ }
+ }
+
if (BUF_STATE_GET_REFCOUNT(buf_state) == 0 &&
- BUF_STATE_GET_USAGECOUNT(buf_state) == 0)
+ BUF_STATE_GET_COOLSTATE(buf_state) == BUF_COOLSTATE_COOL)
{
result |= BUF_REUSABLE;
}
@@ -4604,22 +4625,8 @@ FlushBuffer(BufferDesc *buf, SMgrRelation reln, IOObject io_object,
false);
/*
- * When a strategy is in use, only flushes of dirty buffers already in the
- * strategy ring are counted as strategy writes (IOCONTEXT
- * [BULKREAD|BULKWRITE|VACUUM] IOOP_WRITE) for the purpose of IO
- * statistics tracking.
- *
- * If a shared buffer initially added to the ring must be flushed before
- * being used, this is counted as an IOCONTEXT_NORMAL IOOP_WRITE.
- *
- * If a shared buffer which was added to the ring later because the
- * current strategy buffer is pinned or in use or because all strategy
- * buffers were dirty and rejected (for BAS_BULKREAD operations only)
- * requires flushing, this is counted as an IOCONTEXT_NORMAL IOOP_WRITE
- * (from_ring will be false).
- *
- * When a strategy is not in use, the write can only be a "regular" write
- * of a dirty shared buffer (IOCONTEXT_NORMAL IOOP_WRITE).
+ * All writes of a dirty shared buffer are counted as an IOCONTEXT_NORMAL
+ * IOOP_WRITE for the purpose of IO statistics tracking.
*/
pgstat_count_io_op_time(io_object, io_context,
IOOP_WRITE, io_start, 1, BLCKSZ);
@@ -5380,8 +5387,6 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
BlockNumber nblocks;
BlockNumber blkno;
PGIOAlignedBlock buf;
- BufferAccessStrategy bstrategy_src;
- BufferAccessStrategy bstrategy_dst;
BlockRangeReadStreamPrivate p;
ReadStream *src_stream;
SMgrRelation src_smgr;
@@ -5409,10 +5414,6 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
smgrextend(smgropen(dstlocator, INVALID_PROC_NUMBER), forkNum, nblocks - 1,
buf.data, true);
- /* This is a bulk operation, so use buffer access strategies. */
- bstrategy_src = GetAccessStrategy(BAS_BULKREAD);
- bstrategy_dst = GetAccessStrategy(BAS_BULKWRITE);
-
/* Initialize streaming read */
p.current_blocknum = 0;
p.last_exclusive = nblocks;
@@ -5424,7 +5425,6 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
*/
src_stream = read_stream_begin_smgr_relation(READ_STREAM_FULL |
READ_STREAM_USE_BATCHING,
- bstrategy_src,
src_smgr,
permanent ? RELPERSISTENCE_PERMANENT : RELPERSISTENCE_UNLOGGED,
forkNum,
@@ -5444,7 +5444,7 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
dstBuf = ReadBufferWithoutRelcache(dstlocator, forkNum,
BufferGetBlockNumber(srcBuf),
- RBM_ZERO_AND_LOCK, bstrategy_dst,
+ RBM_ZERO_AND_LOCK,
permanent);
dstPage = BufferGetPage(dstBuf);
@@ -5465,9 +5465,6 @@ RelationCopyStorageUsingBuffer(RelFileLocator srclocator,
}
Assert(read_stream_next_buffer(src_stream, NULL) == InvalidBuffer);
read_stream_end(src_stream);
-
- FreeAccessStrategy(bstrategy_src);
- FreeAccessStrategy(bstrategy_dst);
}
/* ---------------------------------------------------------------------
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index fdb5bad7910a2..ee62b33668003 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -22,6 +22,7 @@
#include "storage/proc.h"
#include "storage/shmem.h"
#include "storage/subsystems.h"
+#include "port/pg_numa.h"
#define INT_ACCESS_ONCE(var) ((int)(*((volatile int *)&(var))))
@@ -48,6 +49,16 @@ typedef struct
uint32 completePasses; /* Complete cycles of the clock-sweep */
pg_atomic_uint32 numBufferAllocs; /* Buffers allocated since last reset */
+ /*
+ * Number of clock-hand values a backend claims per atomic fetch-add.
+ * Computed once at startup (see StrategyCtlShmemInit). Kept in shared
+ * memory rather than a backend-local static so that EXEC_BACKEND children
+ * (which do not inherit the postmaster's statics) see the same value; a
+ * backend-local copy would silently reset to 1 there, disabling batching
+ * on Windows.
+ */
+ uint32 batchSize;
+
/*
* Bgworker process to be notified upon activity or -1 if none. See
* StrategyNotifyBgWriter.
@@ -67,101 +78,98 @@ const ShmemCallbacks StrategyCtlShmemCallbacks = {
};
/*
- * Private (non-shared) state for managing a ring of shared buffers to re-use.
- * This is currently the only kind of BufferAccessStrategy object, but someday
- * we might have more kinds.
+ * Per-backend state for the batched clock sweep. Each backend claims a run
+ * of consecutive clock-hand values with a single atomic fetch-add and then
+ * iterates through them privately, so the contended nextVictimBuffer cache
+ * line is touched roughly 1/batch as often. MyBatchPos is the next hand
+ * value to hand out; MyBatchEnd is one past the end of the claimed run. Both
+ * are absolute (monotonically increasing) hand values; the buffer id is the
+ * value modulo NBuffers.
*/
-typedef struct BufferAccessStrategyData
-{
- /* Overall strategy type */
- BufferAccessStrategyType btype;
- /* Number of elements in buffers[] array */
- int nbuffers;
-
- /*
- * Index of the "current" slot in the ring, ie, the one most recently
- * returned by GetBufferFromRing.
- */
- int current;
-
- /*
- * Array of buffer numbers. InvalidBuffer (that is, zero) indicates we
- * have not yet selected a buffer for this ring slot. For allocation
- * simplicity this is palloc'd together with the fixed fields of the
- * struct.
- */
- Buffer buffers[FLEXIBLE_ARRAY_MEMBER];
-} BufferAccessStrategyData;
-
-
-/* Prototypes for internal functions */
-static BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy,
- uint64 *buf_state);
-static void AddBufferToRing(BufferAccessStrategy strategy,
- BufferDesc *buf);
+static uint32 MyBatchPos = 0;
+static uint32 MyBatchEnd = 0;
/*
* ClockSweepTick - Helper routine for StrategyGetBuffer()
*
- * Move the clock hand one buffer ahead of its current position and return the
- * id of the buffer now under the hand.
+ * Return the next buffer to consider for eviction. Backends claim batches of
+ * consecutive buffer IDs from the shared clock hand, then iterate through
+ * them locally without further atomic operations. This preserves the global
+ * sweep order while reducing contention on the shared counter.
*/
static inline uint32
ClockSweepTick(void)
{
uint32 victim;
- /*
- * Atomically move hand ahead one buffer - if there's several processes
- * doing this, this can lead to buffers being returned slightly out of
- * apparent order.
- */
- victim =
- pg_atomic_fetch_add_u32(&StrategyControl->nextVictimBuffer, 1);
-
- if (victim >= NBuffers)
+ if (MyBatchPos >= MyBatchEnd)
{
- uint32 originalVictim = victim;
-
- /* always wrap what we look up in BufferDescriptors */
- victim = victim % NBuffers;
-
/*
- * If we're the one that just caused a wraparound, force
- * completePasses to be incremented while holding the spinlock. We
- * need the spinlock so StrategySyncStart() can return a consistent
- * value consisting of nextVictimBuffer and completePasses.
+ * Claim a fresh batch from the shared clock hand. This is the only
+ * atomic operation per batch, reducing contention by the batch size.
*/
- if (victim == 0)
- {
- uint32 expected;
- uint32 wrapped;
- bool success = false;
+ uint32 start;
+ uint32 batch_size = StrategyControl->batchSize;
- expected = originalVictim + 1;
+ start = pg_atomic_fetch_add_u32(&StrategyControl->nextVictimBuffer,
+ batch_size);
- while (!success)
- {
- /*
- * Acquire the spinlock while increasing completePasses. That
- * allows other readers to read nextVictimBuffer and
- * completePasses in a consistent manner which is required for
- * StrategySyncStart(). In theory delaying the increment
- * could lead to an overflow of nextVictimBuffers, but that's
- * highly unlikely and wouldn't be particularly harmful.
- */
- SpinLockAcquire(&StrategyControl->buffer_strategy_lock);
+ if (start >= (uint32) NBuffers)
+ {
+ start = start % NBuffers;
- wrapped = expected % NBuffers;
+ /*
+ * The counter has grown past NBuffers; try to wrap it back. We
+ * must hold the spinlock so StrategySyncStart() can read
+ * nextVictimBuffer and completePasses consistently.
+ *
+ * With batching, multiple backends may each land a fetch-add that
+ * returns a value past NBuffers in the same pass. After
+ * acquiring the spinlock we re-read the counter: if another
+ * backend already wrapped it below NBuffers we are done.
+ */
+ SpinLockAcquire(&StrategyControl->buffer_strategy_lock);
+ {
+ uint32 current;
+ uint32 wrapped;
- success = pg_atomic_compare_exchange_u32(&StrategyControl->nextVictimBuffer,
- &expected, wrapped);
- if (success)
- StrategyControl->completePasses++;
- SpinLockRelease(&StrategyControl->buffer_strategy_lock);
+ current = pg_atomic_read_u32(&StrategyControl->nextVictimBuffer);
+ if (current >= (uint32) NBuffers)
+ {
+ wrapped = current % NBuffers;
+ if (pg_atomic_compare_exchange_u32(&StrategyControl->nextVictimBuffer,
+ ¤t, wrapped))
+ StrategyControl->completePasses++;
+ }
}
+ SpinLockRelease(&StrategyControl->buffer_strategy_lock);
}
+ else if (start + batch_size > (uint32) NBuffers)
+ {
+ /*
+ * The fetch-add returned a value below NBuffers, but this batch
+ * spans the wrap point (start .. NBuffers-1 then 0 .. k are
+ * iterated locally via "% NBuffers"). That crossing is a
+ * complete pass too, but the wrap-and-increment path above only
+ * fires when the fetch-add return is itself >= NBuffers, so
+ * without this it would go uncounted and completePasses would
+ * drift low (it feeds bgwriter pacing / StrategySyncStart, not
+ * correctness). The batch is capped at NBuffers, so a batch
+ * spans the wrap at most once; count it under the spinlock for a
+ * consistent (nextVictimBuffer, completePasses) pair.
+ */
+ SpinLockAcquire(&StrategyControl->buffer_strategy_lock);
+ StrategyControl->completePasses++;
+ SpinLockRelease(&StrategyControl->buffer_strategy_lock);
+ }
+
+ MyBatchPos = start;
+ MyBatchEnd = start + batch_size;
}
+
+ victim = MyBatchPos % NBuffers;
+ MyBatchPos++;
+
return victim;
}
@@ -172,8 +180,6 @@ ClockSweepTick(void)
* GetVictimBuffer(). The only hard requirement GetVictimBuffer() has is that
* the selected buffer must not currently be pinned by anyone.
*
- * strategy is a BufferAccessStrategy object, or NULL for default strategy.
- *
* It is the callers responsibility to ensure the buffer ownership can be
* tracked via TrackNewBufferPin().
*
@@ -181,27 +187,12 @@ ClockSweepTick(void)
* before returning.
*/
BufferDesc *
-StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_ring)
+StrategyGetBuffer(uint64 *buf_state)
{
BufferDesc *buf;
int bgwprocno;
int trycounter;
-
- *from_ring = false;
-
- /*
- * If given a strategy object, see whether it can select a buffer. We
- * assume strategy objects don't need buffer_strategy_lock.
- */
- if (strategy != NULL)
- {
- buf = GetBufferFromRing(strategy, buf_state);
- if (buf != NULL)
- {
- *from_ring = true;
- return buf;
- }
- }
+ bool force_cool;
/*
* If asked, we need to waken the bgwriter. Since we don't want to rely on
@@ -231,17 +222,36 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_r
/*
* We count buffer allocation requests so that the bgwriter can estimate
- * the rate of buffer consumption. Note that buffers recycled by a
- * strategy object are intentionally not counted here.
+ * the rate of buffer consumption.
*/
pg_atomic_fetch_add_u32(&StrategyControl->numBufferAllocs, 1);
- /* Use the "clock sweep" algorithm to find a free buffer */
+ /*
+ * Use the cooling-stage clock sweep to find a victim.
+ *
+ * A buffer is HOT (recently used) or COOL (an eviction candidate). We
+ * prefer to reclaim an already-COOL buffer and demote a HOT buffer to
+ * COOL only once a full sweep has found no COOL victim (force_cool) -- so
+ * an abundant supply of COOL/probationary pages (e.g. a scan) is drained
+ * before the hot working set is cooled. Newly loaded pages are admitted
+ * COOL (see BufferAlloc), so scan resistance falls out of the algorithm.
+ *
+ * trycounter bounds the search. Any tick that does not produce a victim
+ * and does not make progress -- a pinned buffer, or a HOT buffer skipped
+ * on a prefer-COOL pass -- decrements it. Cooling a HOT buffer (under
+ * force_cool) is progress and resets it. When a full pass (NBuffers)
+ * makes no progress we escalate to force_cool so the next pass cools HOT
+ * buffers into victims; if a force_cool pass ALSO makes no progress every
+ * buffer is pinned and we fail, matching the stock "no unpinned buffers
+ * available" contract.
+ */
trycounter = NBuffers;
+ force_cool = false;
for (;;)
{
uint64 old_buf_state;
uint64 local_buf_state;
+ bool no_progress = false;
buf = GetBufferDescriptor(ClockSweepTick());
@@ -254,25 +264,10 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_r
{
local_buf_state = old_buf_state;
- /*
- * If the buffer is pinned or has a nonzero usage_count, we cannot
- * use it; decrement the usage_count (unless pinned) and keep
- * scanning.
- */
-
+ /* If the buffer is pinned we cannot use it; keep scanning. */
if (BUF_STATE_GET_REFCOUNT(local_buf_state) != 0)
{
- if (--trycounter == 0)
- {
- /*
- * We've scanned all the buffers without making any state
- * changes, so all the buffers are pinned (or were when we
- * looked at them). We could hope that someone will free
- * one eventually, but it's probably better to fail than
- * to risk getting stuck in an infinite loop.
- */
- elog(ERROR, "no unpinned buffers available");
- }
+ no_progress = true;
break;
}
@@ -283,28 +278,62 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_r
continue;
}
- if (BUF_STATE_GET_USAGECOUNT(local_buf_state) != 0)
+ if (BUF_STATE_GET_COOLSTATE(local_buf_state) != BUF_COOLSTATE_COOL)
{
- local_buf_state -= BUF_USAGECOUNT_ONE;
+ /*
+ * HOT buffer. Prefer a COOL victim: on a normal pass just
+ * advance the hand (no progress). Under force_cool apply the
+ * same second-chance rule the bgwriter's pre-cooling uses: a
+ * HOT buffer whose ref bit is set (recently accessed) has the
+ * ref bit cleared and is left HOT this pass; only a HOT buffer
+ * whose ref bit is already clear is demoted HOT -> COOL. This
+ * keeps a just-touched buffer from being cooled the instant the
+ * bgwriter falls behind and the foreground has to cool for
+ * itself. Either transition is progress toward a victim.
+ */
+ if (!force_cool)
+ {
+ no_progress = true;
+ break; /* advance the hand, look for COOL */
+ }
+
+ if (BUF_STATE_GET_REFBIT(local_buf_state))
+ local_buf_state &= ~BUF_REFBIT; /* second chance: clear ref, stay HOT */
+ else
+ local_buf_state &= ~BUF_USAGECOUNT_MASK; /* HOT -> COOL, clear ref bit */
if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state,
local_buf_state))
{
+ /*
+ * Making a cooling-state transition is progress toward a
+ * victim, so reset the counter. Stay in force_cool: we made
+ * a transition but have not yet produced a reclaimable COOL
+ * victim (a ref-clear leaves the buffer HOT; a demote leaves
+ * it COOL for a later tick to claim), and dropping out here
+ * would waste a full no-progress pass re-escalating. An
+ * all-HOT, all-recently-referenced pool thus takes up to ~3
+ * full passes to yield a victim (discover no COOL, clear ref
+ * bits, cool + reclaim) -- still within the stock clock's
+ * worst case (up to BM_MAX_USAGE_COUNT+1 passes), and in
+ * practice the bgwriter pre-cooling keeps a COOL victim
+ * available so force_cool rarely fires at all. force_cool
+ * ends naturally once a COOL victim is found and returned
+ * below.
+ */
trycounter = NBuffers;
break;
}
}
else
{
- /* pin the buffer if the CAS succeeds */
+ /* COOL and unpinned: claim it. Pin if the CAS succeeds. */
local_buf_state += BUF_REFCOUNT_ONE;
if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state,
local_buf_state))
{
/* Found a usable buffer */
- if (strategy != NULL)
- AddBufferToRing(strategy, buf);
*buf_state = local_buf_state;
TrackNewBufferPin(BufferDescriptorGetBuffer(buf));
@@ -313,6 +342,22 @@ StrategyGetBuffer(BufferAccessStrategy strategy, uint64 *buf_state, bool *from_r
}
}
}
+
+ /*
+ * A tick that made no progress toward a victim counts down
+ * trycounter. A full unproductive pass escalates to force_cool (cool
+ * HOT buffers into victims); a second unproductive full pass means
+ * everything is pinned, so fail rather than spin forever. (A failed
+ * CAS above is neither progress nor a full miss: we simply retry the
+ * same buffer.)
+ */
+ if (no_progress && --trycounter == 0)
+ {
+ if (force_cool)
+ elog(ERROR, "no unpinned buffers available");
+ force_cool = true;
+ trycounter = NBuffers;
+ }
}
}
@@ -408,363 +453,27 @@ StrategyCtlShmemInit(void *arg)
/* No pending notification */
StrategyControl->bgwprocno = -1;
-}
-
-
-/* ----------------------------------------------------------------
- * Backend-private buffer ring management
- * ----------------------------------------------------------------
- */
-
-
-/*
- * GetAccessStrategy -- create a BufferAccessStrategy object
- *
- * The object is allocated in the current memory context.
- */
-BufferAccessStrategy
-GetAccessStrategy(BufferAccessStrategyType btype)
-{
- int ring_size_kb;
/*
- * Select ring size to use. See buffer/README for rationales.
+ * Decide whether to batch the clock sweep.
*
- * Note: if you change the ring size for BAS_BULKREAD, see also
- * SYNC_SCAN_REPORT_INTERVAL in access/heap/syncscan.c.
- */
- switch (btype)
- {
- case BAS_NORMAL:
- /* if someone asks for NORMAL, just give 'em a "default" object */
- return NULL;
-
- case BAS_BULKREAD:
- {
- int ring_max_kb;
-
- /*
- * The ring always needs to be large enough to allow some
- * separation in time between providing a buffer to the user
- * of the strategy and that buffer being reused. Otherwise the
- * user's pin will prevent reuse of the buffer, even without
- * concurrent activity.
- *
- * We also need to ensure the ring always is large enough for
- * SYNC_SCAN_REPORT_INTERVAL, as noted above.
- *
- * Thus we start out a minimal size and increase the size
- * further if appropriate.
- */
- ring_size_kb = 256;
-
- /*
- * There's no point in a larger ring if we won't be allowed to
- * pin sufficiently many buffers. But we never limit to less
- * than the minimal size above.
- */
- ring_max_kb = GetPinLimit() * (BLCKSZ / 1024);
- ring_max_kb = Max(ring_size_kb, ring_max_kb);
-
- /*
- * We would like the ring to additionally have space for the
- * configured degree of IO concurrency. While being read in,
- * buffers can obviously not yet be reused.
- *
- * Each IO can be up to io_combine_limit blocks large, and we
- * want to start up to effective_io_concurrency IOs.
- *
- * Note that effective_io_concurrency may be 0, which disables
- * AIO.
- */
- ring_size_kb += (BLCKSZ / 1024) *
- io_combine_limit * effective_io_concurrency;
-
- if (ring_size_kb > ring_max_kb)
- ring_size_kb = ring_max_kb;
- break;
- }
- case BAS_BULKWRITE:
- ring_size_kb = 16 * 1024;
- break;
- case BAS_VACUUM:
- ring_size_kb = 2048;
- break;
-
- default:
- elog(ERROR, "unrecognized buffer access strategy: %d",
- (int) btype);
- return NULL; /* keep compiler quiet */
- }
-
- return GetAccessStrategyWithSize(btype, ring_size_kb);
-}
-
-/*
- * GetAccessStrategyWithSize -- create a BufferAccessStrategy object with a
- * number of buffers equivalent to the passed in size.
- *
- * If the given ring size is 0, no BufferAccessStrategy will be created and
- * the function will return NULL. ring_size_kb must not be negative.
- */
-BufferAccessStrategy
-GetAccessStrategyWithSize(BufferAccessStrategyType btype, int ring_size_kb)
-{
- int ring_buffers;
- BufferAccessStrategy strategy;
-
- Assert(ring_size_kb >= 0);
-
- /* Figure out how many buffers ring_size_kb is */
- ring_buffers = ring_size_kb / (BLCKSZ / 1024);
-
- /* 0 means unlimited, so no BufferAccessStrategy required */
- if (ring_buffers == 0)
- return NULL;
-
- /* Cap to 1/8th of shared_buffers */
- ring_buffers = Min(NBuffers / 8, ring_buffers);
-
- /* NBuffers should never be less than 16, so this shouldn't happen */
- Assert(ring_buffers > 0);
-
- /* Allocate the object and initialize all elements to zeroes */
- strategy = (BufferAccessStrategy)
- palloc0(offsetof(BufferAccessStrategyData, buffers) +
- ring_buffers * sizeof(Buffer));
-
- /* Set fields that don't start out zero */
- strategy->btype = btype;
- strategy->nbuffers = ring_buffers;
-
- return strategy;
-}
-
-/*
- * GetAccessStrategyBufferCount -- an accessor for the number of buffers in
- * the ring
- *
- * Returns 0 on NULL input to match behavior of GetAccessStrategyWithSize()
- * returning NULL with 0 size.
- */
-int
-GetAccessStrategyBufferCount(BufferAccessStrategy strategy)
-{
- if (strategy == NULL)
- return 0;
-
- return strategy->nbuffers;
-}
-
-/*
- * GetAccessStrategyPinLimit -- get cap of number of buffers that should be pinned
- *
- * When pinning extra buffers to look ahead, users of a ring-based strategy are
- * in danger of pinning too much of the ring at once while performing look-ahead.
- * For some strategies, that means "escaping" from the ring, and in others it
- * means forcing dirty data to disk very frequently with associated WAL
- * flushing. Since external code has no insight into any of that, allow
- * individual strategy types to expose a clamp that should be applied when
- * deciding on a maximum number of buffers to pin at once.
- *
- * Callers should combine this number with other relevant limits and take the
- * minimum.
- */
-int
-GetAccessStrategyPinLimit(BufferAccessStrategy strategy)
-{
- if (strategy == NULL)
- return NBuffers;
-
- switch (strategy->btype)
- {
- case BAS_BULKREAD:
-
- /*
- * Since BAS_BULKREAD uses StrategyRejectBuffer(), dirty buffers
- * shouldn't be a problem and the caller is free to pin up to the
- * entire ring at once.
- */
- return strategy->nbuffers;
-
- default:
-
- /*
- * Tell caller not to pin more than half the buffers in the ring.
- * This is a trade-off between look ahead distance and deferring
- * writeback and associated WAL traffic.
- */
- return strategy->nbuffers / 2;
- }
-}
-
-/*
- * FreeAccessStrategy -- release a BufferAccessStrategy object
- *
- * A simple pfree would do at the moment, but we would prefer that callers
- * don't assume that much about the representation of BufferAccessStrategy.
- */
-void
-FreeAccessStrategy(BufferAccessStrategy strategy)
-{
- /* don't crash if called on a "default" strategy */
- if (strategy != NULL)
- pfree(strategy);
-}
-
-/*
- * GetBufferFromRing -- returns a buffer from the ring, or NULL if the
- * ring is empty / not usable.
- *
- * The buffer is pinned and marked as owned, using TrackNewBufferPin(), before
- * returning.
- */
-static BufferDesc *
-GetBufferFromRing(BufferAccessStrategy strategy, uint64 *buf_state)
-{
- BufferDesc *buf;
- Buffer bufnum;
- uint64 old_buf_state;
- uint64 local_buf_state; /* to avoid repeated (de-)referencing */
-
-
- /* Advance to next ring slot */
- if (++strategy->current >= strategy->nbuffers)
- strategy->current = 0;
-
- /*
- * If the slot hasn't been filled yet, tell the caller to allocate a new
- * buffer with the normal allocation strategy. He will then fill this
- * slot by calling AddBufferToRing with the new buffer.
- */
- bufnum = strategy->buffers[strategy->current];
- if (bufnum == InvalidBuffer)
- return NULL;
-
- buf = GetBufferDescriptor(bufnum - 1);
-
- /*
- * Check whether the buffer can be used and pin it if so. Do this using a
- * CAS loop, to avoid having to lock the buffer header.
- */
- old_buf_state = pg_atomic_read_u64(&buf->state);
- for (;;)
- {
- local_buf_state = old_buf_state;
-
- /*
- * If the buffer is pinned we cannot use it under any circumstances.
- *
- * If usage_count is 0 or 1 then the buffer is fair game (we expect 1,
- * since our own previous usage of the ring element would have left it
- * there, but it might've been decremented by clock-sweep since then).
- * A higher usage_count indicates someone else has touched the buffer,
- * so we shouldn't re-use it.
- */
- if (BUF_STATE_GET_REFCOUNT(local_buf_state) != 0
- || BUF_STATE_GET_USAGECOUNT(local_buf_state) > 1)
- break;
-
- /* See equivalent code in PinBuffer() */
- if (unlikely(local_buf_state & BM_LOCKED))
- {
- old_buf_state = WaitBufHdrUnlocked(buf);
- continue;
- }
-
- /* pin the buffer if the CAS succeeds */
- local_buf_state += BUF_REFCOUNT_ONE;
-
- if (pg_atomic_compare_exchange_u64(&buf->state, &old_buf_state,
- local_buf_state))
- {
- *buf_state = local_buf_state;
-
- TrackNewBufferPin(BufferDescriptorGetBuffer(buf));
- return buf;
- }
- }
-
- /*
- * Tell caller to allocate a new buffer with the normal allocation
- * strategy. He'll then replace this ring element via AddBufferToRing.
- */
- return NULL;
-}
-
-/*
- * AddBufferToRing -- add a buffer to the buffer ring
- *
- * Caller must hold the buffer header spinlock on the buffer. Since this
- * is called with the spinlock held, it had better be quite cheap.
- */
-static void
-AddBufferToRing(BufferAccessStrategy strategy, BufferDesc *buf)
-{
- strategy->buffers[strategy->current] = BufferDescriptorGetBuffer(buf);
-}
-
-/*
- * Utility function returning the IOContext of a given BufferAccessStrategy's
- * strategy ring.
- */
-IOContext
-IOContextForStrategy(BufferAccessStrategy strategy)
-{
- if (!strategy)
- return IOCONTEXT_NORMAL;
-
- switch (strategy->btype)
- {
- case BAS_NORMAL:
-
- /*
- * Currently, GetAccessStrategy() returns NULL for
- * BufferAccessStrategyType BAS_NORMAL, so this case is
- * unreachable.
- */
- pg_unreachable();
- return IOCONTEXT_NORMAL;
- case BAS_BULKREAD:
- return IOCONTEXT_BULKREAD;
- case BAS_BULKWRITE:
- return IOCONTEXT_BULKWRITE;
- case BAS_VACUUM:
- return IOCONTEXT_VACUUM;
- }
-
- elog(ERROR, "unrecognized BufferAccessStrategyType: %d", strategy->btype);
- pg_unreachable();
-}
-
-/*
- * StrategyRejectBuffer -- consider rejecting a dirty buffer
- *
- * When a nondefault strategy is used, the buffer manager calls this function
- * when it turns out that the buffer selected by StrategyGetBuffer needs to
- * be written out and doing so would require flushing WAL too. This gives us
- * a chance to choose a different victim.
- *
- * Returns true if buffer manager should ask for a new victim, and false
- * if this buffer should be written and re-used.
- */
-bool
-StrategyRejectBuffer(BufferAccessStrategy strategy, BufferDesc *buf, bool from_ring)
-{
- /* We only do this in bulkread mode */
- if (strategy->btype != BAS_BULKREAD)
- return false;
-
- /* Don't muck with behavior of normal buffer-replacement strategy */
- if (!from_ring ||
- strategy->buffers[strategy->current] != BufferDescriptorGetBuffer(buf))
- return false;
-
- /*
- * Remove the dirty buffer from the ring; necessary to prevent infinite
- * loop if all ring members are dirty.
+ * Batching claims a run of consecutive buffer IDs per atomic fetch-add so
+ * concurrent backends touch the shared nextVictimBuffer cache line ~1/batch
+ * as often -- a win only when that line actually bounces across sockets,
+ * i.e. on multi-node NUMA hardware. On a single socket the atomic is
+ * already node-local and batching would only make backends skip ahead for
+ * no benefit, so we fall back to batch size 1 there (byte-identical to the
+ * stock one-buffer-at-a-time clock sweep).
+ *
+ * Batch (> 1) only when libnuma reports more than one node
+ * (pg_numa_get_max_node() >= 1); pg_numa_init() returns -1 when NUMA is
+ * unavailable. (Benchmarking showed the win holds with or without huge
+ * pages, so huge-page availability is intentionally not part of the gate.)
*/
- strategy->buffers[strategy->current] = InvalidBuffer;
-
- return true;
+ if (pg_numa_init() != -1 &&
+ pg_numa_get_max_node() >= 1)
+ StrategyControl->batchSize = Min(PG_CACHE_LINE_SIZE / (uint32) sizeof(uint32),
+ (uint32) NBuffers);
+ else
+ StrategyControl->batchSize = 1;
}
diff --git a/src/backend/storage/buffer/localbuf.c b/src/backend/storage/buffer/localbuf.c
index 4870c8e13d010..21c08091c490b 100644
--- a/src/backend/storage/buffer/localbuf.c
+++ b/src/backend/storage/buffer/localbuf.c
@@ -167,7 +167,7 @@ LocalBufferAlloc(SMgrRelation smgr, ForkNumber forkNum, BlockNumber blockNum,
buf_state = pg_atomic_read_u64(&bufHdr->state);
buf_state &= ~(BUF_FLAG_MASK | BUF_USAGECOUNT_MASK);
- buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE;
+ buf_state |= BM_TAG_VALID; /* admit COOL (probation) */
pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state);
*foundPtr = false;
@@ -248,9 +248,10 @@ GetLocalVictimBuffer(void)
{
uint64 buf_state = pg_atomic_read_u64(&bufHdr->state);
- if (BUF_STATE_GET_USAGECOUNT(buf_state) > 0)
+ if (BUF_STATE_GET_COOLSTATE(buf_state) != BUF_COOLSTATE_COOL)
{
- buf_state -= BUF_USAGECOUNT_ONE;
+ /* HOT: give it a second chance, cool it and keep scanning. */
+ buf_state -= BUF_COOLSTATE_ONE;
pg_atomic_unlocked_write_u64(&bufHdr->state, buf_state);
trycounter = NLocBuffer;
}
@@ -454,7 +455,7 @@ ExtendBufferedRelLocal(BufferManagerRelation bmr,
victim_buf_hdr->tag = tag;
- buf_state |= BM_TAG_VALID | BUF_USAGECOUNT_ONE;
+ buf_state |= BM_TAG_VALID; /* admit COOL (probation) */
pg_atomic_unlocked_write_u64(&victim_buf_hdr->state, buf_state);
@@ -839,9 +840,9 @@ PinLocalBuffer(BufferDesc *buf_hdr, bool adjust_usagecount)
NLocalPinnedBuffers++;
buf_state += BUF_REFCOUNT_ONE;
if (adjust_usagecount &&
- BUF_STATE_GET_USAGECOUNT(buf_state) < BM_MAX_USAGE_COUNT)
+ BUF_STATE_GET_COOLSTATE(buf_state) < BUF_COOLSTATE_HOT)
{
- buf_state += BUF_USAGECOUNT_ONE;
+ buf_state += BUF_COOLSTATE_ONE;
}
pg_atomic_unlocked_write_u64(&buf_hdr->state, buf_state);
diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c
index 006edab9d77df..29cb2d70f66e4 100644
--- a/src/backend/storage/freespace/freespace.c
+++ b/src/backend/storage/freespace/freespace.c
@@ -603,7 +603,7 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
return InvalidBuffer;
}
else
- buf = ReadBufferExtended(rel, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR, NULL);
+ buf = ReadBufferExtended(rel, FSM_FORKNUM, blkno, RBM_ZERO_ON_ERROR);
/*
* Initializing the page when needed is trickier than it looks, because of
@@ -638,7 +638,7 @@ fsm_readbuf(Relation rel, FSMAddress addr, bool extend)
static Buffer
fsm_extend(Relation rel, BlockNumber fsm_nblocks)
{
- return ExtendBufferedRelTo(BMR_REL(rel), FSM_FORKNUM, NULL,
+ return ExtendBufferedRelTo(BMR_REL(rel), FSM_FORKNUM,
EB_CREATE_FORK_IF_NEEDED |
EB_CLEAR_SIZE_CACHE,
fsm_nblocks,
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 718c1cfc0f9df..3c3e35ab8a86f 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -1540,15 +1540,8 @@ register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
FilePathName(seg->mdfd_vfd))));
/*
- * We have no way of knowing if the current IOContext is
- * IOCONTEXT_NORMAL or IOCONTEXT_[BULKREAD, BULKWRITE, VACUUM] at this
- * point, so count the fsync as being in the IOCONTEXT_NORMAL
- * IOContext. This is probably okay, because the number of backend
- * fsyncs doesn't say anything about the efficacy of the
- * BufferAccessStrategy. And counting both fsyncs done in
- * IOCONTEXT_NORMAL and IOCONTEXT_[BULKREAD, BULKWRITE, VACUUM] under
- * IOCONTEXT_NORMAL is likely clearer when investigating the number of
- * backend fsyncs.
+ * Count the fsync in the IOCONTEXT_NORMAL IOContext, the only
+ * IOContext relations are read/written under.
*/
pgstat_count_io_op_time(IOOBJECT_RELATION, IOCONTEXT_NORMAL,
IOOP_FSYNC, io_start, 1, 0);
diff --git a/src/backend/utils/activity/pgstat_io.c b/src/backend/utils/activity/pgstat_io.c
index 38bae7b15d2ed..d66a23749d5a9 100644
--- a/src/backend/utils/activity/pgstat_io.c
+++ b/src/backend/utils/activity/pgstat_io.c
@@ -241,16 +241,10 @@ pgstat_get_io_context_name(IOContext io_context)
{
switch (io_context)
{
- case IOCONTEXT_BULKREAD:
- return "bulkread";
- case IOCONTEXT_BULKWRITE:
- return "bulkwrite";
case IOCONTEXT_INIT:
return "init";
case IOCONTEXT_NORMAL:
return "normal";
- case IOCONTEXT_VACUUM:
- return "vacuum";
}
elog(ERROR, "unrecognized IOContext value: %d", io_context);
@@ -451,18 +445,6 @@ pgstat_tracks_io_object(BackendType bktype, IOObject io_object,
* IOContexts, and, while it may not be inherently incorrect for them to
* do so, excluding those rows from the view makes the view easier to use.
*/
- if ((bktype == B_CHECKPOINTER || bktype == B_BG_WRITER) &&
- (io_context == IOCONTEXT_BULKREAD ||
- io_context == IOCONTEXT_BULKWRITE ||
- io_context == IOCONTEXT_VACUUM))
- return false;
-
- if (bktype == B_AUTOVAC_LAUNCHER && io_context == IOCONTEXT_VACUUM)
- return false;
-
- if ((bktype == B_AUTOVAC_WORKER || bktype == B_AUTOVAC_LAUNCHER) &&
- io_context == IOCONTEXT_BULKWRITE)
- return false;
return true;
}
@@ -479,8 +461,6 @@ bool
pgstat_tracks_io_op(BackendType bktype, IOObject io_object,
IOContext io_context, IOOp io_op)
{
- bool strategy_io_context;
-
/* if (io_context, io_object) will never collect stats, we're done */
if (!pgstat_tracks_io_object(bktype, io_object, io_context))
return false;
@@ -521,17 +501,13 @@ pgstat_tracks_io_op(BackendType bktype, IOObject io_object,
/*
* Some IOOps are not valid in certain IOContexts and some IOOps are only
* valid in certain contexts.
+ *
+ * IOOP_REUSE was only relevant when a BufferAccessStrategy was in use.
+ * Buffer access strategies (ring buffers) have been removed -- scan
+ * resistance is now intrinsic to the cooling-stage clock sweep -- so
+ * IOOP_REUSE never occurs.
*/
- if (io_context == IOCONTEXT_BULKREAD && io_op == IOOP_EXTEND)
- return false;
-
- strategy_io_context = io_context == IOCONTEXT_BULKREAD ||
- io_context == IOCONTEXT_BULKWRITE || io_context == IOCONTEXT_VACUUM;
-
- /*
- * IOOP_REUSE is only relevant when a BufferAccessStrategy is in use.
- */
- if (!strategy_io_context && io_op == IOOP_REUSE)
+ if (io_op == IOOP_REUSE)
return false;
/*
@@ -545,14 +521,5 @@ pgstat_tracks_io_op(BackendType bktype, IOObject io_object,
!(io_op == IOOP_WRITE || io_op == IOOP_READ || io_op == IOOP_FSYNC))
return false;
- /*
- * IOOP_FSYNC IOOps done by a backend using a BufferAccessStrategy are
- * counted in the IOCONTEXT_NORMAL IOContext. See comment in
- * register_dirty_segment() for more details.
- */
- if (strategy_io_context && io_op == IOOP_FSYNC)
- return false;
-
-
return true;
}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index bbd28d14d9948..555c04272f532 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -149,7 +149,6 @@ int autovacuum_max_parallel_workers = 0;
int MaxBackends = 0;
/* GUC parameters for vacuum */
-int VacuumBufferUsageLimit = 2048;
int VacuumCostPageHit = 1;
int VacuumCostPageMiss = 2;
diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat
index d421cdbde76da..b1ea81f536c99 100644
--- a/src/backend/utils/misc/guc_parameters.dat
+++ b/src/backend/utils/misc/guc_parameters.dat
@@ -3326,16 +3326,6 @@
boot_val => 'DEFAULT_UPDATE_PROCESS_TITLE',
},
-{ name => 'vacuum_buffer_usage_limit', type => 'int', context => 'PGC_USERSET', group => 'RESOURCES_MEM',
- short_desc => 'Sets the buffer pool size for VACUUM, ANALYZE, and autovacuum.',
- flags => 'GUC_UNIT_KB',
- variable => 'VacuumBufferUsageLimit',
- boot_val => '2048',
- min => '0',
- max => 'MAX_BAS_VAC_RING_SIZE_KB',
- check_hook => 'check_vacuum_buffer_usage_limit',
-},
-
{ name => 'vacuum_cost_delay', type => 'real', context => 'PGC_USERSET', group => 'VACUUM_COST_DELAY',
short_desc => 'Vacuum cost delay in milliseconds.',
flags => 'GUC_UNIT_MS',
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 7958653077b16..cb1eb8ef3ffbc 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -164,9 +164,6 @@
# mmap
# (change requires restart)
#min_dynamic_shared_memory = 0MB # (change requires restart)
-#vacuum_buffer_usage_limit = 2MB # size of vacuum and analyze buffer access strategy ring;
- # 0 to disable vacuum buffer access strategy;
- # range 128kB to 16GB
# SLRU buffers (change requires restart)
#commit_timestamp_buffers = 0 # memory for pg_commit_ts (0 = auto)
diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c
index f8158ca6a78fa..f78e57ff2c3e2 100644
--- a/src/bin/scripts/vacuumdb.c
+++ b/src/bin/scripts/vacuumdb.c
@@ -57,7 +57,6 @@ main(int argc, char *argv[])
{"no-truncate", no_argument, NULL, 10},
{"no-process-toast", no_argument, NULL, 11},
{"no-process-main", no_argument, NULL, 12},
- {"buffer-usage-limit", required_argument, NULL, 13},
{"missing-stats-only", no_argument, NULL, 14},
{"dry-run", no_argument, NULL, 15},
{NULL, 0, NULL, 0}
@@ -202,9 +201,6 @@ main(int argc, char *argv[])
case 12:
vacopts.process_main = false;
break;
- case 13:
- vacopts.buffer_usage_limit = escape_quotes(optarg);
- break;
case 14:
vacopts.missing_stats_only = true;
break;
@@ -290,14 +286,6 @@ main(int argc, char *argv[])
pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
"no-index-cleanup", "force-index-cleanup");
- /*
- * buffer-usage-limit is not allowed with VACUUM FULL unless ANALYZE is
- * included too.
- */
- if (vacopts.buffer_usage_limit && vacopts.full && !vacopts.and_analyze)
- pg_fatal("cannot use the \"%s\" option with the \"%s\" option",
- "buffer-usage-limit", "full");
-
/*
* Prohibit --missing-stats-only without --analyze-only or
* --analyze-in-stages.
@@ -352,7 +340,6 @@ help(const char *progname)
printf(_(" %s [OPTION]... [DBNAME]\n"), progname);
printf(_("\nOptions:\n"));
printf(_(" -a, --all vacuum all databases\n"));
- printf(_(" --buffer-usage-limit=SIZE size of ring buffer used for vacuum\n"));
printf(_(" -d, --dbname=DBNAME database to vacuum\n"));
printf(_(" --disable-page-skipping disable all page-skipping behavior\n"));
printf(_(" --dry-run show the commands that would be sent to the server\n"));
diff --git a/src/bin/scripts/vacuuming.c b/src/bin/scripts/vacuuming.c
index 855a5754c98c1..078a3bbb51681 100644
--- a/src/bin/scripts/vacuuming.c
+++ b/src/bin/scripts/vacuuming.c
@@ -264,13 +264,6 @@ vacuum_one_database(ConnParams *cparams,
"--parallel", "13");
}
- if (vacopts->buffer_usage_limit && PQserverVersion(conn) < 160000)
- {
- PQfinish(conn);
- pg_fatal("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
- "--buffer-usage-limit", "16");
- }
-
if (vacopts->missing_stats_only && PQserverVersion(conn) < 150000)
{
PQfinish(conn);
@@ -865,13 +858,6 @@ prepare_vacuum_command(PGconn *conn, PQExpBuffer sql,
appendPQExpBuffer(sql, "%sVERBOSE", sep);
sep = comma;
}
- if (vacopts->buffer_usage_limit)
- {
- Assert(serverVersion >= 160000);
- appendPQExpBuffer(sql, "%sBUFFER_USAGE_LIMIT '%s'", sep,
- vacopts->buffer_usage_limit);
- sep = comma;
- }
if (sep != paren)
appendPQExpBufferChar(sql, ')');
}
@@ -974,13 +960,6 @@ prepare_vacuum_command(PGconn *conn, PQExpBuffer sql,
vacopts->parallel_workers);
sep = comma;
}
- if (vacopts->buffer_usage_limit)
- {
- Assert(serverVersion >= 160000);
- appendPQExpBuffer(sql, "%sBUFFER_USAGE_LIMIT '%s'", sep,
- vacopts->buffer_usage_limit);
- sep = comma;
- }
if (sep != paren)
appendPQExpBufferChar(sql, ')');
}
diff --git a/src/bin/scripts/vacuuming.h b/src/bin/scripts/vacuuming.h
index 5a491db2526d7..83a2469a6aaf8 100644
--- a/src/bin/scripts/vacuuming.h
+++ b/src/bin/scripts/vacuuming.h
@@ -49,7 +49,6 @@ typedef struct vacuumingOptions
bool process_main;
bool process_toast;
bool skip_database_stats;
- char *buffer_usage_limit;
bool missing_stats_only;
bool echo;
bool quiet;
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 68bfe405db3a0..bc87f6f7cc0ed 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -58,7 +58,6 @@ typedef struct IndexVacuumInfo
bool estimated_count; /* num_heap_tuples is an estimate */
int message_level; /* ereport level for progress messages */
double num_heap_tuples; /* tuples remaining in heap */
- BufferAccessStrategy strategy; /* access strategy for reads */
} IndexVacuumInfo;
/*
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index a8702f0e5ea13..7c9268fe95370 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -405,12 +405,11 @@ extern void _hash_pgaddmultitup(Relation rel, Buffer buf, IndexTuple *itups,
extern Buffer _hash_addovflpage(Relation rel, Buffer metabuf, Buffer buf, bool retain_pin);
extern BlockNumber _hash_freeovflpage(Relation rel, Buffer bucketbuf, Buffer ovflbuf,
Buffer wbuf, IndexTuple *itups, OffsetNumber *itup_offsets,
- Size *tups_size, uint16 nitups, BufferAccessStrategy bstrategy);
+ Size *tups_size, uint16 nitups);
extern void _hash_initbitmapbuffer(Buffer buf, uint16 bmsize, bool initpage);
extern void _hash_squeezebucket(Relation rel,
Bucket bucket, BlockNumber bucket_blkno,
- Buffer bucket_buf,
- BufferAccessStrategy bstrategy);
+ Buffer bucket_buf);
extern uint32 _hash_ovflblkno_to_bitno(HashMetaPage metap, BlockNumber ovflblkno);
/* hashpage.c */
@@ -428,9 +427,6 @@ extern void _hash_initbuf(Buffer buf, uint32 max_bucket, uint32 num_bucket,
uint32 flag, bool initpage);
extern Buffer _hash_getnewbuf(Relation rel, BlockNumber blkno,
ForkNumber forkNum);
-extern Buffer _hash_getbuf_with_strategy(Relation rel, BlockNumber blkno,
- int access, int flags,
- BufferAccessStrategy bstrategy);
extern void _hash_relbuf(Relation rel, Buffer buf);
extern void _hash_dropbuf(Relation rel, Buffer buf);
extern void _hash_dropscanbuf(Relation rel, HashScanOpaque so);
@@ -481,7 +477,6 @@ extern void _hash_kill_items(IndexScanDesc scan);
/* hash.c */
extern void hashbucketcleanup(Relation rel, Bucket cur_bucket,
Buffer bucket_buf, BlockNumber bucket_blkno,
- BufferAccessStrategy bstrategy,
uint32 maxbucket, uint32 highmask, uint32 lowmask,
double *tuples_removed, double *num_index_tuples,
bool split_cleanup,
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h
index 5176478c29583..0967b659794c2 100644
--- a/src/include/access/heapam.h
+++ b/src/include/access/heapam.h
@@ -72,8 +72,6 @@ typedef struct HeapScanDescData
Buffer rs_cbuf; /* current buffer in scan, if any */
/* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */
- BufferAccessStrategy rs_strategy; /* access strategy for reads */
-
HeapTupleData rs_ctup; /* current tuple in scan, if any */
/* For scans that stream reads */
@@ -466,7 +464,7 @@ extern void log_heap_prune_and_freeze(Relation relation, Buffer buffer,
/* in heap/vacuumlazy.c */
extern void heap_vacuum_rel(Relation rel,
- const VacuumParams *params, BufferAccessStrategy bstrategy);
+ const VacuumParams *params);
#ifdef USE_ASSERT_CHECKING
extern bool heap_page_is_all_visible(Relation rel, Buffer buf,
GlobalVisState *vistest,
diff --git a/src/include/access/hio.h b/src/include/access/hio.h
index 60cfc375fd523..63bfcc884eea1 100644
--- a/src/include/access/hio.h
+++ b/src/include/access/hio.h
@@ -28,7 +28,6 @@
*/
typedef struct BulkInsertStateData
{
- BufferAccessStrategy strategy; /* our BULKWRITE strategy object */
Buffer current_buf; /* current insertion target page */
/*
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index f2c36696bcad0..83ba0f3ca730d 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -689,8 +689,7 @@ typedef struct TableAmRoutine
* integrate with autovacuum's scheduling.
*/
void (*relation_vacuum) (Relation rel,
- const VacuumParams *params,
- BufferAccessStrategy bstrategy);
+ const VacuumParams *params);
/*
* Prepare to analyze block `blockno` of `scan`. The scan has been started
@@ -1774,10 +1773,9 @@ table_relation_copy_for_cluster(Relation OldTable, Relation NewTable,
* routine, even if (for ANALYZE) it is part of the same VACUUM command.
*/
static inline void
-table_relation_vacuum(Relation rel, const VacuumParams *params,
- BufferAccessStrategy bstrategy)
+table_relation_vacuum(Relation rel, const VacuumParams *params)
{
- rel->rd_tableam->relation_vacuum(rel, params, bstrategy);
+ rel->rd_tableam->relation_vacuum(rel, params);
}
/*
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 956d9cea36da6..14a9b530bcf87 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -363,7 +363,7 @@ extern PGDLLIMPORT int64 parallel_vacuum_worker_delay_ns;
/* in commands/vacuum.c */
extern void ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel);
extern void vacuum(List *relations, const VacuumParams *params,
- BufferAccessStrategy bstrategy, MemoryContext vac_context,
+ MemoryContext vac_context,
bool isTopLevel);
extern void vac_open_indexes(Relation relation, LOCKMODE lockmode,
int *nindexes, Relation **Irel);
@@ -407,8 +407,7 @@ extern void VacuumUpdateCosts(void);
/* in commands/vacuumparallel.c */
extern ParallelVacuumState *parallel_vacuum_init(Relation rel, Relation *indrels,
int nindexes, int nrequested_workers,
- int vac_work_mem, int elevel,
- BufferAccessStrategy bstrategy);
+ int vac_work_mem, int elevel);
extern void parallel_vacuum_end(ParallelVacuumState *pvs, IndexBulkDeleteResult **istats);
extern TidStore *parallel_vacuum_get_dead_items(ParallelVacuumState *pvs,
VacDeadItemsInfo **dead_items_info_p);
@@ -428,8 +427,7 @@ extern void parallel_vacuum_main(dsm_segment *seg, shm_toc *toc);
/* in commands/analyze.c */
extern void analyze_rel(Oid relid, RangeVar *relation,
- const VacuumParams *params, List *va_cols, bool in_outer_xact,
- BufferAccessStrategy bstrategy);
+ const VacuumParams *params, List *va_cols, bool in_outer_xact);
extern bool attribute_is_analyzable(Relation onerel, int attnum, Form_pg_attribute attr,
int *p_attstattarget);
extern bool std_typanalyze(VacAttrStats *stats);
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 7170a4bff9896..c5d582b152b60 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -273,15 +273,6 @@ extern PGDLLIMPORT double hash_mem_multiplier;
extern PGDLLIMPORT int maintenance_work_mem;
extern PGDLLIMPORT int max_parallel_maintenance_workers;
-/*
- * Upper and lower hard limits for the buffer access strategy ring size
- * specified by the VacuumBufferUsageLimit GUC and BUFFER_USAGE_LIMIT option
- * to VACUUM and ANALYZE.
- */
-#define MIN_BAS_VAC_RING_SIZE_KB 128
-#define MAX_BAS_VAC_RING_SIZE_KB (16 * 1024 * 1024)
-
-extern PGDLLIMPORT int VacuumBufferUsageLimit;
extern PGDLLIMPORT int VacuumCostPageHit;
extern PGDLLIMPORT int VacuumCostPageMiss;
extern PGDLLIMPORT int VacuumCostPageDirty;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 58a44857f1311..68b4e5093a2bc 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -287,14 +287,11 @@ typedef enum IOObject
typedef enum IOContext
{
- IOCONTEXT_BULKREAD,
- IOCONTEXT_BULKWRITE,
IOCONTEXT_INIT,
IOCONTEXT_NORMAL,
- IOCONTEXT_VACUUM,
} IOContext;
-#define IOCONTEXT_NUM_TYPES (IOCONTEXT_VACUUM + 1)
+#define IOCONTEXT_NUM_TYPES (IOCONTEXT_NORMAL + 1)
/*
* Enumeration of IO operations.
diff --git a/src/include/storage/buf.h b/src/include/storage/buf.h
index b21445522b180..fa942a64f05a5 100644
--- a/src/include/storage/buf.h
+++ b/src/include/storage/buf.h
@@ -36,11 +36,4 @@ typedef int Buffer;
*/
#define BufferIsLocal(buffer) ((buffer) < 0)
-/*
- * Buffer access strategy objects.
- *
- * BufferAccessStrategyData is private to freelist.c
- */
-typedef struct BufferAccessStrategyData *BufferAccessStrategy;
-
#endif /* BUF_H */
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index e4ff5619b79ca..3b44ad3e0b67b 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -67,6 +67,50 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS + BUF_L
#define BUF_USAGECOUNT_ONE \
(UINT64CONST(1) << BUF_REFCOUNT_BITS)
+/*
+ * Cooling state (LeanStore / 2Q-A1 cooling-stage clock sweep).
+ *
+ * The field historically used for the 0..5 usage_count now holds a single
+ * cooling-state bit: HOT (recently accessed, not an eviction candidate) or
+ * COOL (an eviction candidate). We reuse BUF_USAGECOUNT_ONE as the unit so
+ * the buffer-state bit geography -- refcount, flag, and lock offsets, and the
+ * 64-bit StaticAsserts -- is unchanged; only the meaning of the field and the
+ * instructions that touch it change.
+ *
+ * A demand-loaded page is admitted COOL (probation); a second access promotes
+ * it to HOT (the rescue). The sweep prefers COOL victims and demotes HOT to
+ * COOL only when a full pass finds no COOL victim. So a one-touch scan fills
+ * and drains the COOL stage without displacing the HOT working set -- scan
+ * resistance intrinsic to the replacement algorithm.
+ */
+#define BUF_COOLSTATE_COOL 0
+#define BUF_COOLSTATE_HOT 1
+#define BUF_COOLSTATE_ONE BUF_USAGECOUNT_ONE
+
+/*
+ * Second-chance reference bit, bit 1 of the (former usagecount) field, one
+ * position above the cooling-state bit. PinBuffer sets it on every access.
+ * The bgwriter's pre-cooling gives a HOT buffer a second chance: the first
+ * time it passes a HOT buffer whose ref bit is set, it clears the ref bit and
+ * leaves the buffer HOT; only a HOT buffer whose ref bit is already clear (not
+ * re-accessed since the previous bgwriter pass) is demoted to COOL. This
+ * keeps genuinely-hot pages out of the COOL stage (protecting the working set
+ * from being cooled under scan pressure) while leaving the foreground sweep a
+ * single-pass search over the pre-staged COOL buffers. A separate bit (not a
+ * count) so it stays a plain masked store under the header lock.
+ */
+#define BUF_REFBIT (UINT64CONST(2) << BUF_REFCOUNT_BITS)
+#define BUF_STATE_GET_REFBIT(state) (((state) & BUF_REFBIT) != 0)
+
+/*
+ * The cooling state occupies bit 0 and the reference bit occupies bit 1 of
+ * the (former usagecount) field, so the field must be at least 2 bits wide.
+ * Assert it here so a future change to BUF_USAGECOUNT_BITS cannot silently
+ * push BUF_REFBIT up into the flag bits.
+ */
+StaticAssertDecl(BUF_USAGECOUNT_BITS >= 2,
+ "cooling state + reference bit need at least 2 bits in the usagecount field");
+
/* flags related definitions */
#define BUF_FLAG_SHIFT \
(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS)
@@ -92,6 +136,11 @@ StaticAssertDecl(BUF_REFCOUNT_BITS + BUF_USAGECOUNT_BITS + BUF_FLAG_BITS + BUF_L
#define BUF_STATE_GET_USAGECOUNT(state) \
((uint32)(((state) & BUF_USAGECOUNT_MASK) >> BUF_USAGECOUNT_SHIFT))
+/* Cooling state (HOT/COOL) from buffer state -- bit 0 of the field only, so
+ * the second-chance ref bit (bit 1) does not perturb the HOT/COOL test. */
+#define BUF_STATE_GET_COOLSTATE(state) \
+ ((uint32) (((state) >> BUF_USAGECOUNT_SHIFT) & 1))
+
/*
* Flags for buffer descriptors
*
@@ -134,17 +183,15 @@ StaticAssertDecl(MAX_BACKENDS_BITS <= (BUF_LOCK_BITS - 2),
/*
- * The maximum allowed value of usage_count represents a tradeoff between
- * accuracy and speed of the clock-sweep buffer management algorithm. A
- * large value (comparable to NBuffers) would approximate LRU semantics.
- * But it can take as many as BM_MAX_USAGE_COUNT+1 complete cycles of the
- * clock-sweep hand to find a free buffer, so in practice we don't want the
- * value to be very large.
+ * The cooling state is a single bit (HOT/COOL); the maximum value stored in
+ * the field is therefore BUF_COOLSTATE_HOT. Retained under the historical
+ * name BM_MAX_USAGE_COUNT so the pin fast path ("promote unless already at
+ * max") reads naturally.
*/
-#define BM_MAX_USAGE_COUNT 5
+#define BM_MAX_USAGE_COUNT BUF_COOLSTATE_HOT
StaticAssertDecl(BM_MAX_USAGE_COUNT < (UINT64CONST(1) << BUF_USAGECOUNT_BITS),
- "BM_MAX_USAGE_COUNT doesn't fit in BUF_USAGECOUNT_BITS bits");
+ "cooling state doesn't fit in BUF_USAGECOUNT_BITS bits");
/*
* Buffer tag identifies which disk block the buffer contains.
@@ -585,11 +632,7 @@ extern void TerminateBufferIO(BufferDesc *buf, bool clear_dirty, uint64 set_flag
/* freelist.c */
-extern IOContext IOContextForStrategy(BufferAccessStrategy strategy);
-extern BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy,
- uint64 *buf_state, bool *from_ring);
-extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
- BufferDesc *buf, bool from_ring);
+extern BufferDesc *StrategyGetBuffer(uint64 *buf_state);
extern int StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc);
extern void StrategyNotifyBgWriter(int bgwprocno);
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 6837b35fc6d0b..36023792f3611 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -25,21 +25,6 @@
typedef void *Block;
-/*
- * Possible arguments for GetAccessStrategy().
- *
- * If adding a new BufferAccessStrategyType, also add a new IOContext so
- * IO statistics using this strategy are tracked.
- */
-typedef enum BufferAccessStrategyType
-{
- BAS_NORMAL, /* Normal random access */
- BAS_BULKREAD, /* Large read-only scan (hint bit updates are
- * ok) */
- BAS_BULKWRITE, /* Large multi-block write (e.g. COPY IN) */
- BAS_VACUUM, /* VACUUM */
-} BufferAccessStrategyType;
-
/* Possible modes for ReadBufferExtended() */
typedef enum
{
@@ -135,7 +120,6 @@ struct ReadBuffersOperation
SMgrRelation smgr;
char persistence;
ForkNumber forknum;
- BufferAccessStrategy strategy;
/*
* The following private members are private state for communication
@@ -235,11 +219,10 @@ extern bool ReadRecentBuffer(RelFileLocator rlocator, ForkNumber forkNum,
BlockNumber blockNum, Buffer recent_buffer);
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
- BlockNumber blockNum, ReadBufferMode mode,
- BufferAccessStrategy strategy);
+ BlockNumber blockNum, ReadBufferMode mode);
extern Buffer ReadBufferWithoutRelcache(RelFileLocator rlocator,
ForkNumber forkNum, BlockNumber blockNum,
- ReadBufferMode mode, BufferAccessStrategy strategy,
+ ReadBufferMode mode,
bool permanent);
extern bool StartReadBuffer(ReadBuffersOperation *operation,
@@ -266,18 +249,15 @@ extern Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation,
extern Buffer ExtendBufferedRel(BufferManagerRelation bmr,
ForkNumber forkNum,
- BufferAccessStrategy strategy,
uint32 flags);
extern BlockNumber ExtendBufferedRelBy(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
uint32 extend_by,
Buffer *buffers,
uint32 *extended_by);
extern Buffer ExtendBufferedRelTo(BufferManagerRelation bmr,
ForkNumber fork,
- BufferAccessStrategy strategy,
uint32 flags,
BlockNumber extend_to,
ReadBufferMode mode);
@@ -376,14 +356,6 @@ extern void AtProcExit_LocalBuffers(void);
/* in freelist.c */
-extern BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype);
-extern BufferAccessStrategy GetAccessStrategyWithSize(BufferAccessStrategyType btype,
- int ring_size_kb);
-extern int GetAccessStrategyBufferCount(BufferAccessStrategy strategy);
-extern int GetAccessStrategyPinLimit(BufferAccessStrategy strategy);
-
-extern void FreeAccessStrategy(BufferAccessStrategy strategy);
-
/* inline functions */
diff --git a/src/include/storage/read_stream.h b/src/include/storage/read_stream.h
index 48995c6d534bd..9e5fbbed9e866 100644
--- a/src/include/storage/read_stream.h
+++ b/src/include/storage/read_stream.h
@@ -83,17 +83,14 @@ extern BlockNumber block_range_read_stream_cb(ReadStream *stream,
void *callback_private_data,
void *per_buffer_data);
extern ReadStream *read_stream_begin_relation(int flags,
- BufferAccessStrategy strategy,
Relation rel,
ForkNumber forknum,
ReadStreamBlockNumberCB callback,
void *callback_private_data,
size_t per_buffer_data_size);
extern Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data);
-extern BlockNumber read_stream_next_block(ReadStream *stream,
- BufferAccessStrategy *strategy);
+extern BlockNumber read_stream_next_block(ReadStream *stream);
extern ReadStream *read_stream_begin_smgr_relation(int flags,
- BufferAccessStrategy strategy,
SMgrRelation smgr,
char smgr_persistence,
ForkNumber forknum,
diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h
index 307f4fbaefe08..3f28558d47c6d 100644
--- a/src/include/utils/guc_hooks.h
+++ b/src/include/utils/guc_hooks.h
@@ -31,8 +31,6 @@ extern void assign_application_name(const char *newval, void *extra);
extern const char *show_archive_command(void);
extern bool check_autovacuum_work_mem(int *newval, void **extra,
GucSource source);
-extern bool check_vacuum_buffer_usage_limit(int *newval, void **extra,
- GucSource source);
extern bool check_backtrace_functions(char **newval, void **extra,
GucSource source);
extern void assign_backtrace_functions(const char *newval, void *extra);
diff --git a/src/test/modules/test_aio/test_aio.c b/src/test/modules/test_aio/test_aio.c
index 6270775af7ca2..8d7b2a728d680 100644
--- a/src/test/modules/test_aio/test_aio.c
+++ b/src/test/modules/test_aio/test_aio.c
@@ -194,7 +194,6 @@ grow_rel(PG_FUNCTION_ARGS)
ExtendBufferedRelBy(BMR_REL(rel),
MAIN_FORKNUM,
- NULL,
0,
extend_by_pages,
victim_buffers,
@@ -231,7 +230,7 @@ modify_rel_block(PG_FUNCTION_ARGS)
rel = relation_open(relid, AccessExclusiveLock);
buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno,
- RBM_ZERO_ON_ERROR, NULL);
+ RBM_ZERO_ON_ERROR);
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
@@ -331,7 +330,7 @@ create_toy_buffer(Relation rel, BlockNumber blkno)
uint64 unset_bits = 0;
/* place buffer in shared buffers without erroring out */
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK, NULL);
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_ZERO_AND_LOCK);
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
if (RelationUsesLocalBuffers(rel))
@@ -737,7 +736,6 @@ read_buffers(PG_FUNCTION_ARGS)
operation->rel = rel;
operation->smgr = smgr;
operation->persistence = rel->rd_rel->relpersistence;
- operation->strategy = NULL;
operation->forknum = MAIN_FORKNUM;
io_reqds[nios] = StartReadBuffers(operation,
@@ -879,7 +877,6 @@ read_stream_for_blocks(PG_FUNCTION_ARGS)
rel = relation_open(relid, AccessShareLock);
stream = read_stream_begin_relation(READ_STREAM_FULL,
- NULL,
rel,
MAIN_FORKNUM,
read_stream_for_blocks_cb,
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 03cbc1cdef59e..beb876c48b4fb 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -16,22 +16,16 @@ SHOW track_counts; -- must be on
SELECT backend_type, object, context FROM pg_stat_io
ORDER BY backend_type COLLATE "C", object COLLATE "C", context COLLATE "C";
backend_type|object|context
-autovacuum launcher|relation|bulkread
autovacuum launcher|relation|init
autovacuum launcher|relation|normal
autovacuum launcher|wal|init
autovacuum launcher|wal|normal
-autovacuum worker|relation|bulkread
autovacuum worker|relation|init
autovacuum worker|relation|normal
-autovacuum worker|relation|vacuum
autovacuum worker|wal|init
autovacuum worker|wal|normal
-background worker|relation|bulkread
-background worker|relation|bulkwrite
background worker|relation|init
background worker|relation|normal
-background worker|relation|vacuum
background worker|temp relation|normal
background worker|wal|init
background worker|wal|normal
@@ -43,67 +37,43 @@ checkpointer|relation|init
checkpointer|relation|normal
checkpointer|wal|init
checkpointer|wal|normal
-client backend|relation|bulkread
-client backend|relation|bulkwrite
client backend|relation|init
client backend|relation|normal
-client backend|relation|vacuum
client backend|temp relation|normal
client backend|wal|init
client backend|wal|normal
-datachecksums launcher|relation|bulkread
-datachecksums launcher|relation|bulkwrite
datachecksums launcher|relation|init
datachecksums launcher|relation|normal
-datachecksums launcher|relation|vacuum
datachecksums launcher|temp relation|normal
datachecksums launcher|wal|init
datachecksums launcher|wal|normal
-datachecksums worker|relation|bulkread
-datachecksums worker|relation|bulkwrite
datachecksums worker|relation|init
datachecksums worker|relation|normal
-datachecksums worker|relation|vacuum
datachecksums worker|temp relation|normal
datachecksums worker|wal|init
datachecksums worker|wal|normal
-io worker|relation|bulkread
-io worker|relation|bulkwrite
io worker|relation|init
io worker|relation|normal
-io worker|relation|vacuum
io worker|temp relation|normal
io worker|wal|init
io worker|wal|normal
-slotsync worker|relation|bulkread
-slotsync worker|relation|bulkwrite
slotsync worker|relation|init
slotsync worker|relation|normal
-slotsync worker|relation|vacuum
slotsync worker|temp relation|normal
slotsync worker|wal|init
slotsync worker|wal|normal
-standalone backend|relation|bulkread
-standalone backend|relation|bulkwrite
standalone backend|relation|init
standalone backend|relation|normal
-standalone backend|relation|vacuum
standalone backend|wal|init
standalone backend|wal|normal
-startup|relation|bulkread
-startup|relation|bulkwrite
startup|relation|init
startup|relation|normal
-startup|relation|vacuum
startup|wal|init
startup|wal|normal
walreceiver|wal|init
walreceiver|wal|normal
-walsender|relation|bulkread
-walsender|relation|bulkwrite
walsender|relation|init
walsender|relation|normal
-walsender|relation|vacuum
walsender|temp relation|normal
walsender|wal|init
walsender|wal|normal
@@ -111,7 +81,7 @@ walsummarizer|wal|init
walsummarizer|wal|normal
walwriter|wal|init
walwriter|wal|normal
-(95 rows)
+(65 rows)
\a
-- List of registered statistics kinds.
SELECT id, name, fixed_amount,
@@ -1757,80 +1727,20 @@ SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes;
(1 row)
RESET temp_buffers;
--- Test that reuse of strategy buffers and reads of blocks into these reused
--- buffers while VACUUMing are tracked in pg_stat_io. If there is sufficient
--- demand for shared buffers from concurrent queries, some buffers may be
--- pinned by other backends before they can be reused. In such cases, the
--- backend will evict a buffer from outside the ring and add it to the
--- ring. This is considered an eviction and not a reuse.
--- Set wal_skip_threshold smaller than the expected size of
--- test_io_vac_strategy so that, even if wal_level is minimal, VACUUM FULL will
--- fsync the newly rewritten test_io_vac_strategy instead of writing it to WAL.
--- Writing it to WAL will result in the newly written relation pages being in
--- shared buffers -- preventing us from testing BAS_VACUUM BufferAccessStrategy
--- reads.
-SET wal_skip_threshold = '1 kB';
-SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions
- FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_
-CREATE TABLE test_io_vac_strategy(a int, b int) WITH (autovacuum_enabled = 'false');
-INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 4500)i;
--- Ensure that the next VACUUM will need to perform IO by rewriting the table
--- first with VACUUM (FULL).
-VACUUM (FULL) test_io_vac_strategy;
--- Use the minimum BUFFER_USAGE_LIMIT to cause reuses or evictions with the
--- smallest table possible.
-VACUUM (PARALLEL 0, BUFFER_USAGE_LIMIT 128) test_io_vac_strategy;
-SELECT pg_stat_force_next_flush();
- pg_stat_force_next_flush
---------------------------
-
-(1 row)
-
-SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions
- FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_
-SELECT :io_sum_vac_strategy_after_reads > :io_sum_vac_strategy_before_reads;
- ?column?
-----------
- t
-(1 row)
-
-SELECT (:io_sum_vac_strategy_after_reuses + :io_sum_vac_strategy_after_evictions) >
- (:io_sum_vac_strategy_before_reuses + :io_sum_vac_strategy_before_evictions);
- ?column?
-----------
- t
-(1 row)
-
-RESET wal_skip_threshold;
--- Test that extends done by a CTAS, which uses a BAS_BULKWRITE
--- BufferAccessStrategy, are tracked in pg_stat_io.
-SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_before
- FROM pg_stat_io WHERE context = 'bulkwrite' \gset
-CREATE TABLE test_io_bulkwrite_strategy AS SELECT i FROM generate_series(1,100)i;
-SELECT pg_stat_force_next_flush();
- pg_stat_force_next_flush
---------------------------
-
-(1 row)
-
-SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_after
- FROM pg_stat_io WHERE context = 'bulkwrite' \gset
-SELECT :io_sum_bulkwrite_strategy_extends_after > :io_sum_bulkwrite_strategy_extends_before;
- ?column?
-----------
- t
-(1 row)
-
-- Test IO stats reset
+-- Note: reuses is intentionally excluded from these totals. With the
+-- BufferAccessStrategy ring buffers removed, IOOP_REUSE is never tracked, so
+-- the reuses column is NULL for every row; summing it would make the whole
+-- total NULL.
SELECT pg_stat_have_stats('io', 0, 0);
pg_stat_have_stats
--------------------
t
(1 row)
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset
FROM pg_stat_io \gset
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_pre_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_pre_reset
FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
SELECT pg_stat_reset_shared('io');
pg_stat_reset_shared
@@ -1838,7 +1748,7 @@ SELECT pg_stat_reset_shared('io');
(1 row)
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset
FROM pg_stat_io \gset
SELECT :io_stats_post_reset < :io_stats_pre_reset;
?column?
@@ -1846,7 +1756,7 @@ SELECT :io_stats_post_reset < :io_stats_pre_reset;
t
(1 row)
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_reset
FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
-- pg_stat_reset_shared() did not reset backend IO stats
SELECT :my_io_stats_pre_reset <= :my_io_stats_post_reset;
@@ -1862,7 +1772,7 @@ SELECT pg_stat_reset_backend_stats(pg_backend_pid());
(1 row)
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_backend_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_backend_reset
FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
SELECT :my_io_stats_pre_reset > :my_io_stats_post_backend_reset;
?column?
diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out
index d4696bc332557..85d06907cec0f 100644
--- a/src/test/regress/expected/vacuum.out
+++ b/src/test/regress/expected/vacuum.out
@@ -526,25 +526,6 @@ SELECT t.relfilenode = :toast_filenode AS is_same_toast_filenode
f
(1 row)
--- BUFFER_USAGE_LIMIT option
-VACUUM (BUFFER_USAGE_LIMIT '512 kB') vac_option_tab;
-ANALYZE (BUFFER_USAGE_LIMIT '512 kB') vac_option_tab;
--- try disabling the buffer usage limit
-VACUUM (BUFFER_USAGE_LIMIT 0) vac_option_tab;
-ANALYZE (BUFFER_USAGE_LIMIT 0) vac_option_tab;
--- value exceeds max size error
-VACUUM (BUFFER_USAGE_LIMIT 16777220) vac_option_tab;
-ERROR: BUFFER_USAGE_LIMIT option must be 0 or between 128 kB and 16777216 kB
--- value is less than min size error
-VACUUM (BUFFER_USAGE_LIMIT 120) vac_option_tab;
-ERROR: BUFFER_USAGE_LIMIT option must be 0 or between 128 kB and 16777216 kB
--- integer overflow error
-VACUUM (BUFFER_USAGE_LIMIT 10000000000) vac_option_tab;
-ERROR: BUFFER_USAGE_LIMIT option must be 0 or between 128 kB and 16777216 kB
-HINT: Value exceeds integer range.
--- incompatible with VACUUM FULL error
-VACUUM (BUFFER_USAGE_LIMIT '512 kB', FULL) vac_option_tab;
-ERROR: BUFFER_USAGE_LIMIT cannot be specified for VACUUM FULL
-- SKIP_DATABASE_STATS option
VACUUM (SKIP_DATABASE_STATS) vactst;
-- ONLY_DATABASE_STATS option
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 4c265d1245c72..4eb48114e80fa 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -814,65 +814,27 @@ SELECT sum(writes) AS io_sum_local_new_tblspc_writes
SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes;
RESET temp_buffers;
--- Test that reuse of strategy buffers and reads of blocks into these reused
--- buffers while VACUUMing are tracked in pg_stat_io. If there is sufficient
--- demand for shared buffers from concurrent queries, some buffers may be
--- pinned by other backends before they can be reused. In such cases, the
--- backend will evict a buffer from outside the ring and add it to the
--- ring. This is considered an eviction and not a reuse.
-
--- Set wal_skip_threshold smaller than the expected size of
--- test_io_vac_strategy so that, even if wal_level is minimal, VACUUM FULL will
--- fsync the newly rewritten test_io_vac_strategy instead of writing it to WAL.
--- Writing it to WAL will result in the newly written relation pages being in
--- shared buffers -- preventing us from testing BAS_VACUUM BufferAccessStrategy
--- reads.
-SET wal_skip_threshold = '1 kB';
-SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions
- FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_
-CREATE TABLE test_io_vac_strategy(a int, b int) WITH (autovacuum_enabled = 'false');
-INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 4500)i;
--- Ensure that the next VACUUM will need to perform IO by rewriting the table
--- first with VACUUM (FULL).
-VACUUM (FULL) test_io_vac_strategy;
--- Use the minimum BUFFER_USAGE_LIMIT to cause reuses or evictions with the
--- smallest table possible.
-VACUUM (PARALLEL 0, BUFFER_USAGE_LIMIT 128) test_io_vac_strategy;
-SELECT pg_stat_force_next_flush();
-SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions
- FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_
-SELECT :io_sum_vac_strategy_after_reads > :io_sum_vac_strategy_before_reads;
-SELECT (:io_sum_vac_strategy_after_reuses + :io_sum_vac_strategy_after_evictions) >
- (:io_sum_vac_strategy_before_reuses + :io_sum_vac_strategy_before_evictions);
-RESET wal_skip_threshold;
-
--- Test that extends done by a CTAS, which uses a BAS_BULKWRITE
--- BufferAccessStrategy, are tracked in pg_stat_io.
-SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_before
- FROM pg_stat_io WHERE context = 'bulkwrite' \gset
-CREATE TABLE test_io_bulkwrite_strategy AS SELECT i FROM generate_series(1,100)i;
-SELECT pg_stat_force_next_flush();
-SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_after
- FROM pg_stat_io WHERE context = 'bulkwrite' \gset
-SELECT :io_sum_bulkwrite_strategy_extends_after > :io_sum_bulkwrite_strategy_extends_before;
-
-- Test IO stats reset
+-- Note: reuses is intentionally excluded from these totals. With the
+-- BufferAccessStrategy ring buffers removed, IOOP_REUSE is never tracked, so
+-- the reuses column is NULL for every row; summing it would make the whole
+-- total NULL.
SELECT pg_stat_have_stats('io', 0, 0);
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset
FROM pg_stat_io \gset
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_pre_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_pre_reset
FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
SELECT pg_stat_reset_shared('io');
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset
FROM pg_stat_io \gset
SELECT :io_stats_post_reset < :io_stats_pre_reset;
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_reset
FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
-- pg_stat_reset_shared() did not reset backend IO stats
SELECT :my_io_stats_pre_reset <= :my_io_stats_post_reset;
-- but pg_stat_reset_backend_stats() does
SELECT pg_stat_reset_backend_stats(pg_backend_pid());
-SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_backend_reset
+SELECT sum(evictions) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_backend_reset
FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
SELECT :my_io_stats_pre_reset > :my_io_stats_post_backend_reset;
diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql
index 247b8e23b2357..506c438976552 100644
--- a/src/test/regress/sql/vacuum.sql
+++ b/src/test/regress/sql/vacuum.sql
@@ -390,21 +390,6 @@ SELECT t.relfilenode = :toast_filenode AS is_same_toast_filenode
FROM pg_class c, pg_class t
WHERE c.reltoastrelid = t.oid AND c.relname = 'vac_option_tab';
--- BUFFER_USAGE_LIMIT option
-VACUUM (BUFFER_USAGE_LIMIT '512 kB') vac_option_tab;
-ANALYZE (BUFFER_USAGE_LIMIT '512 kB') vac_option_tab;
--- try disabling the buffer usage limit
-VACUUM (BUFFER_USAGE_LIMIT 0) vac_option_tab;
-ANALYZE (BUFFER_USAGE_LIMIT 0) vac_option_tab;
--- value exceeds max size error
-VACUUM (BUFFER_USAGE_LIMIT 16777220) vac_option_tab;
--- value is less than min size error
-VACUUM (BUFFER_USAGE_LIMIT 120) vac_option_tab;
--- integer overflow error
-VACUUM (BUFFER_USAGE_LIMIT 10000000000) vac_option_tab;
--- incompatible with VACUUM FULL error
-VACUUM (BUFFER_USAGE_LIMIT '512 kB', FULL) vac_option_tab;
-
-- SKIP_DATABASE_STATS option
VACUUM (SKIP_DATABASE_STATS) vactst;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 56c1f997f88b1..064a9878e7276 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -355,8 +355,6 @@ BtreeLevel
Bucket
BufFile
Buffer
-BufferAccessStrategy
-BufferAccessStrategyType
BufferCacheOsPagesContext
BufferCacheOsPagesRec
BufferDesc