diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2023-04-07 14:25:45 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2023-04-07 14:25:53 -0400 |
commit | f3fa31327ecba75ee0e946abaa56dbf471ba704b (patch) | |
tree | aeb9141330c50f171f475a8f14c22d3a427adf3c /contrib | |
parent | e056c557aef4006c3dfbf8a4b94b7ae88eb9fd67 (diff) | |
download | postgresql-f3fa31327ecba75ee0e946abaa56dbf471ba704b.tar.gz |
Add pg_buffercache_usage_counts() to contrib/pg_buffercache.
It was pointed out that pg_buffercache_summary()'s report of
the overall average usage count isn't that useful, and what
would be more helpful in many cases is to report totals for
each possible usage count. Add a new function to do it like
that. Since pg_buffercache 1.4 is already new for v16,
we don't need to create a new extension version; we'll just
define this as part of 1.4.
Nathan Bossart
Discussion: https://postgr.es/m/20230130233040.GA2800702@nathanxps13
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/pg_buffercache/expected/pg_buffercache.out | 14 | ||||
-rw-r--r-- | contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql | 11 | ||||
-rw-r--r-- | contrib/pg_buffercache/pg_buffercache_pages.c | 43 | ||||
-rw-r--r-- | contrib/pg_buffercache/sql/pg_buffercache.sql | 4 |
4 files changed, 72 insertions, 0 deletions
diff --git a/contrib/pg_buffercache/expected/pg_buffercache.out b/contrib/pg_buffercache/expected/pg_buffercache.out index 635f01e3b2..b745dc69ea 100644 --- a/contrib/pg_buffercache/expected/pg_buffercache.out +++ b/contrib/pg_buffercache/expected/pg_buffercache.out @@ -17,6 +17,12 @@ from pg_buffercache_summary(); t | t | t (1 row) +SELECT count(*) > 0 FROM pg_buffercache_usage_counts() WHERE buffers >= 0; + ?column? +---------- + t +(1 row) + -- Check that the functions / views can't be accessed by default. To avoid -- having to create a dedicated user, use the pg_database_owner pseudo-role. SET ROLE pg_database_owner; @@ -26,6 +32,8 @@ SELECT * FROM pg_buffercache_pages() AS p (wrong int); ERROR: permission denied for function pg_buffercache_pages SELECT * FROM pg_buffercache_summary(); ERROR: permission denied for function pg_buffercache_summary +SELECT * FROM pg_buffercache_usage_counts(); +ERROR: permission denied for function pg_buffercache_usage_counts RESET role; -- Check that pg_monitor is allowed to query view / function SET ROLE pg_monitor; @@ -41,3 +49,9 @@ SELECT buffers_used + buffers_unused > 0 FROM pg_buffercache_summary(); t (1 row) +SELECT count(*) > 0 FROM pg_buffercache_usage_counts(); + ?column? +---------- + t +(1 row) + diff --git a/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql b/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql index 8f212dc5e9..d5aebf3ba3 100644 --- a/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql +++ b/contrib/pg_buffercache/pg_buffercache--1.3--1.4.sql @@ -12,6 +12,17 @@ CREATE FUNCTION pg_buffercache_summary( AS 'MODULE_PATHNAME', 'pg_buffercache_summary' LANGUAGE C PARALLEL SAFE; +CREATE FUNCTION pg_buffercache_usage_counts( + OUT usage_count int4, + OUT buffers int4, + OUT dirty int4, + OUT pinned int4) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'pg_buffercache_usage_counts' +LANGUAGE C PARALLEL SAFE; + -- Don't want these to be available to public. REVOKE ALL ON FUNCTION pg_buffercache_summary() FROM PUBLIC; GRANT EXECUTE ON FUNCTION pg_buffercache_summary() TO pg_monitor; +REVOKE ALL ON FUNCTION pg_buffercache_usage_counts() FROM PUBLIC; +GRANT EXECUTE ON FUNCTION pg_buffercache_usage_counts() TO pg_monitor; diff --git a/contrib/pg_buffercache/pg_buffercache_pages.c b/contrib/pg_buffercache/pg_buffercache_pages.c index 1c6a2f22ca..3316732365 100644 --- a/contrib/pg_buffercache/pg_buffercache_pages.c +++ b/contrib/pg_buffercache/pg_buffercache_pages.c @@ -18,6 +18,7 @@ #define NUM_BUFFERCACHE_PAGES_MIN_ELEM 8 #define NUM_BUFFERCACHE_PAGES_ELEM 9 #define NUM_BUFFERCACHE_SUMMARY_ELEM 5 +#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM 4 PG_MODULE_MAGIC; @@ -61,6 +62,7 @@ typedef struct */ PG_FUNCTION_INFO_V1(pg_buffercache_pages); PG_FUNCTION_INFO_V1(pg_buffercache_summary); +PG_FUNCTION_INFO_V1(pg_buffercache_usage_counts); Datum pg_buffercache_pages(PG_FUNCTION_ARGS) @@ -304,3 +306,44 @@ pg_buffercache_summary(PG_FUNCTION_ARGS) PG_RETURN_DATUM(result); } + +Datum +pg_buffercache_usage_counts(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0}; + int dirty[BM_MAX_USAGE_COUNT + 1] = {0}; + int pinned[BM_MAX_USAGE_COUNT + 1] = {0}; + Datum values[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM]; + bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0}; + + InitMaterializedSRF(fcinfo, 0); + + for (int i = 0; i < NBuffers; i++) + { + BufferDesc *bufHdr = GetBufferDescriptor(i); + uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); + int usage_count; + + usage_count = BUF_STATE_GET_USAGECOUNT(buf_state); + usage_counts[usage_count]++; + + if (buf_state & BM_DIRTY) + dirty[usage_count]++; + + if (BUF_STATE_GET_REFCOUNT(buf_state) > 0) + pinned[usage_count]++; + } + + for (int i = 0; i < BM_MAX_USAGE_COUNT + 1; i++) + { + values[0] = Int32GetDatum(i); + values[1] = Int32GetDatum(usage_counts[i]); + values[2] = Int32GetDatum(dirty[i]); + values[3] = Int32GetDatum(pinned[i]); + + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); + } + + return (Datum) 0; +} diff --git a/contrib/pg_buffercache/sql/pg_buffercache.sql b/contrib/pg_buffercache/sql/pg_buffercache.sql index 2e2e0a7451..944fbb1bea 100644 --- a/contrib/pg_buffercache/sql/pg_buffercache.sql +++ b/contrib/pg_buffercache/sql/pg_buffercache.sql @@ -10,15 +10,19 @@ select buffers_used + buffers_unused > 0, buffers_pinned <= buffers_used from pg_buffercache_summary(); +SELECT count(*) > 0 FROM pg_buffercache_usage_counts() WHERE buffers >= 0; + -- Check that the functions / views can't be accessed by default. To avoid -- having to create a dedicated user, use the pg_database_owner pseudo-role. SET ROLE pg_database_owner; SELECT * FROM pg_buffercache; SELECT * FROM pg_buffercache_pages() AS p (wrong int); SELECT * FROM pg_buffercache_summary(); +SELECT * FROM pg_buffercache_usage_counts(); RESET role; -- Check that pg_monitor is allowed to query view / function SET ROLE pg_monitor; SELECT count(*) > 0 FROM pg_buffercache; SELECT buffers_used + buffers_unused > 0 FROM pg_buffercache_summary(); +SELECT count(*) > 0 FROM pg_buffercache_usage_counts(); |