PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_evict)
 
Datum pg_buffercache_pages (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_summary (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_usage_counts (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_evict (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_evict()

Datum pg_buffercache_evict ( PG_FUNCTION_ARGS  )

Definition at line 356 of file pg_buffercache_pages.c.

357{
359
360 if (!superuser())
362 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
363 errmsg("must be superuser to use pg_buffercache_evict function")));
364
365 if (buf < 1 || buf > NBuffers)
366 elog(ERROR, "bad buffer ID: %d", buf);
367
369}
int Buffer
Definition: buf.h:23
bool EvictUnpinnedBuffer(Buffer buf)
Definition: bufmgr.c:6101
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
int NBuffers
Definition: globals.c:141
static char * buf
Definition: pg_test_fsync.c:72
bool superuser(void)
Definition: superuser.c:46

References buf, elog, ereport, errcode(), errmsg(), ERROR, EvictUnpinnedBuffer(), NBuffers, PG_GETARG_INT32, PG_RETURN_BOOL, and superuser().

◆ pg_buffercache_pages()

Datum pg_buffercache_pages ( PG_FUNCTION_ARGS  )

Definition at line 69 of file pg_buffercache_pages.c.

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

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

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

313{
314 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
315 int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0};
316 int dirty[BM_MAX_USAGE_COUNT + 1] = {0};
317 int pinned[BM_MAX_USAGE_COUNT + 1] = {0};
319 bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0};
320
321 InitMaterializedSRF(fcinfo, 0);
322
323 for (int i = 0; i < NBuffers; i++)
324 {
326 uint32 buf_state = pg_atomic_read_u32(&bufHdr->state);
327 int usage_count;
328
329 usage_count = BUF_STATE_GET_USAGECOUNT(buf_state);
330 usage_counts[usage_count]++;
331
332 if (buf_state & BM_DIRTY)
333 dirty[usage_count]++;
334
335 if (BUF_STATE_GET_REFCOUNT(buf_state) > 0)
336 pinned[usage_count]++;
337 }
338
339 for (int i = 0; i < BM_MAX_USAGE_COUNT + 1; i++)
340 {
341 values[0] = Int32GetDatum(i);
342 values[1] = Int32GetDatum(usage_counts[i]);
343 values[2] = Int32GetDatum(dirty[i]);
344 values[3] = Int32GetDatum(pinned[i]);
345
346 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
347 }
348
349 return (Datum) 0;
350}
#define BM_MAX_USAGE_COUNT
Definition: buf_internals.h:77
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:784

References BM_MAX_USAGE_COUNT.

◆ PG_FUNCTION_INFO_V1() [1/4]

PG_FUNCTION_INFO_V1 ( pg_buffercache_evict  )

◆ PG_FUNCTION_INFO_V1() [2/4]

PG_FUNCTION_INFO_V1 ( pg_buffercache_pages  )

◆ PG_FUNCTION_INFO_V1() [3/4]

PG_FUNCTION_INFO_V1 ( pg_buffercache_summary  )

◆ PG_FUNCTION_INFO_V1() [4/4]

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.