Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f577919

Browse files
committed
Add pinning_backends column to the pg_buffercache extension.
The new column shows how many backends have a buffer pinned. That can be useful during development or to diagnose production issues e.g. caused by vacuum waiting for cleanup locks. To handle upgrades transparently - the extension might be used in views - deal with callers expecting the old number of columns. Reviewed by Fujii Masao and Rajeev rastogi.
1 parent ce48605 commit f577919

File tree

6 files changed

+58
-6
lines changed

6 files changed

+58
-6
lines changed

contrib/pg_buffercache/Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ MODULE_big = pg_buffercache
44
OBJS = pg_buffercache_pages.o $(WIN32RES)
55

66
EXTENSION = pg_buffercache
7-
DATA = pg_buffercache--1.0.sql pg_buffercache--unpackaged--1.0.sql
7+
DATA = pg_buffercache--1.1.sql pg_buffercache--1.0--1.1.sql pg_buffercache--unpackaged--1.0.sql
88
PGFILEDESC = "pg_buffercache - monitoring of shared buffer cache in real-time"
99

1010
ifdef USE_PGXS
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* contrib/pg_buffercache/pg_buffercache--1.0--1.1.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION pg_buffercache UPDATE TO '1.1'" to load this file. \quit
5+
6+
-- Upgrade view to 1.1. format
7+
CREATE OR REPLACE VIEW pg_buffercache AS
8+
SELECT P.* FROM pg_buffercache_pages() AS P
9+
(bufferid integer, relfilenode oid, reltablespace oid, reldatabase oid,
10+
relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2,
11+
pinning_backends int4);

contrib/pg_buffercache/pg_buffercache--1.0.sql renamed to contrib/pg_buffercache/pg_buffercache--1.1.sql

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* contrib/pg_buffercache/pg_buffercache--1.0.sql */
1+
/* contrib/pg_buffercache/pg_buffercache--1.1.sql */
22

33
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
44
\echo Use "CREATE EXTENSION pg_buffercache" to load this file. \quit
@@ -13,7 +13,8 @@ LANGUAGE C;
1313
CREATE VIEW pg_buffercache AS
1414
SELECT P.* FROM pg_buffercache_pages() AS P
1515
(bufferid integer, relfilenode oid, reltablespace oid, reldatabase oid,
16-
relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2);
16+
relforknumber int2, relblocknumber int8, isdirty bool, usagecount int2,
17+
pinning_backends int4);
1718

1819
-- Don't want these to be available to public.
1920
REVOKE ALL ON FUNCTION pg_buffercache_pages() FROM PUBLIC;
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# pg_buffercache extension
22
comment = 'examine the shared buffer cache'
3-
default_version = '1.0'
3+
default_version = '1.1'
44
module_pathname = '$libdir/pg_buffercache'
55
relocatable = true

contrib/pg_buffercache/pg_buffercache_pages.c

+35-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
#include "storage/bufmgr.h"
1616

1717

18-
#define NUM_BUFFERCACHE_PAGES_ELEM 8
18+
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM 8
19+
#define NUM_BUFFERCACHE_PAGES_ELEM 9
1920

2021
PG_MODULE_MAGIC;
2122

@@ -33,6 +34,12 @@ typedef struct
3334
bool isvalid;
3435
bool isdirty;
3536
uint16 usagecount;
37+
/*
38+
* An int32 is sufficiently large, as MAX_BACKENDS prevents a buffer from
39+
* being pinned by too many backends and each backend will only pin once
40+
* because of bufmgr.c's PrivateRefCount array.
41+
*/
42+
int32 pinning_backends;
3643
} BufferCachePagesRec;
3744

3845

@@ -60,6 +67,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
6067
MemoryContext oldcontext;
6168
BufferCachePagesContext *fctx; /* User function context. */
6269
TupleDesc tupledesc;
70+
TupleDesc expected_tupledesc;
6371
HeapTuple tuple;
6472

6573
if (SRF_IS_FIRSTCALL())
@@ -75,8 +83,23 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
7583
/* Create a user function context for cross-call persistence */
7684
fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext));
7785

86+
/*
87+
* To smoothly support upgrades from version 1.0 of this extension
88+
* transparently handle the (non-)existance of the pinning_backends
89+
* column. We unfortunately have to get the result type for that... -
90+
* we can't use the result type determined by the function definition
91+
* without potentially crashing when somebody uses the old (or even
92+
* wrong) function definition though.
93+
*/
94+
if (get_call_result_type(fcinfo, NULL, &expected_tupledesc) != TYPEFUNC_COMPOSITE)
95+
elog(ERROR, "return type must be a row type");
96+
97+
if (expected_tupledesc->natts < NUM_BUFFERCACHE_PAGES_MIN_ELEM ||
98+
expected_tupledesc->natts > NUM_BUFFERCACHE_PAGES_ELEM)
99+
elog(ERROR, "incorrect number of output arguments");
100+
78101
/* Construct a tuple descriptor for the result rows. */
79-
tupledesc = CreateTemplateTupleDesc(NUM_BUFFERCACHE_PAGES_ELEM, false);
102+
tupledesc = CreateTemplateTupleDesc(expected_tupledesc->natts, false);
80103
TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
81104
INT4OID, -1, 0);
82105
TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
@@ -94,6 +117,10 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
94117
TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count",
95118
INT2OID, -1, 0);
96119

120+
if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_ELEM)
121+
TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends",
122+
INT4OID, -1, 0);
123+
97124
fctx->tupdesc = BlessTupleDesc(tupledesc);
98125

99126
/* Allocate NBuffers worth of BufferCachePagesRec records. */
@@ -131,6 +158,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
131158
fctx->record[i].forknum = bufHdr->tag.forkNum;
132159
fctx->record[i].blocknum = bufHdr->tag.blockNum;
133160
fctx->record[i].usagecount = bufHdr->usage_count;
161+
fctx->record[i].pinning_backends = bufHdr->refcount;
134162

135163
if (bufHdr->flags & BM_DIRTY)
136164
fctx->record[i].isdirty = true;
@@ -185,6 +213,8 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
185213
nulls[5] = true;
186214
nulls[6] = true;
187215
nulls[7] = true;
216+
/* unused for v1.0 callers, but the array is always long enough */
217+
nulls[8] = true;
188218
}
189219
else
190220
{
@@ -202,6 +232,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
202232
nulls[6] = false;
203233
values[7] = Int16GetDatum(fctx->record[i].usagecount);
204234
nulls[7] = false;
235+
/* unused for v1.0 callers, but the array is always long enough */
236+
values[8] = Int32GetDatum(fctx->record[i].pinning_backends);
237+
nulls[8] = false;
205238
}
206239

207240
/* Build and return the tuple. */

doc/src/sgml/pgbuffercache.sgml

+7
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,13 @@
106106
<entry>Clock-sweep access count</entry>
107107
</row>
108108

109+
<row>
110+
<entry><structfield>pinning_backends</structfield></entry>
111+
<entry><type>integer</type></entry>
112+
<entry></entry>
113+
<entry>Number of backends pinning this buffer</entry>
114+
</row>
115+
109116
</tbody>
110117
</tgroup>
111118
</table>

0 commit comments

Comments
 (0)