PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_buffercache_pages.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "port/pg_numa.h"
#include "storage/buf_internals.h"
#include "storage/bufmgr.h"
#include "utils/rel.h"
#include "utils/tuplestore.h"
Include dependency graph for pg_buffercache_pages.c:

Go to the source code of this file.

Data Structures

struct  BufferCacheOsPagesRec
 
struct  BufferCacheOsPagesContext
 

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
 
#define NUM_BUFFERCACHE_EVICT_ELEM   2
 
#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM   3
 
#define NUM_BUFFERCACHE_EVICT_ALL_ELEM   3
 
#define NUM_BUFFERCACHE_MARK_DIRTY_ELEM   2
 
#define NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM   3
 
#define NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM   3
 
#define NUM_BUFFERCACHE_OS_PAGES_ELEM   3
 

Functions

 PG_MODULE_MAGIC_EXT (.name="pg_buffercache",.version=PG_VERSION)
 
static TupleDesc build_buffercache_pages_tupledesc (int natts)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_pages)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_os_pages)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_numa_pages)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_summary)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_usage_counts)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_evict)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_evict_relation)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_evict_all)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_mark_dirty)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_mark_dirty_relation)
 
 PG_FUNCTION_INFO_V1 (pg_buffercache_mark_dirty_all)
 
Datum pg_buffercache_pages (PG_FUNCTION_ARGS)
 
static Datum pg_buffercache_os_pages_internal (FunctionCallInfo fcinfo, bool include_numa)
 
Datum pg_buffercache_os_pages (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_numa_pages (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_summary (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_usage_counts (PG_FUNCTION_ARGS)
 
static void pg_buffercache_superuser_check (char *func_name)
 
Datum pg_buffercache_evict (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_evict_relation (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_evict_all (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_mark_dirty (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_mark_dirty_relation (PG_FUNCTION_ARGS)
 
Datum pg_buffercache_mark_dirty_all (PG_FUNCTION_ARGS)
 

Variables

static bool firstNumaTouch = true
 

Macro Definition Documentation

◆ NUM_BUFFERCACHE_EVICT_ALL_ELEM

#define NUM_BUFFERCACHE_EVICT_ALL_ELEM   3

Definition at line 28 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_EVICT_ELEM

#define NUM_BUFFERCACHE_EVICT_ELEM   2

Definition at line 26 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_EVICT_RELATION_ELEM

#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM   3

Definition at line 27 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM

#define NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM   3

Definition at line 31 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_MARK_DIRTY_ELEM

#define NUM_BUFFERCACHE_MARK_DIRTY_ELEM   2

Definition at line 29 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM

#define NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM   3

Definition at line 30 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_OS_PAGES_ELEM

#define NUM_BUFFERCACHE_OS_PAGES_ELEM   3

Definition at line 33 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_PAGES_ELEM

#define NUM_BUFFERCACHE_PAGES_ELEM   9

Definition at line 23 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_PAGES_MIN_ELEM

#define NUM_BUFFERCACHE_PAGES_MIN_ELEM   8

Definition at line 22 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_SUMMARY_ELEM

#define NUM_BUFFERCACHE_SUMMARY_ELEM   5

Definition at line 24 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_USAGE_COUNTS_ELEM

#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM   4

Definition at line 25 of file pg_buffercache_pages.c.

Function Documentation

◆ build_buffercache_pages_tupledesc()

static TupleDesc build_buffercache_pages_tupledesc ( int  natts)
static

Definition at line 228 of file pg_buffercache_pages.c.

229{
230 TupleDesc tupledesc;
231
232 tupledesc = CreateTemplateTupleDesc(natts);
233 TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
234 INT4OID, -1, 0);
235 TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
236 OIDOID, -1, 0);
237 TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace",
238 OIDOID, -1, 0);
239 TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase",
240 OIDOID, -1, 0);
241 TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber",
242 INT2OID, -1, 0);
243 TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber",
244 INT8OID, -1, 0);
245 TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty",
246 BOOLOID, -1, 0);
247 TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usagecount",
248 INT2OID, -1, 0);
249
250 if (natts == NUM_BUFFERCACHE_PAGES_ELEM)
251 TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends",
252 INT4OID, -1, 0);
253
254 TupleDescFinalize(tupledesc);
255
256 return BlessTupleDesc(tupledesc);
257}
int16 AttrNumber
Definition attnum.h:21
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
#define NUM_BUFFERCACHE_PAGES_ELEM
static int fb(int x)
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:165
void TupleDescFinalize(TupleDesc tupdesc)
Definition tupdesc.c:511
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:909

References BlessTupleDesc(), CreateTemplateTupleDesc(), fb(), NUM_BUFFERCACHE_PAGES_ELEM, TupleDescFinalize(), and TupleDescInitEntry().

Referenced by pg_buffercache_pages().

◆ pg_buffercache_evict()

Datum pg_buffercache_evict ( PG_FUNCTION_ARGS  )

Definition at line 698 of file pg_buffercache_pages.c.

699{
701 TupleDesc tupledesc;
702 HeapTuple tuple;
704 bool nulls[NUM_BUFFERCACHE_EVICT_ELEM] = {0};
705
707 bool buffer_flushed;
708
709 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
710 elog(ERROR, "return type must be a row type");
711
712 pg_buffercache_superuser_check("pg_buffercache_evict");
713
715 elog(ERROR, "bad buffer ID: %d", buf);
716
719
720 tuple = heap_form_tuple(tupledesc, values, nulls);
721 result = HeapTupleGetDatum(tuple);
722
724}
static Datum values[MAXATTR]
Definition bootstrap.c:190
int Buffer
Definition buf.h:23
bool EvictUnpinnedBuffer(Buffer buf, bool *buffer_flushed)
Definition bufmgr.c:7962
uint32 result
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_RETURN_DATUM(x)
Definition fmgr.h:354
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition funcapi.h:230
int NBuffers
Definition globals.c:144
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
static void pg_buffercache_superuser_check(char *func_name)
#define NUM_BUFFERCACHE_EVICT_ELEM
static char buf[DEFAULT_XLOG_SEG_SIZE]
static Datum BoolGetDatum(bool X)
Definition postgres.h:112
uint64_t Datum
Definition postgres.h:70

References BoolGetDatum(), buf, elog, ERROR, EvictUnpinnedBuffer(), fb(), get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), NBuffers, NUM_BUFFERCACHE_EVICT_ELEM, pg_buffercache_superuser_check(), PG_GETARG_INT32, PG_RETURN_DATUM, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_evict_all()

Datum pg_buffercache_evict_all ( PG_FUNCTION_ARGS  )

Definition at line 780 of file pg_buffercache_pages.c.

781{
783 TupleDesc tupledesc;
784 HeapTuple tuple;
786 bool nulls[NUM_BUFFERCACHE_EVICT_ALL_ELEM] = {0};
787
791
792 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
793 elog(ERROR, "return type must be a row type");
794
795 pg_buffercache_superuser_check("pg_buffercache_evict_all");
796
799
803
804 tuple = heap_form_tuple(tupledesc, values, nulls);
805 result = HeapTupleGetDatum(tuple);
806
808}
void EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
Definition bufmgr.c:7991
int32_t int32
Definition c.h:620
#define NUM_BUFFERCACHE_EVICT_ALL_ELEM
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212

References elog, ERROR, EvictAllUnpinnedBuffers(), fb(), get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), Int32GetDatum(), NUM_BUFFERCACHE_EVICT_ALL_ELEM, pg_buffercache_superuser_check(), PG_RETURN_DATUM, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_evict_relation()

Datum pg_buffercache_evict_relation ( PG_FUNCTION_ARGS  )

Definition at line 730 of file pg_buffercache_pages.c.

731{
733 TupleDesc tupledesc;
734 HeapTuple tuple;
736 bool nulls[NUM_BUFFERCACHE_EVICT_RELATION_ELEM] = {0};
737
738 Oid relOid;
739 Relation rel;
740
744
745 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
746 elog(ERROR, "return type must be a row type");
747
748 pg_buffercache_superuser_check("pg_buffercache_evict_relation");
749
750 relOid = PG_GETARG_OID(0);
751
752 rel = relation_open(relOid, AccessShareLock);
753
757 errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
758 "pg_buffercache_evict_relation")));
759
762
764
768
769 tuple = heap_form_tuple(tupledesc, values, nulls);
770 result = HeapTupleGetDatum(tuple);
771
773}
void EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
Definition bufmgr.c:8041
int errcode(int sqlerrcode)
Definition elog.c:875
#define ereport(elevel,...)
Definition elog.h:152
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define AccessShareLock
Definition lockdefs.h:36
static char * errmsg
#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM
unsigned int Oid
#define RelationUsesLocalBuffers(relation)
Definition rel.h:648
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:48

References AccessShareLock, elog, ereport, errcode(), errmsg, ERROR, EvictRelUnpinnedBuffers(), fb(), get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), Int32GetDatum(), NUM_BUFFERCACHE_EVICT_RELATION_ELEM, pg_buffercache_superuser_check(), PG_GETARG_OID, PG_RETURN_DATUM, relation_close(), relation_open(), RelationUsesLocalBuffers, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_mark_dirty()

Datum pg_buffercache_mark_dirty ( PG_FUNCTION_ARGS  )

Definition at line 814 of file pg_buffercache_pages.c.

815{
816
818 TupleDesc tupledesc;
819 HeapTuple tuple;
821 bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ELEM] = {0};
822
825
826 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
827 elog(ERROR, "return type must be a row type");
828
829 pg_buffercache_superuser_check("pg_buffercache_mark_dirty");
830
832 elog(ERROR, "bad buffer ID: %d", buf);
833
836
837 tuple = heap_form_tuple(tupledesc, values, nulls);
838 result = HeapTupleGetDatum(tuple);
839
841}
bool MarkDirtyUnpinnedBuffer(Buffer buf, bool *buffer_already_dirty)
Definition bufmgr.c:8148
#define NUM_BUFFERCACHE_MARK_DIRTY_ELEM

References BoolGetDatum(), buf, elog, ERROR, fb(), get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), MarkDirtyUnpinnedBuffer(), NBuffers, NUM_BUFFERCACHE_MARK_DIRTY_ELEM, pg_buffercache_superuser_check(), PG_GETARG_INT32, PG_RETURN_DATUM, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_mark_dirty_all()

Datum pg_buffercache_mark_dirty_all ( PG_FUNCTION_ARGS  )

Definition at line 896 of file pg_buffercache_pages.c.

897{
899 TupleDesc tupledesc;
900 HeapTuple tuple;
902 bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM] = {0};
903
907
908 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
909 elog(ERROR, "return type must be a row type");
910
911 pg_buffercache_superuser_check("pg_buffercache_mark_dirty_all");
912
915
919
920 tuple = heap_form_tuple(tupledesc, values, nulls);
921 result = HeapTupleGetDatum(tuple);
922
924}
void MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
Definition bufmgr.c:8241
#define NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM

References elog, ERROR, fb(), get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), Int32GetDatum(), MarkDirtyAllUnpinnedBuffers(), NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM, pg_buffercache_superuser_check(), PG_RETURN_DATUM, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_mark_dirty_relation()

Datum pg_buffercache_mark_dirty_relation ( PG_FUNCTION_ARGS  )

Definition at line 847 of file pg_buffercache_pages.c.

848{
850 TupleDesc tupledesc;
851 HeapTuple tuple;
854
855 Oid relOid;
856 Relation rel;
857
861
862 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
863 elog(ERROR, "return type must be a row type");
864
865 pg_buffercache_superuser_check("pg_buffercache_mark_dirty_relation");
866
867 relOid = PG_GETARG_OID(0);
868
869 rel = relation_open(relOid, AccessShareLock);
870
874 errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
875 "pg_buffercache_mark_dirty_relation")));
876
879
881
885
886 tuple = heap_form_tuple(tupledesc, values, nulls);
887 result = HeapTupleGetDatum(tuple);
888
890}
void MarkDirtyRelUnpinnedBuffers(Relation rel, int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
Definition bufmgr.c:8184
#define NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM

References AccessShareLock, elog, ereport, errcode(), errmsg, ERROR, fb(), get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), Int32GetDatum(), MarkDirtyRelUnpinnedBuffers(), NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM, pg_buffercache_superuser_check(), PG_GETARG_OID, PG_RETURN_DATUM, relation_close(), relation_open(), RelationUsesLocalBuffers, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_numa_pages()

Datum pg_buffercache_numa_pages ( PG_FUNCTION_ARGS  )

Definition at line 565 of file pg_buffercache_pages.c.

566{
567 /* Call internal function with include_numa=true */
568 return pg_buffercache_os_pages_internal(fcinfo, true);
569}
static Datum pg_buffercache_os_pages_internal(FunctionCallInfo fcinfo, bool include_numa)

References pg_buffercache_os_pages_internal().

◆ pg_buffercache_os_pages()

Datum pg_buffercache_os_pages ( PG_FUNCTION_ARGS  )

Definition at line 553 of file pg_buffercache_pages.c.

554{
555 bool include_numa;
556
557 /* Get the boolean parameter that controls the NUMA behavior. */
558 include_numa = PG_GETARG_BOOL(0);
559
560 return pg_buffercache_os_pages_internal(fcinfo, include_numa);
561}
#define PG_GETARG_BOOL(n)
Definition fmgr.h:274

References pg_buffercache_os_pages_internal(), and PG_GETARG_BOOL.

◆ pg_buffercache_os_pages_internal()

static Datum pg_buffercache_os_pages_internal ( FunctionCallInfo  fcinfo,
bool  include_numa 
)
static

Definition at line 281 of file pg_buffercache_pages.c.

282{
284 MemoryContext oldcontext;
285 BufferCacheOsPagesContext *fctx; /* User function context. */
286 TupleDesc tupledesc;
288 HeapTuple tuple;
290
291 if (SRF_IS_FIRSTCALL())
292 {
293 int i,
294 idx;
297 int *os_page_status = NULL;
299 int max_entries;
300 char *startptr,
301 *endptr;
302
303 /* If NUMA information is requested, initialize NUMA support. */
304 if (include_numa && pg_numa_init() == -1)
305 elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
306
307 /*
308 * The database block size and OS memory page size are unlikely to be
309 * the same. The block size is 1-32KB, the memory page size depends on
310 * platform. On x86 it's usually 4KB, on ARM it's 4KB or 64KB, but
311 * there are also features like THP etc. Moreover, we don't quite know
312 * how the pages and buffers "align" in memory - the buffers may be
313 * shifted in some way, using more memory pages than necessary.
314 *
315 * So we need to be careful about mapping buffers to memory pages. We
316 * calculate the maximum number of pages a buffer might use, so that
317 * we allocate enough space for the entries. And then we count the
318 * actual number of entries as we scan the buffers.
319 *
320 * This information is needed before calling move_pages() for NUMA
321 * node id inquiry.
322 */
324
325 /*
326 * The pages and block size is expected to be 2^k, so one divides the
327 * other (we don't know in which direction). This does not say
328 * anything about relative alignment of pages/buffers.
329 */
330 Assert((os_page_size % BLCKSZ == 0) || (BLCKSZ % os_page_size == 0));
331
332 if (include_numa)
333 {
334 void **os_page_ptrs = NULL;
335
336 /*
337 * How many addresses we are going to query? Simply get the page
338 * for the first buffer, and first page after the last buffer, and
339 * count the pages from that.
340 */
341 startptr = (char *) TYPEALIGN_DOWN(os_page_size,
342 BufferGetBlock(1));
343 endptr = (char *) TYPEALIGN(os_page_size,
344 (char *) BufferGetBlock(NBuffers) + BLCKSZ);
345 os_page_count = (endptr - startptr) / os_page_size;
346
347 /* Used to determine the NUMA node for all OS pages at once */
350
351 /*
352 * Fill pointers for all the memory pages. This loop stores and
353 * touches (if needed) addresses into os_page_ptrs[] as input to
354 * one big move_pages(2) inquiry system call, as done in
355 * pg_numa_query_pages().
356 */
357 idx = 0;
358 for (char *ptr = startptr; ptr < endptr; ptr += os_page_size)
359 {
360 os_page_ptrs[idx++] = ptr;
361
362 /* Only need to touch memory once per backend process lifetime */
363 if (firstNumaTouch)
365 }
366
368
369 elog(DEBUG1, "NUMA: NBuffers=%d os_page_count=" UINT64_FORMAT " "
370 "os_page_size=%zu", NBuffers, os_page_count, os_page_size);
371
372 /*
373 * If we ever get 0xff back from kernel inquiry, then we probably
374 * have bug in our buffers to OS page mapping code here.
375 */
376 memset(os_page_status, 0xff, sizeof(int) * os_page_count);
377
378 /* Query NUMA status for all the pointers */
380 elog(ERROR, "failed NUMA pages inquiry: %m");
381 }
382
383 /* Initialize the multi-call context, load entries about buffers */
384
386
387 /* Switch context when allocating stuff to be used in later calls */
388 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
389
390 /* Create a user function context for cross-call persistence */
392
394 elog(ERROR, "return type must be a row type");
395
397 elog(ERROR, "incorrect number of output arguments");
398
399 /* Construct a tuple descriptor for the result rows. */
401 TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
402 INT4OID, -1, 0);
403 TupleDescInitEntry(tupledesc, (AttrNumber) 2, "os_page_num",
404 INT8OID, -1, 0);
405 TupleDescInitEntry(tupledesc, (AttrNumber) 3, "numa_node",
406 INT4OID, -1, 0);
407
408 TupleDescFinalize(tupledesc);
409 fctx->tupdesc = BlessTupleDesc(tupledesc);
410 fctx->include_numa = include_numa;
411
412 /*
413 * Each buffer needs at least one entry, but it might be offset in
414 * some way, and use one extra entry. So we allocate space for the
415 * maximum number of entries we might need, and then count the exact
416 * number as we're walking buffers. That way we can do it in one pass,
417 * without reallocating memory.
418 */
421
422 /* Allocate entries for BufferCacheOsPagesRec records. */
423 fctx->record = (BufferCacheOsPagesRec *)
426
427 /* Return to original context when allocating transient memory */
428 MemoryContextSwitchTo(oldcontext);
429
430 if (include_numa && firstNumaTouch)
431 elog(DEBUG1, "NUMA: page-faulting the buffercache for proper NUMA readouts");
432
433 /*
434 * Scan through all the buffers, saving the relevant fields in the
435 * fctx->record structure.
436 *
437 * We don't hold the partition locks, so we don't get a consistent
438 * snapshot across all buffers, but we do grab the buffer header
439 * locks, so the information of each buffer is self-consistent.
440 */
441 startptr = (char *) TYPEALIGN_DOWN(os_page_size, (char *) BufferGetBlock(1));
442 idx = 0;
443 for (i = 0; i < NBuffers; i++)
444 {
445 char *buffptr = (char *) BufferGetBlock(i + 1);
447 uint32 bufferid;
448 int32 page_num;
449 char *startptr_buff,
451
453
455
456 /* Lock each buffer header before inspecting. */
460
461 /* start of the first page of this buffer */
463
464 /* end of the buffer (no need to align to memory page) */
466
468
469 /* calculate ID of the first page for this buffer */
470 page_num = (startptr_buff - startptr) / os_page_size;
471
472 /* Add an entry for each OS page overlapping with this buffer. */
473 for (char *ptr = startptr_buff; ptr < endptr_buff; ptr += os_page_size)
474 {
475 fctx->record[idx].bufferid = bufferid;
476 fctx->record[idx].page_num = page_num;
477 fctx->record[idx].numa_node = include_numa ? os_page_status[page_num] : -1;
478
479 /* advance to the next entry/page */
480 ++idx;
481 ++page_num;
482 }
483 }
484
486
487 if (include_numa)
489
490 /* Set max calls and remember the user function context. */
491 funcctx->max_calls = idx;
492 funcctx->user_fctx = fctx;
493
494 /* Remember this backend touched the pages (only relevant for NUMA) */
495 if (include_numa)
496 firstNumaTouch = false;
497 }
498
500
501 /* Get the saved state */
502 fctx = funcctx->user_fctx;
503
504 if (funcctx->call_cntr < funcctx->max_calls)
505 {
506 uint32 i = funcctx->call_cntr;
509
510 values[0] = Int32GetDatum(fctx->record[i].bufferid);
511 nulls[0] = false;
512
513 values[1] = Int64GetDatum(fctx->record[i].page_num);
514 nulls[1] = false;
515
516 if (fctx->include_numa)
517 {
518 /* status is valid node number */
519 if (fctx->record[i].numa_node >= 0)
520 {
521 values[2] = Int32GetDatum(fctx->record[i].numa_node);
522 nulls[2] = false;
523 }
524 else
525 {
526 /* some kind of error (e.g. pages moved to swap) */
527 values[2] = (Datum) 0;
528 nulls[2] = true;
529 }
530 }
531 else
532 {
533 values[2] = (Datum) 0;
534 nulls[2] = true;
535 }
536
537 /* Build and return the tuple. */
538 tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
539 result = HeapTupleGetDatum(tuple);
540
542 }
543 else
545}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:263
static void UnlockBufHdr(BufferDesc *desc)
static BufferDesc * GetBufferDescriptor(uint32 id)
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)
uint64 LockBufHdr(BufferDesc *desc)
Definition bufmgr.c:7527
static Block BufferGetBlock(Buffer buffer)
Definition bufmgr.h:435
#define TYPEALIGN(ALIGNVAL, LEN)
Definition c.h:889
#define Max(x, y)
Definition c.h:1085
#define Assert(condition)
Definition c.h:943
#define UINT64_FORMAT
Definition c.h:635
uint64_t uint64
Definition c.h:625
uint32_t uint32
Definition c.h:624
size_t Size
Definition c.h:689
#define TYPEALIGN_DOWN(ALIGNVAL, LEN)
Definition c.h:901
#define DEBUG1
Definition elog.h:31
#define palloc_object(type)
Definition fe_memutils.h:89
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define palloc0_array(type, count)
Definition fe_memutils.h:92
#define SRF_IS_FIRSTCALL()
Definition funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition funcapi.h:328
int i
Definition isn.c:77
MemoryContext CurrentMemoryContext
Definition mcxt.c:161
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition mcxt.c:1854
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:138
#define NUM_BUFFERCACHE_OS_PAGES_ELEM
static bool firstNumaTouch
#define pg_numa_touch_mem_if_required(ptr)
Definition pg_numa.h:37
PGDLLIMPORT int pg_numa_query_pages(int pid, unsigned long count, void **pages, int *status)
Definition pg_numa.c:132
PGDLLIMPORT int pg_numa_init(void)
Definition pg_numa.c:125
static Datum Int64GetDatum(int64 X)
Definition postgres.h:426
Size pg_get_shmem_pagesize(void)
Definition shmem.c:1273

References Assert, BlessTupleDesc(), BufferDescriptorGetBuffer(), BufferGetBlock(), CHECK_FOR_INTERRUPTS, CreateTemplateTupleDesc(), CurrentMemoryContext, DEBUG1, elog, ERROR, fb(), firstNumaTouch, get_call_result_type(), GetBufferDescriptor(), heap_form_tuple(), HeapTupleGetDatum(), i, idx(), Int32GetDatum(), Int64GetDatum(), LockBufHdr(), Max, MemoryContextAllocHuge(), MemoryContextSwitchTo(), NBuffers, NUM_BUFFERCACHE_OS_PAGES_ELEM, palloc0_array, palloc_array, palloc_object, pg_get_shmem_pagesize(), pg_numa_init(), pg_numa_query_pages(), pg_numa_touch_mem_if_required, result, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TupleDescFinalize(), TupleDescInitEntry(), TYPEALIGN, TYPEALIGN_DOWN, TYPEFUNC_COMPOSITE, UINT64_FORMAT, UnlockBufHdr(), and values.

Referenced by pg_buffercache_numa_pages(), and pg_buffercache_os_pages().

◆ pg_buffercache_pages()

Datum pg_buffercache_pages ( PG_FUNCTION_ARGS  )

Definition at line 87 of file pg_buffercache_pages.c.

88{
89 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
92 MemoryContext oldcontext;
93 int i;
94
95 /*
96 * To smoothly support upgrades from version 1.0 of this extension
97 * transparently handle the (non-)existence of the pinning_backends
98 * column. We unfortunately have to get the result type for that... - we
99 * can't use the result type determined by the function definition without
100 * potentially crashing when somebody uses the old (or even wrong)
101 * function definition though.
102 */
104 elog(ERROR, "return type must be a row type");
105
108 elog(ERROR, "incorrect number of output arguments");
109
110 InitMaterializedSRF(fcinfo, 0);
111
112 oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory);
114 MemoryContextSwitchTo(oldcontext);
115
116 /*
117 * Override the caller-supplied descriptor with the tuple descriptor that
118 * matches the values we actually return, so executor-side
119 * tupledesc_match() can verify the caller's row definition.
120 *
121 * Do not free the previous rsinfo->setDesc here: for RECORD results it
122 * can alias rsinfo->expectedDesc, which the executor still needs to
123 * reference.
124 */
125 rsinfo->setDesc = actual_tupledesc;
126
127 /*
128 * Scan through all the buffers, adding one row for each of the buffers to
129 * the tuplestore.
130 *
131 * We don't hold the partition locks, so we don't get a consistent
132 * snapshot across all buffers, but we do grab the buffer header locks, so
133 * the information of each buffer is self-consistent.
134 */
135 for (i = 0; i < NBuffers; i++)
136 {
139 uint32 bufferid;
140 RelFileNumber relfilenumber;
141 Oid reltablespace;
143 ForkNumber forknum;
144 BlockNumber blocknum;
145 bool isvalid;
146 bool isdirty;
150 bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
151
153
155 /* Lock each buffer header before inspecting. */
157
159 relfilenumber = BufTagGetRelNumber(&bufHdr->tag);
160 reltablespace = bufHdr->tag.spcOid;
161 reldatabase = bufHdr->tag.dbOid;
162 forknum = BufTagGetForkNum(&bufHdr->tag);
163 blocknum = bufHdr->tag.blockNum;
166
167 if (buf_state & BM_DIRTY)
168 isdirty = true;
169 else
170 isdirty = false;
171
172 /* Note if the buffer is valid, and has storage created */
174 isvalid = true;
175 else
176 isvalid = false;
177
179
180 /* Build the tuple and add it to tuplestore */
181 values[0] = Int32GetDatum(bufferid);
182 nulls[0] = false;
183
184 /*
185 * Set all fields except the bufferid to null if the buffer is unused
186 * or not valid.
187 */
188 if (blocknum == InvalidBlockNumber || isvalid == false)
189 {
190 nulls[1] = true;
191 nulls[2] = true;
192 nulls[3] = true;
193 nulls[4] = true;
194 nulls[5] = true;
195 nulls[6] = true;
196 nulls[7] = true;
197 /* unused for v1.0 callers, but the array is always long enough */
198 nulls[8] = true;
199 }
200 else
201 {
202 values[1] = ObjectIdGetDatum(relfilenumber);
203 nulls[1] = false;
204 values[2] = ObjectIdGetDatum(reltablespace);
205 nulls[2] = false;
207 nulls[3] = false;
208 values[4] = Int16GetDatum(forknum);
209 nulls[4] = false;
210 values[5] = Int64GetDatum((int64) blocknum);
211 nulls[5] = false;
213 nulls[6] = false;
215 nulls[7] = false;
216 /* unused for v1.0 callers, but the array is always long enough */
218 nulls[8] = false;
219 }
220
221 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
222 }
223
224 return (Datum) 0;
225}
uint32 BlockNumber
Definition block.h:31
#define InvalidBlockNumber
Definition block.h:33
#define BM_TAG_VALID
static ForkNumber BufTagGetForkNum(const BufferTag *tag)
static RelFileNumber BufTagGetRelNumber(const BufferTag *tag)
#define BM_DIRTY
#define BUF_STATE_GET_USAGECOUNT(state)
#define BUF_STATE_GET_REFCOUNT(state)
#define BM_VALID
int64_t int64
Definition c.h:621
uint16_t uint16
Definition c.h:623
void InitMaterializedSRF(FunctionCallInfo fcinfo, uint32 flags)
Definition funcapi.c:76
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM
static TupleDesc build_buffercache_pages_tupledesc(int natts)
static Datum Int16GetDatum(int16 X)
Definition postgres.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
Oid RelFileNumber
Definition relpath.h:25
ForkNumber
Definition relpath.h:56
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:785

References BM_DIRTY, BM_TAG_VALID, BM_VALID, BoolGetDatum(), BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BufferDescriptorGetBuffer(), BufTagGetForkNum(), BufTagGetRelNumber(), build_buffercache_pages_tupledesc(), CHECK_FOR_INTERRUPTS, elog, ERROR, fb(), get_call_result_type(), GetBufferDescriptor(), i, InitMaterializedSRF(), Int16GetDatum(), Int32GetDatum(), Int64GetDatum(), InvalidBlockNumber, LockBufHdr(), MemoryContextSwitchTo(), NBuffers, NUM_BUFFERCACHE_PAGES_ELEM, NUM_BUFFERCACHE_PAGES_MIN_ELEM, ObjectIdGetDatum(), tuplestore_putvalues(), TYPEFUNC_COMPOSITE, UnlockBufHdr(), and values.

◆ pg_buffercache_summary()

Datum pg_buffercache_summary ( PG_FUNCTION_ARGS  )

Definition at line 572 of file pg_buffercache_pages.c.

573{
575 TupleDesc tupledesc;
576 HeapTuple tuple;
579
585
586 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
587 elog(ERROR, "return type must be a row type");
588
589 for (int i = 0; i < NBuffers; i++)
590 {
593
595
596 /*
597 * This function summarizes the state of all headers. Locking the
598 * buffer headers wouldn't provide an improved result as the state of
599 * the buffer can still change after we release the lock and it'd
600 * noticeably increase the cost of the function.
601 */
604
605 if (buf_state & BM_VALID)
606 {
607 buffers_used++;
609
610 if (buf_state & BM_DIRTY)
612 }
613 else
615
618 }
619
620 memset(nulls, 0, sizeof(nulls));
625
626 if (buffers_used != 0)
628 else
629 nulls[4] = true;
630
631 /* Build and return the tuple. */
632 tuple = heap_form_tuple(tupledesc, values, nulls);
633 result = HeapTupleGetDatum(tuple);
634
636}
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition atomics.h:467
#define NUM_BUFFERCACHE_SUMMARY_ELEM
static Datum Float8GetDatum(float8 X)
Definition postgres.h:515

References BM_DIRTY, BM_VALID, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, CHECK_FOR_INTERRUPTS, elog, ERROR, fb(), Float8GetDatum(), get_call_result_type(), GetBufferDescriptor(), heap_form_tuple(), HeapTupleGetDatum(), i, Int32GetDatum(), NBuffers, NUM_BUFFERCACHE_SUMMARY_ELEM, pg_atomic_read_u64(), PG_RETURN_DATUM, result, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_superuser_check()

static void pg_buffercache_superuser_check ( char func_name)
static

◆ pg_buffercache_usage_counts()

Datum pg_buffercache_usage_counts ( PG_FUNCTION_ARGS  )

Definition at line 639 of file pg_buffercache_pages.c.

640{
641 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
642 int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0};
643 int dirty[BM_MAX_USAGE_COUNT + 1] = {0};
644 int pinned[BM_MAX_USAGE_COUNT + 1] = {0};
646 bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0};
647
648 InitMaterializedSRF(fcinfo, 0);
649
650 for (int i = 0; i < NBuffers; i++)
651 {
654 int usage_count;
655
657
660
661 if (buf_state & BM_DIRTY)
662 dirty[usage_count]++;
663
665 pinned[usage_count]++;
666 }
667
668 for (int i = 0; i < BM_MAX_USAGE_COUNT + 1; i++)
669 {
670 values[0] = Int32GetDatum(i);
672 values[2] = Int32GetDatum(dirty[i]);
673 values[3] = Int32GetDatum(pinned[i]);
674
675 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
676 }
677
678 return (Datum) 0;
679}
#define BM_MAX_USAGE_COUNT
#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM

References BM_DIRTY, BM_MAX_USAGE_COUNT, BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, CHECK_FOR_INTERRUPTS, fb(), GetBufferDescriptor(), i, InitMaterializedSRF(), Int32GetDatum(), NBuffers, NUM_BUFFERCACHE_USAGE_COUNTS_ELEM, pg_atomic_read_u64(), tuplestore_putvalues(), and values.

◆ PG_FUNCTION_INFO_V1() [1/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_evict  )

◆ PG_FUNCTION_INFO_V1() [2/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_evict_all  )

◆ PG_FUNCTION_INFO_V1() [3/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_evict_relation  )

◆ PG_FUNCTION_INFO_V1() [4/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_mark_dirty  )

◆ PG_FUNCTION_INFO_V1() [5/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_mark_dirty_all  )

◆ PG_FUNCTION_INFO_V1() [6/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_mark_dirty_relation  )

◆ PG_FUNCTION_INFO_V1() [7/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_numa_pages  )

◆ PG_FUNCTION_INFO_V1() [8/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_os_pages  )

◆ PG_FUNCTION_INFO_V1() [9/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_pages  )

◆ PG_FUNCTION_INFO_V1() [10/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_summary  )

◆ PG_FUNCTION_INFO_V1() [11/11]

PG_FUNCTION_INFO_V1 ( pg_buffercache_usage_counts  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "pg_buffercache",
version = PG_VERSION 
)

Variable Documentation

◆ firstNumaTouch

bool firstNumaTouch = true
static

Definition at line 83 of file pg_buffercache_pages.c.

Referenced by pg_buffercache_os_pages_internal().