PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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
 

Functions

 PG_FUNCTION_INFO_V1 (pg_buffercache_pages)
 
Datum pg_buffercache_pages (PG_FUNCTION_ARGS)
 

Variables

 PG_MODULE_MAGIC
 

Macro Definition Documentation

#define NUM_BUFFERCACHE_PAGES_ELEM   9

Definition at line 19 of file pg_buffercache_pages.c.

Referenced by pg_buffercache_pages().

#define NUM_BUFFERCACHE_PAGES_MIN_ELEM   8

Definition at line 18 of file pg_buffercache_pages.c.

Referenced by pg_buffercache_pages().

Function Documentation

Datum pg_buffercache_pages ( PG_FUNCTION_ARGS  )

Definition at line 64 of file pg_buffercache_pages.c.

References BlessTupleDesc(), BufferCachePagesRec::blocknum, buftag::blockNum, BM_DIRTY, BM_TAG_VALID, BM_VALID, BoolGetDatum, BOOLOID, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BufferDescriptorGetBuffer, BufferCachePagesRec::bufferid, FuncCallContext::call_cntr, CreateTemplateTupleDesc(), CurrentMemoryContext, RelFileNode::dbNode, elog, ERROR, BufferCachePagesRec::forknum, buftag::forkNum, get_call_result_type(), GetBufferDescriptor, heap_form_tuple(), HeapTupleGetDatum, i, Int16GetDatum, INT2OID, Int32GetDatum, INT4OID, Int64GetDatum(), INT8OID, InvalidBlockNumber, BufferCachePagesRec::isdirty, BufferCachePagesRec::isvalid, LockBufHdr(), FuncCallContext::max_calls, MemoryContextAllocHuge(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, tupleDesc::natts, NBuffers, NUM_BUFFERCACHE_PAGES_ELEM, NUM_BUFFERCACHE_PAGES_MIN_ELEM, ObjectIdGetDatum, OIDOID, palloc(), BufferCachePagesRec::pinning_backends, BufferCachePagesContext::record, BufferCachePagesRec::reldatabase, BufferCachePagesRec::relfilenode, RelFileNode::relNode, BufferCachePagesRec::reltablespace, buftag::rnode, RelFileNode::spcNode, 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.

65 {
66  FuncCallContext *funcctx;
67  Datum result;
68  MemoryContext oldcontext;
69  BufferCachePagesContext *fctx; /* User function context. */
70  TupleDesc tupledesc;
71  TupleDesc expected_tupledesc;
72  HeapTuple tuple;
73 
74  if (SRF_IS_FIRSTCALL())
75  {
76  int i;
77 
78  funcctx = SRF_FIRSTCALL_INIT();
79 
80  /* Switch context when allocating stuff to be used in later calls */
81  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
82 
83  /* Create a user function context for cross-call persistence */
85 
86  /*
87  * To smoothly support upgrades from version 1.0 of this extension
88  * transparently handle the (non-)existence 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 
101  /* Construct a tuple descriptor for the result rows. */
102  tupledesc = CreateTemplateTupleDesc(expected_tupledesc->natts, false);
103  TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
104  INT4OID, -1, 0);
105  TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
106  OIDOID, -1, 0);
107  TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace",
108  OIDOID, -1, 0);
109  TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase",
110  OIDOID, -1, 0);
111  TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber",
112  INT2OID, -1, 0);
113  TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber",
114  INT8OID, -1, 0);
115  TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty",
116  BOOLOID, -1, 0);
117  TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count",
118  INT2OID, -1, 0);
119 
120  if (expected_tupledesc->natts == NUM_BUFFERCACHE_PAGES_ELEM)
121  TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends",
122  INT4OID, -1, 0);
123 
124  fctx->tupdesc = BlessTupleDesc(tupledesc);
125 
126  /* Allocate NBuffers worth of BufferCachePagesRec records. */
127  fctx->record = (BufferCachePagesRec *)
129  sizeof(BufferCachePagesRec) * NBuffers);
130 
131  /* Set max calls and remember the user function context. */
132  funcctx->max_calls = NBuffers;
133  funcctx->user_fctx = fctx;
134 
135  /* Return to original context when allocating transient memory */
136  MemoryContextSwitchTo(oldcontext);
137 
138  /*
139  * Scan through all the buffers, saving the relevant fields in the
140  * fctx->record structure.
141  *
142  * We don't hold the partition locks, so we don't get a consistent
143  * snapshot across all buffers, but we do grab the buffer header
144  * locks, so the information of each buffer is self-consistent.
145  */
146  for (i = 0; i < NBuffers; i++)
147  {
148  BufferDesc *bufHdr;
149  uint32 buf_state;
150 
151  bufHdr = GetBufferDescriptor(i);
152  /* Lock each buffer header before inspecting. */
153  buf_state = LockBufHdr(bufHdr);
154 
155  fctx->record[i].bufferid = BufferDescriptorGetBuffer(bufHdr);
156  fctx->record[i].relfilenode = bufHdr->tag.rnode.relNode;
157  fctx->record[i].reltablespace = bufHdr->tag.rnode.spcNode;
158  fctx->record[i].reldatabase = bufHdr->tag.rnode.dbNode;
159  fctx->record[i].forknum = bufHdr->tag.forkNum;
160  fctx->record[i].blocknum = bufHdr->tag.blockNum;
161  fctx->record[i].usagecount = BUF_STATE_GET_USAGECOUNT(buf_state);
162  fctx->record[i].pinning_backends = BUF_STATE_GET_REFCOUNT(buf_state);
163 
164  if (buf_state & BM_DIRTY)
165  fctx->record[i].isdirty = true;
166  else
167  fctx->record[i].isdirty = false;
168 
169  /* Note if the buffer is valid, and has storage created */
170  if ((buf_state & BM_VALID) && (buf_state & BM_TAG_VALID))
171  fctx->record[i].isvalid = true;
172  else
173  fctx->record[i].isvalid = false;
174 
175  UnlockBufHdr(bufHdr, buf_state);
176  }
177  }
178 
179  funcctx = SRF_PERCALL_SETUP();
180 
181  /* Get the saved state */
182  fctx = funcctx->user_fctx;
183 
184  if (funcctx->call_cntr < funcctx->max_calls)
185  {
186  uint32 i = funcctx->call_cntr;
188  bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
189 
190  values[0] = Int32GetDatum(fctx->record[i].bufferid);
191  nulls[0] = false;
192 
193  /*
194  * Set all fields except the bufferid to null if the buffer is unused
195  * or not valid.
196  */
197  if (fctx->record[i].blocknum == InvalidBlockNumber ||
198  fctx->record[i].isvalid == false)
199  {
200  nulls[1] = true;
201  nulls[2] = true;
202  nulls[3] = true;
203  nulls[4] = true;
204  nulls[5] = true;
205  nulls[6] = true;
206  nulls[7] = true;
207  /* unused for v1.0 callers, but the array is always long enough */
208  nulls[8] = true;
209  }
210  else
211  {
212  values[1] = ObjectIdGetDatum(fctx->record[i].relfilenode);
213  nulls[1] = false;
214  values[2] = ObjectIdGetDatum(fctx->record[i].reltablespace);
215  nulls[2] = false;
216  values[3] = ObjectIdGetDatum(fctx->record[i].reldatabase);
217  nulls[3] = false;
218  values[4] = ObjectIdGetDatum(fctx->record[i].forknum);
219  nulls[4] = false;
220  values[5] = Int64GetDatum((int64) fctx->record[i].blocknum);
221  nulls[5] = false;
222  values[6] = BoolGetDatum(fctx->record[i].isdirty);
223  nulls[6] = false;
224  values[7] = Int16GetDatum(fctx->record[i].usagecount);
225  nulls[7] = false;
226  /* unused for v1.0 callers, but the array is always long enough */
227  values[8] = Int32GetDatum(fctx->record[i].pinning_backends);
228  nulls[8] = false;
229  }
230 
231  /* Build and return the tuple. */
232  tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
233  result = HeapTupleGetDatum(tuple);
234 
235  SRF_RETURN_NEXT(funcctx, result);
236  }
237  else
238  SRF_RETURN_DONE(funcctx);
239 }
uint64 call_cntr
Definition: funcapi.h:65
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:211
#define BM_TAG_VALID
Definition: buf_internals.h:61
ForkNumber forkNum
Definition: buf_internals.h:94
#define OIDOID
Definition: pg_type.h:328
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:285
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Int16GetDatum(X)
Definition: postgres.h:457
#define INT4OID
Definition: pg_type.h:316
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
#define BM_DIRTY
Definition: buf_internals.h:59
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:289
int natts
Definition: tupdesc.h:73
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:291
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:1032
#define INT2OID
Definition: pg_type.h:308
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition: mcxt.c:997
#define GetBufferDescriptor(id)
unsigned int uint32
Definition: c.h:258
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1786
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:505
#define BM_VALID
Definition: buf_internals.h:60
uintptr_t Datum
Definition: postgres.h:372
BufferCachePagesRec * record
#define BoolGetDatum(X)
Definition: postgres.h:408
#define INT8OID
Definition: pg_type.h:304
uint32 LockBufHdr(BufferDesc *desc)
Definition: bufmgr.c:4092
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:109
#define InvalidBlockNumber
Definition: block.h:33
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM
#define BufferDescriptorGetBuffer(bdesc)
BlockNumber blockNum
Definition: buf_internals.h:95
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:222
#define BOOLOID
Definition: pg_type.h:288
RelFileNode rnode
Definition: buf_internals.h:93
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:43
static Datum values[MAXATTR]
Definition: bootstrap.c:164
BufferTag tag
#define Int32GetDatum(X)
Definition: postgres.h:485
void * user_fctx
Definition: funcapi.h:90
void * palloc(Size size)
Definition: mcxt.c:848
#define UnlockBufHdr(desc, s)
int i
int NBuffers
Definition: globals.c:122
#define elog
Definition: elog.h:219
#define BUF_STATE_GET_USAGECOUNT(state)
Definition: buf_internals.h:50
int16 AttrNumber
Definition: attnum.h:21
uint64 max_calls
Definition: funcapi.h:74
#define NUM_BUFFERCACHE_PAGES_ELEM
#define BUF_STATE_GET_REFCOUNT(state)
Definition: buf_internals.h:49
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:287
PG_FUNCTION_INFO_V1 ( pg_buffercache_pages  )

Variable Documentation

PG_MODULE_MAGIC

Definition at line 21 of file pg_buffercache_pages.c.