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
 

Functions

 PG_FUNCTION_INFO_V1 (pg_buffercache_pages)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_summary)
 
Datum pg_buffercache_pages (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_summary (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.

Function Documentation

◆ pg_buffercache_pages()

Datum pg_buffercache_pages ( PG_FUNCTION_ARGS  )

Definition at line 66 of file pg_buffercache_pages.c.

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

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 244 of file pg_buffercache_pages.c.

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

PG_FUNCTION_INFO_V1 ( pg_buffercache_pages  )

◆ PG_FUNCTION_INFO_V1() [2/2]

PG_FUNCTION_INFO_V1 ( pg_buffercache_summary  )

Variable Documentation

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 22 of file pg_buffercache_pages.c.