PostgreSQL Source Code  git master
pg_buffercache_pages.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
Include dependency graph for pg_buffercache_pages.c:

Go to the source code of this file.

Data Structures

struct  BufferCachePagesRec
 
struct  BufferCachePagesContext
 

Macros

#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
 

Functions

 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)
 
Datum pg_buffercache_summary (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_usage_counts (PG_FUNCTION_ARGS)
 

Variables

 PG_MODULE_MAGIC
 

Macro Definition Documentation

◆ NUM_BUFFERCACHE_PAGES_ELEM

#define NUM_BUFFERCACHE_PAGES_ELEM   9

Definition at line 19 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_PAGES_MIN_ELEM

#define NUM_BUFFERCACHE_PAGES_MIN_ELEM   8

Definition at line 18 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_SUMMARY_ELEM

#define NUM_BUFFERCACHE_SUMMARY_ELEM   5

Definition at line 20 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_USAGE_COUNTS_ELEM

#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM   4

Definition at line 21 of file pg_buffercache_pages.c.

Function Documentation

◆ pg_buffercache_pages()

Datum pg_buffercache_pages ( PG_FUNCTION_ARGS  )

Definition at line 68 of file pg_buffercache_pages.c.

69 {
70  FuncCallContext *funcctx;
71  Datum result;
72  MemoryContext oldcontext;
73  BufferCachePagesContext *fctx; /* User function context. */
74  TupleDesc tupledesc;
75  TupleDesc expected_tupledesc;
76  HeapTuple tuple;
77 
78  if (SRF_IS_FIRSTCALL())
79  {
80  int i;
81 
82  funcctx = SRF_FIRSTCALL_INIT();
83 
84  /* Switch context when allocating stuff to be used in later calls */
85  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
86 
87  /* Create a user function context for cross-call persistence */
89 
90  /*
91  * To smoothly support upgrades from version 1.0 of this extension
92  * transparently handle the (non-)existence of the pinning_backends
93  * column. We unfortunately have to get the result type for that... -
94  * we can't use the result type determined by the function definition
95  * without potentially crashing when somebody uses the old (or even
96  * wrong) function definition though.
97  */
98  if (get_call_result_type(fcinfo, NULL, &expected_tupledesc) != TYPEFUNC_COMPOSITE)
99  elog(ERROR, "return type must be a row type");
100 
101  if (expected_tupledesc->natts < NUM_BUFFERCACHE_PAGES_MIN_ELEM ||
102  expected_tupledesc->natts > NUM_BUFFERCACHE_PAGES_ELEM)
103  elog(ERROR, "incorrect number of output arguments");
104 
105  /* Construct a tuple descriptor for the result rows. */
106  tupledesc = CreateTemplateTupleDesc(expected_tupledesc->natts);
107  TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
108  INT4OID, -1, 0);
109  TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
110  OIDOID, -1, 0);
111  TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace",
112  OIDOID, -1, 0);
113  TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase",
114  OIDOID, -1, 0);
115  TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber",
116  INT2OID, -1, 0);
117  TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber",
118  INT8OID, -1, 0);
119  TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty",
120  BOOLOID, -1, 0);
121  TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count",
122  INT2OID, -1, 0);
123 
124  if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_ELEM)
125  TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends",
126  INT4OID, -1, 0);
127 
128  fctx->tupdesc = BlessTupleDesc(tupledesc);
129 
130  /* Allocate NBuffers worth of BufferCachePagesRec records. */
131  fctx->record = (BufferCachePagesRec *)
133  sizeof(BufferCachePagesRec) * NBuffers);
134 
135  /* Set max calls and remember the user function context. */
136  funcctx->max_calls = NBuffers;
137  funcctx->user_fctx = fctx;
138 
139  /* Return to original context when allocating transient memory */
140  MemoryContextSwitchTo(oldcontext);
141 
142  /*
143  * Scan through all the buffers, saving the relevant fields in the
144  * fctx->record structure.
145  *
146  * We don't hold the partition locks, so we don't get a consistent
147  * snapshot across all buffers, but we do grab the buffer header
148  * locks, so the information of each buffer is self-consistent.
149  */
150  for (i = 0; i < NBuffers; i++)
151  {
152  BufferDesc *bufHdr;
153  uint32 buf_state;
154 
155  bufHdr = GetBufferDescriptor(i);
156  /* Lock each buffer header before inspecting. */
157  buf_state = LockBufHdr(bufHdr);
158 
159  fctx->record[i].bufferid = BufferDescriptorGetBuffer(bufHdr);
160  fctx->record[i].relfilenumber = BufTagGetRelNumber(&bufHdr->tag);
161  fctx->record[i].reltablespace = bufHdr->tag.spcOid;
162  fctx->record[i].reldatabase = bufHdr->tag.dbOid;
163  fctx->record[i].forknum = BufTagGetForkNum(&bufHdr->tag);
164  fctx->record[i].blocknum = bufHdr->tag.blockNum;
165  fctx->record[i].usagecount = BUF_STATE_GET_USAGECOUNT(buf_state);
166  fctx->record[i].pinning_backends = BUF_STATE_GET_REFCOUNT(buf_state);
167 
168  if (buf_state & BM_DIRTY)
169  fctx->record[i].isdirty = true;
170  else
171  fctx->record[i].isdirty = false;
172 
173  /* Note if the buffer is valid, and has storage created */
174  if ((buf_state & BM_VALID) && (buf_state & BM_TAG_VALID))
175  fctx->record[i].isvalid = true;
176  else
177  fctx->record[i].isvalid = false;
178 
179  UnlockBufHdr(bufHdr, buf_state);
180  }
181  }
182 
183  funcctx = SRF_PERCALL_SETUP();
184 
185  /* Get the saved state */
186  fctx = funcctx->user_fctx;
187 
188  if (funcctx->call_cntr < funcctx->max_calls)
189  {
190  uint32 i = funcctx->call_cntr;
192  bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
193 
194  values[0] = Int32GetDatum(fctx->record[i].bufferid);
195  nulls[0] = false;
196 
197  /*
198  * Set all fields except the bufferid to null if the buffer is unused
199  * or not valid.
200  */
201  if (fctx->record[i].blocknum == InvalidBlockNumber ||
202  fctx->record[i].isvalid == false)
203  {
204  nulls[1] = true;
205  nulls[2] = true;
206  nulls[3] = true;
207  nulls[4] = true;
208  nulls[5] = true;
209  nulls[6] = true;
210  nulls[7] = true;
211  /* unused for v1.0 callers, but the array is always long enough */
212  nulls[8] = true;
213  }
214  else
215  {
217  nulls[1] = false;
219  nulls[2] = false;
221  nulls[3] = false;
222  values[4] = ObjectIdGetDatum(fctx->record[i].forknum);
223  nulls[4] = false;
224  values[5] = Int64GetDatum((int64) fctx->record[i].blocknum);
225  nulls[5] = false;
226  values[6] = BoolGetDatum(fctx->record[i].isdirty);
227  nulls[6] = false;
228  values[7] = Int16GetDatum(fctx->record[i].usagecount);
229  nulls[7] = false;
230  /* unused for v1.0 callers, but the array is always long enough */
232  nulls[8] = false;
233  }
234 
235  /* Build and return the tuple. */
236  tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
237  result = HeapTupleGetDatum(tuple);
238 
239  SRF_RETURN_NEXT(funcctx, result);
240  }
241  else
242  SRF_RETURN_DONE(funcctx);
243 }
int16 AttrNumber
Definition: attnum.h:21
#define InvalidBlockNumber
Definition: block.h:33
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define BM_TAG_VALID
Definition: buf_internals.h:63
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
static BufferDesc * GetBufferDescriptor(uint32 id)
static void UnlockBufHdr(BufferDesc *desc, uint32 buf_state)
static RelFileNumber BufTagGetRelNumber(const BufferTag *tag)
#define BM_DIRTY
Definition: buf_internals.h:61
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:52
#define BUF_STATE_GET_REFCOUNT(state)
Definition: buf_internals.h:51
#define BM_VALID
Definition: buf_internals.h:62
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)
uint32 LockBufHdr(BufferDesc *desc)
Definition: bufmgr.c:5390
unsigned int uint32
Definition: c.h:493
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2158
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
int NBuffers
Definition: globals.c:139
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
int i
Definition: isn.c:73
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition: mcxt.c:1627
void * palloc(Size size)
Definition: mcxt.c:1304
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM
#define NUM_BUFFERCACHE_PAGES_ELEM
uintptr_t Datum
Definition: postgres.h:64
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
MemoryContextSwitchTo(old_ctx)
BufferCachePagesRec * record
BufferTag tag
void * user_fctx
Definition: funcapi.h:82
uint64 max_calls
Definition: funcapi.h:74
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
BlockNumber blockNum
Definition: buf_internals.h:98
Oid spcOid
Definition: buf_internals.h:94
Oid dbOid
Definition: buf_internals.h:95
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651

References BlessTupleDesc(), BufferCachePagesRec::blocknum, buftag::blockNum, BM_DIRTY, BM_TAG_VALID, BM_VALID, BoolGetDatum(), BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BufferDescriptorGetBuffer(), BufferCachePagesRec::bufferid, BufTagGetForkNum(), BufTagGetRelNumber(), FuncCallContext::call_cntr, CreateTemplateTupleDesc(), CurrentMemoryContext, buftag::dbOid, elog, ERROR, BufferCachePagesRec::forknum, get_call_result_type(), GetBufferDescriptor(), heap_form_tuple(), HeapTupleGetDatum(), i, Int16GetDatum(), Int32GetDatum(), Int64GetDatum(), InvalidBlockNumber, BufferCachePagesRec::isdirty, BufferCachePagesRec::isvalid, LockBufHdr(), FuncCallContext::max_calls, MemoryContextAllocHuge(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, TupleDescData::natts, NBuffers, NUM_BUFFERCACHE_PAGES_ELEM, NUM_BUFFERCACHE_PAGES_MIN_ELEM, ObjectIdGetDatum(), palloc(), BufferCachePagesRec::pinning_backends, BufferCachePagesContext::record, BufferCachePagesRec::reldatabase, BufferCachePagesRec::relfilenumber, BufferCachePagesRec::reltablespace, buftag::spcOid, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, BufferDesc::tag, BufferCachePagesContext::tupdesc, TupleDescInitEntry(), TYPEFUNC_COMPOSITE, UnlockBufHdr(), BufferCachePagesRec::usagecount, FuncCallContext::user_fctx, and values.

◆ pg_buffercache_summary()

Datum pg_buffercache_summary ( PG_FUNCTION_ARGS  )

Definition at line 246 of file pg_buffercache_pages.c.

247 {
248  Datum result;
249  TupleDesc tupledesc;
250  HeapTuple tuple;
252  bool nulls[NUM_BUFFERCACHE_SUMMARY_ELEM];
253 
254  int32 buffers_used = 0;
255  int32 buffers_unused = 0;
256  int32 buffers_dirty = 0;
257  int32 buffers_pinned = 0;
258  int64 usagecount_total = 0;
259 
260  if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
261  elog(ERROR, "return type must be a row type");
262 
263  for (int i = 0; i < NBuffers; i++)
264  {
265  BufferDesc *bufHdr;
266  uint32 buf_state;
267 
268  /*
269  * This function summarizes the state of all headers. Locking the
270  * buffer headers wouldn't provide an improved result as the state of
271  * the buffer can still change after we release the lock and it'd
272  * noticeably increase the cost of the function.
273  */
274  bufHdr = GetBufferDescriptor(i);
275  buf_state = pg_atomic_read_u32(&bufHdr->state);
276 
277  if (buf_state & BM_VALID)
278  {
279  buffers_used++;
280  usagecount_total += BUF_STATE_GET_USAGECOUNT(buf_state);
281 
282  if (buf_state & BM_DIRTY)
283  buffers_dirty++;
284  }
285  else
286  buffers_unused++;
287 
288  if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
289  buffers_pinned++;
290  }
291 
292  memset(nulls, 0, sizeof(nulls));
293  values[0] = Int32GetDatum(buffers_used);
294  values[1] = Int32GetDatum(buffers_unused);
295  values[2] = Int32GetDatum(buffers_dirty);
296  values[3] = Int32GetDatum(buffers_pinned);
297 
298  if (buffers_used != 0)
299  values[4] = Float8GetDatum((double) usagecount_total / buffers_used);
300  else
301  nulls[4] = true;
302 
303  /* Build and return the tuple. */
304  tuple = heap_form_tuple(tupledesc, values, nulls);
305  result = HeapTupleGetDatum(tuple);
306 
307  PG_RETURN_DATUM(result);
308 }
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:234
signed int int32
Definition: c.h:481
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1816
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define NUM_BUFFERCACHE_SUMMARY_ELEM
pg_atomic_uint32 state

References BM_DIRTY, BM_VALID, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, elog, ERROR, Float8GetDatum(), get_call_result_type(), GetBufferDescriptor(), heap_form_tuple(), HeapTupleGetDatum(), i, Int32GetDatum(), NBuffers, NUM_BUFFERCACHE_SUMMARY_ELEM, pg_atomic_read_u32(), PG_RETURN_DATUM, BufferDesc::state, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_usage_counts()

Datum pg_buffercache_usage_counts ( PG_FUNCTION_ARGS  )

Definition at line 311 of file pg_buffercache_pages.c.

312 {
313  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
314  int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0};
315  int dirty[BM_MAX_USAGE_COUNT + 1] = {0};
316  int pinned[BM_MAX_USAGE_COUNT + 1] = {0};
318  bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0};
319 
320  InitMaterializedSRF(fcinfo, 0);
321 
322  for (int i = 0; i < NBuffers; i++)
323  {
324  BufferDesc *bufHdr = GetBufferDescriptor(i);
325  uint32 buf_state = pg_atomic_read_u32(&bufHdr->state);
326  int usage_count;
327 
328  usage_count = BUF_STATE_GET_USAGECOUNT(buf_state);
329  usage_counts[usage_count]++;
330 
331  if (buf_state & BM_DIRTY)
332  dirty[usage_count]++;
333 
334  if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
335  pinned[usage_count]++;
336  }
337 
338  for (int i = 0; i < BM_MAX_USAGE_COUNT + 1; i++)
339  {
340  values[0] = Int32GetDatum(i);
341  values[1] = Int32GetDatum(usage_counts[i]);
342  values[2] = Int32GetDatum(dirty[i]);
343  values[3] = Int32GetDatum(pinned[i]);
344 
345  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
346  }
347 
348  return (Datum) 0;
349 }
#define BM_MAX_USAGE_COUNT
Definition: buf_internals.h:78
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:750

References BM_MAX_USAGE_COUNT.

◆ PG_FUNCTION_INFO_V1() [1/3]

PG_FUNCTION_INFO_V1 ( pg_buffercache_pages  )

◆ PG_FUNCTION_INFO_V1() [2/3]

PG_FUNCTION_INFO_V1 ( pg_buffercache_summary  )

◆ PG_FUNCTION_INFO_V1() [3/3]

PG_FUNCTION_INFO_V1 ( pg_buffercache_usage_counts  )

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 23 of file pg_buffercache_pages.c.