From 2e46bf67114586835f4a9908f1a1f08ee8ba83a8 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Tue, 13 Mar 2012 09:51:03 -0400
Subject: [PATCH] pgstattuple: Use a BufferAccessStrategy object to avoid
 cache-trashing.

Jaime Casanova, reviewed by Noah Misch, slightly modified by me.
---
 contrib/pgstattuple/pgstatindex.c |  5 ++--
 contrib/pgstattuple/pgstattuple.c | 42 +++++++++++++++++++++----------
 2 files changed, 32 insertions(+), 15 deletions(-)

diff --git a/contrib/pgstattuple/pgstatindex.c b/contrib/pgstattuple/pgstatindex.c
index beff1b9855b..9f2ec1f2108 100644
--- a/contrib/pgstattuple/pgstatindex.c
+++ b/contrib/pgstattuple/pgstatindex.c
@@ -95,6 +95,7 @@ pgstatindex(PG_FUNCTION_ARGS)
 	BlockNumber nblocks;
 	BlockNumber blkno;
 	BTIndexStat indexStat;
+ 	BufferAccessStrategy bstrategy = GetAccessStrategy(BAS_BULKREAD);
 
 	if (!superuser())
 		ereport(ERROR,
@@ -122,7 +123,7 @@ pgstatindex(PG_FUNCTION_ARGS)
 	 * Read metapage
 	 */
 	{
-		Buffer		buffer = ReadBuffer(rel, 0);
+		Buffer		buffer = ReadBufferExtended(rel, MAIN_FORKNUM, 0, RBM_NORMAL, bstrategy);
 		Page		page = BufferGetPage(buffer);
 		BTMetaPageData *metad = BTPageGetMeta(page);
 
@@ -159,7 +160,7 @@ pgstatindex(PG_FUNCTION_ARGS)
 		CHECK_FOR_INTERRUPTS();
 
 		/* Read and lock buffer */
-		buffer = ReadBuffer(rel, blkno);
+ 		buffer = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
 		LockBuffer(buffer, BUFFER_LOCK_SHARE);
 
 		page = BufferGetPage(buffer);
diff --git a/contrib/pgstattuple/pgstattuple.c b/contrib/pgstattuple/pgstattuple.c
index 7af724f24bb..c9be8c92e4b 100644
--- a/contrib/pgstattuple/pgstattuple.c
+++ b/contrib/pgstattuple/pgstattuple.c
@@ -61,18 +61,22 @@ typedef struct pgstattuple_type
 	uint64		free_space;		/* free/reusable space in bytes */
 } pgstattuple_type;
 
-typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber);
+typedef void (*pgstat_page) (pgstattuple_type *, Relation, BlockNumber,
+							 BufferAccessStrategy);
 
 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);
+				  Relation rel, BlockNumber blkno,
+				  BufferAccessStrategy bstrategy);
 static void pgstat_hash_page(pgstattuple_type *stat,
-				 Relation rel, BlockNumber blkno);
+				 Relation rel, BlockNumber blkno,
+				 BufferAccessStrategy bstrategy);
 static void pgstat_gist_page(pgstattuple_type *stat,
-				 Relation rel, BlockNumber blkno);
+				 Relation rel, BlockNumber blkno,
+				 BufferAccessStrategy bstrategy);
 static Datum pgstat_index(Relation rel, BlockNumber start,
 			 pgstat_page pagefn, FunctionCallInfo fcinfo);
 static void pgstat_index_page(pgstattuple_type *stat, Page page,
@@ -273,12 +277,17 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 	BlockNumber tupblock;
 	Buffer		buffer;
 	pgstattuple_type stat = {0};
+	BufferAccessStrategy bstrategy;
 
 	/* Disable syncscan because we assume we scan from block zero upwards */
 	scan = heap_beginscan_strat(rel, SnapshotAny, 0, NULL, true, false);
 
 	nblocks = scan->rs_nblocks; /* # blocks to be scanned */
 
+	/* prepare access strategy for this table */
+	bstrategy = GetAccessStrategy(BAS_BULKREAD);
+	scan->rs_strategy = bstrategy;
+
 	/* scan the relation */
 	while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
 	{
@@ -312,7 +321,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 		{
 			CHECK_FOR_INTERRUPTS();
 
-			buffer = ReadBuffer(rel, block);
+			buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block, RBM_NORMAL, bstrategy);
 			LockBuffer(buffer, BUFFER_LOCK_SHARE);
 			stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer));
 			UnlockReleaseBuffer(buffer);
@@ -325,7 +334,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
 	{
 		CHECK_FOR_INTERRUPTS();
 
-		buffer = ReadBuffer(rel, block);
+		buffer = ReadBufferExtended(rel, MAIN_FORKNUM, block, RBM_NORMAL, bstrategy);
 		LockBuffer(buffer, BUFFER_LOCK_SHARE);
 		stat.free_space += PageGetHeapFreeSpace((Page) BufferGetPage(buffer));
 		UnlockReleaseBuffer(buffer);
@@ -343,12 +352,13 @@ 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)
+pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
+				  BufferAccessStrategy bstrategy)
 {
 	Buffer		buf;
 	Page		page;
 
-	buf = ReadBuffer(rel, blkno);
+	buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
 	LockBuffer(buf, BT_READ);
 	page = BufferGetPage(buf);
 
@@ -386,13 +396,14 @@ 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)
+pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
+				 BufferAccessStrategy bstrategy)
 {
 	Buffer		buf;
 	Page		page;
 
 	_hash_getlock(rel, blkno, HASH_SHARE);
-	buf = _hash_getbuf(rel, blkno, HASH_READ, 0);
+	buf = _hash_getbuf_with_strategy(rel, blkno, HASH_READ, 0, bstrategy);
 	page = BufferGetPage(buf);
 
 	if (PageGetSpecialSize(page) == MAXALIGN(sizeof(HashPageOpaqueData)))
@@ -429,12 +440,13 @@ 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)
+pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno,
+				 BufferAccessStrategy bstrategy)
 {
 	Buffer		buf;
 	Page		page;
 
-	buf = ReadBuffer(rel, blkno);
+	buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL, bstrategy);
 	LockBuffer(buf, GIST_SHARE);
 	gistcheckpage(rel, buf);
 	page = BufferGetPage(buf);
@@ -461,8 +473,12 @@ 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 (;;)
 	{
@@ -483,7 +499,7 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
 		{
 			CHECK_FOR_INTERRUPTS();
 
-			pagefn(&stat, rel, blkno);
+			pagefn(&stat, rel, blkno, bstrategy);
 		}
 	}
 
-- 
GitLab