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 dependency graph for pg_buffercache_pages.c:

Go to the source code of this file.

Data Structures

struct  BufferCachePagesRec
 
struct  BufferCachePagesContext
 
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)
 
 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 27 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_EVICT_ELEM

#define NUM_BUFFERCACHE_EVICT_ELEM   2

Definition at line 25 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_EVICT_RELATION_ELEM

#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM   3

Definition at line 26 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM

#define NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM   3

Definition at line 30 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_MARK_DIRTY_ELEM

#define NUM_BUFFERCACHE_MARK_DIRTY_ELEM   2

Definition at line 28 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM

#define NUM_BUFFERCACHE_MARK_DIRTY_RELATION_ELEM   3

Definition at line 29 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_OS_PAGES_ELEM

#define NUM_BUFFERCACHE_OS_PAGES_ELEM   3

Definition at line 32 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_PAGES_ELEM

#define NUM_BUFFERCACHE_PAGES_ELEM   9

Definition at line 22 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_PAGES_MIN_ELEM

#define NUM_BUFFERCACHE_PAGES_MIN_ELEM   8

Definition at line 21 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_SUMMARY_ELEM

#define NUM_BUFFERCACHE_SUMMARY_ELEM   5

Definition at line 23 of file pg_buffercache_pages.c.

◆ NUM_BUFFERCACHE_USAGE_COUNTS_ELEM

#define NUM_BUFFERCACHE_USAGE_COUNTS_ELEM   4

Definition at line 24 of file pg_buffercache_pages.c.

Function Documentation

◆ pg_buffercache_evict()

Datum pg_buffercache_evict ( PG_FUNCTION_ARGS  )

Definition at line 734 of file pg_buffercache_pages.c.

735{
736 Datum result;
737 TupleDesc tupledesc;
738 HeapTuple tuple;
740 bool nulls[NUM_BUFFERCACHE_EVICT_ELEM] = {0};
741
743 bool buffer_flushed;
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");
749
751 elog(ERROR, "bad buffer ID: %d", buf);
752
755
756 tuple = heap_form_tuple(tupledesc, values, nulls);
757 result = HeapTupleGetDatum(tuple);
758
759 PG_RETURN_DATUM(result);
760}
static Datum values[MAXATTR]
Definition bootstrap.c:155
int Buffer
Definition buf.h:23
bool EvictUnpinnedBuffer(Buffer buf, bool *buffer_flushed)
Definition bufmgr.c:7542
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#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:142
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1117
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
static int fb(int x)

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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_evict_all()

Datum pg_buffercache_evict_all ( PG_FUNCTION_ARGS  )

Definition at line 816 of file pg_buffercache_pages.c.

817{
818 Datum result;
819 TupleDesc tupledesc;
820 HeapTuple tuple;
822 bool nulls[NUM_BUFFERCACHE_EVICT_ALL_ELEM] = {0};
823
827
828 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
829 elog(ERROR, "return type must be a row type");
830
831 pg_buffercache_superuser_check("pg_buffercache_evict_all");
832
835
839
840 tuple = heap_form_tuple(tupledesc, values, nulls);
841 result = HeapTupleGetDatum(tuple);
842
843 PG_RETURN_DATUM(result);
844}
void EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
Definition bufmgr.c:7571
int32_t int32
Definition c.h:542
#define NUM_BUFFERCACHE_EVICT_ALL_ELEM
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222

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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_evict_relation()

Datum pg_buffercache_evict_relation ( PG_FUNCTION_ARGS  )

Definition at line 766 of file pg_buffercache_pages.c.

767{
768 Datum result;
769 TupleDesc tupledesc;
770 HeapTuple tuple;
772 bool nulls[NUM_BUFFERCACHE_EVICT_RELATION_ELEM] = {0};
773
774 Oid relOid;
775 Relation rel;
776
780
781 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
782 elog(ERROR, "return type must be a row type");
783
784 pg_buffercache_superuser_check("pg_buffercache_evict_relation");
785
786 relOid = PG_GETARG_OID(0);
787
788 rel = relation_open(relOid, AccessShareLock);
789
793 errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
794 "pg_buffercache_evict_relation")));
795
798
800
804
805 tuple = heap_form_tuple(tupledesc, values, nulls);
806 result = HeapTupleGetDatum(tuple);
807
808 PG_RETURN_DATUM(result);
809}
void EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
Definition bufmgr.c:7621
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ereport(elevel,...)
Definition elog.h:150
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define AccessShareLock
Definition lockdefs.h:36
#define NUM_BUFFERCACHE_EVICT_RELATION_ELEM
unsigned int Oid
#define RelationUsesLocalBuffers(relation)
Definition rel.h:646
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:205
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition relation.c:47

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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_mark_dirty()

Datum pg_buffercache_mark_dirty ( PG_FUNCTION_ARGS  )

Definition at line 850 of file pg_buffercache_pages.c.

851{
852
853 Datum result;
854 TupleDesc tupledesc;
855 HeapTuple tuple;
857 bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ELEM] = {0};
858
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");
866
868 elog(ERROR, "bad buffer ID: %d", buf);
869
872
873 tuple = heap_form_tuple(tupledesc, values, nulls);
874 result = HeapTupleGetDatum(tuple);
875
876 PG_RETURN_DATUM(result);
877}
bool MarkDirtyUnpinnedBuffer(Buffer buf, bool *buffer_already_dirty)
Definition bufmgr.c:7728
#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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_mark_dirty_all()

Datum pg_buffercache_mark_dirty_all ( PG_FUNCTION_ARGS  )

Definition at line 932 of file pg_buffercache_pages.c.

933{
934 Datum result;
935 TupleDesc tupledesc;
936 HeapTuple tuple;
938 bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM] = {0};
939
943
944 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
945 elog(ERROR, "return type must be a row type");
946
947 pg_buffercache_superuser_check("pg_buffercache_mark_dirty_all");
948
951
955
956 tuple = heap_form_tuple(tupledesc, values, nulls);
957 result = HeapTupleGetDatum(tuple);
958
959 PG_RETURN_DATUM(result);
960}
void MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
Definition bufmgr.c:7821
#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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_mark_dirty_relation()

Datum pg_buffercache_mark_dirty_relation ( PG_FUNCTION_ARGS  )

Definition at line 883 of file pg_buffercache_pages.c.

884{
885 Datum result;
886 TupleDesc tupledesc;
887 HeapTuple tuple;
890
891 Oid relOid;
892 Relation rel;
893
897
898 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
899 elog(ERROR, "return type must be a row type");
900
901 pg_buffercache_superuser_check("pg_buffercache_mark_dirty_relation");
902
903 relOid = PG_GETARG_OID(0);
904
905 rel = relation_open(relOid, AccessShareLock);
906
910 errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
911 "pg_buffercache_mark_dirty_relation")));
912
915
917
921
922 tuple = heap_form_tuple(tupledesc, values, nulls);
923 result = HeapTupleGetDatum(tuple);
924
925 PG_RETURN_DATUM(result);
926}
void MarkDirtyRelUnpinnedBuffers(Relation rel, int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
Definition bufmgr.c:7764
#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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_numa_pages()

Datum pg_buffercache_numa_pages ( PG_FUNCTION_ARGS  )

Definition at line 601 of file pg_buffercache_pages.c.

602{
603 /* Call internal function with include_numa=true */
604 return pg_buffercache_os_pages_internal(fcinfo, true);
605}
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 589 of file pg_buffercache_pages.c.

590{
591 bool include_numa;
592
593 /* Get the boolean parameter that controls the NUMA behavior. */
594 include_numa = PG_GETARG_BOOL(0);
595
596 return pg_buffercache_os_pages_internal(fcinfo, include_numa);
597}
#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 318 of file pg_buffercache_pages.c.

319{
321 MemoryContext oldcontext;
322 BufferCacheOsPagesContext *fctx; /* User function context. */
323 TupleDesc tupledesc;
325 HeapTuple tuple;
326 Datum result;
327
328 if (SRF_IS_FIRSTCALL())
329 {
330 int i,
331 idx;
334 int *os_page_status = NULL;
336 int max_entries;
337 char *startptr,
338 *endptr;
339
340 /* If NUMA information is requested, initialize NUMA support. */
341 if (include_numa && pg_numa_init() == -1)
342 elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
343
344 /*
345 * The database block size and OS memory page size are unlikely to be
346 * the same. The block size is 1-32KB, the memory page size depends on
347 * platform. On x86 it's usually 4KB, on ARM it's 4KB or 64KB, but
348 * there are also features like THP etc. Moreover, we don't quite know
349 * how the pages and buffers "align" in memory - the buffers may be
350 * shifted in some way, using more memory pages than necessary.
351 *
352 * So we need to be careful about mapping buffers to memory pages. We
353 * calculate the maximum number of pages a buffer might use, so that
354 * we allocate enough space for the entries. And then we count the
355 * actual number of entries as we scan the buffers.
356 *
357 * This information is needed before calling move_pages() for NUMA
358 * node id inquiry.
359 */
361
362 /*
363 * The pages and block size is expected to be 2^k, so one divides the
364 * other (we don't know in which direction). This does not say
365 * anything about relative alignment of pages/buffers.
366 */
367 Assert((os_page_size % BLCKSZ == 0) || (BLCKSZ % os_page_size == 0));
368
369 if (include_numa)
370 {
371 void **os_page_ptrs = NULL;
372
373 /*
374 * How many addresses we are going to query? Simply get the page
375 * for the first buffer, and first page after the last buffer, and
376 * count the pages from that.
377 */
378 startptr = (char *) TYPEALIGN_DOWN(os_page_size,
379 BufferGetBlock(1));
380 endptr = (char *) TYPEALIGN(os_page_size,
381 (char *) BufferGetBlock(NBuffers) + BLCKSZ);
382 os_page_count = (endptr - startptr) / os_page_size;
383
384 /* Used to determine the NUMA node for all OS pages at once */
387
388 /*
389 * Fill pointers for all the memory pages. This loop stores and
390 * touches (if needed) addresses into os_page_ptrs[] as input to
391 * one big move_pages(2) inquiry system call, as done in
392 * pg_numa_query_pages().
393 */
394 idx = 0;
395 for (char *ptr = startptr; ptr < endptr; ptr += os_page_size)
396 {
397 os_page_ptrs[idx++] = ptr;
398
399 /* Only need to touch memory once per backend process lifetime */
400 if (firstNumaTouch)
402 }
403
405
406 elog(DEBUG1, "NUMA: NBuffers=%d os_page_count=" UINT64_FORMAT " "
407 "os_page_size=%zu", NBuffers, os_page_count, os_page_size);
408
409 /*
410 * If we ever get 0xff back from kernel inquiry, then we probably
411 * have bug in our buffers to OS page mapping code here.
412 */
413 memset(os_page_status, 0xff, sizeof(int) * os_page_count);
414
415 /* Query NUMA status for all the pointers */
417 elog(ERROR, "failed NUMA pages inquiry: %m");
418 }
419
420 /* Initialize the multi-call context, load entries about buffers */
421
423
424 /* Switch context when allocating stuff to be used in later calls */
425 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
426
427 /* Create a user function context for cross-call persistence */
429
431 elog(ERROR, "return type must be a row type");
432
434 elog(ERROR, "incorrect number of output arguments");
435
436 /* Construct a tuple descriptor for the result rows. */
438 TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
439 INT4OID, -1, 0);
440 TupleDescInitEntry(tupledesc, (AttrNumber) 2, "os_page_num",
441 INT8OID, -1, 0);
442 TupleDescInitEntry(tupledesc, (AttrNumber) 3, "numa_node",
443 INT4OID, -1, 0);
444
445 fctx->tupdesc = BlessTupleDesc(tupledesc);
446 fctx->include_numa = include_numa;
447
448 /*
449 * Each buffer needs at least one entry, but it might be offset in
450 * some way, and use one extra entry. So we allocate space for the
451 * maximum number of entries we might need, and then count the exact
452 * number as we're walking buffers. That way we can do it in one pass,
453 * without reallocating memory.
454 */
457
458 /* Allocate entries for BufferCacheOsPagesRec records. */
459 fctx->record = (BufferCacheOsPagesRec *)
462
463 /* Return to original context when allocating transient memory */
464 MemoryContextSwitchTo(oldcontext);
465
466 if (include_numa && firstNumaTouch)
467 elog(DEBUG1, "NUMA: page-faulting the buffercache for proper NUMA readouts");
468
469 /*
470 * Scan through all the buffers, saving the relevant fields in the
471 * fctx->record structure.
472 *
473 * We don't hold the partition locks, so we don't get a consistent
474 * snapshot across all buffers, but we do grab the buffer header
475 * locks, so the information of each buffer is self-consistent.
476 */
477 startptr = (char *) TYPEALIGN_DOWN(os_page_size, (char *) BufferGetBlock(1));
478 idx = 0;
479 for (i = 0; i < NBuffers; i++)
480 {
481 char *buffptr = (char *) BufferGetBlock(i + 1);
483 uint32 bufferid;
484 int32 page_num;
485 char *startptr_buff,
487
489
491
492 /* Lock each buffer header before inspecting. */
496
497 /* start of the first page of this buffer */
499
500 /* end of the buffer (no need to align to memory page) */
502
504
505 /* calculate ID of the first page for this buffer */
506 page_num = (startptr_buff - startptr) / os_page_size;
507
508 /* Add an entry for each OS page overlapping with this buffer. */
509 for (char *ptr = startptr_buff; ptr < endptr_buff; ptr += os_page_size)
510 {
511 fctx->record[idx].bufferid = bufferid;
512 fctx->record[idx].page_num = page_num;
513 fctx->record[idx].numa_node = include_numa ? os_page_status[page_num] : -1;
514
515 /* advance to the next entry/page */
516 ++idx;
517 ++page_num;
518 }
519 }
520
522
523 if (include_numa)
525
526 /* Set max calls and remember the user function context. */
527 funcctx->max_calls = idx;
528 funcctx->user_fctx = fctx;
529
530 /* Remember this backend touched the pages (only relevant for NUMA) */
531 if (include_numa)
532 firstNumaTouch = false;
533 }
534
536
537 /* Get the saved state */
538 fctx = funcctx->user_fctx;
539
540 if (funcctx->call_cntr < funcctx->max_calls)
541 {
542 uint32 i = funcctx->call_cntr;
545
546 values[0] = Int32GetDatum(fctx->record[i].bufferid);
547 nulls[0] = false;
548
549 values[1] = Int64GetDatum(fctx->record[i].page_num);
550 nulls[1] = false;
551
552 if (fctx->include_numa)
553 {
554 /* status is valid node number */
555 if (fctx->record[i].numa_node >= 0)
556 {
557 values[2] = Int32GetDatum(fctx->record[i].numa_node);
558 nulls[2] = false;
559 }
560 else
561 {
562 /* some kind of error (e.g. pages moved to swap) */
563 values[2] = (Datum) 0;
564 nulls[2] = true;
565 }
566 }
567 else
568 {
569 values[2] = (Datum) 0;
570 nulls[2] = true;
571 }
572
573 /* Build and return the tuple. */
574 tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
575 result = HeapTupleGetDatum(tuple);
576
577 SRF_RETURN_NEXT(funcctx, result);
578 }
579 else
581}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
int16 AttrNumber
Definition attnum.h:21
static void UnlockBufHdr(BufferDesc *desc)
static BufferDesc * GetBufferDescriptor(uint32 id)
static Buffer BufferDescriptorGetBuffer(const BufferDesc *bdesc)
uint64 LockBufHdr(BufferDesc *desc)
Definition bufmgr.c:7107
static Block BufferGetBlock(Buffer buffer)
Definition bufmgr.h:433
#define TYPEALIGN(ALIGNVAL, LEN)
Definition c.h:819
#define Max(x, y)
Definition c.h:991
#define Assert(condition)
Definition c.h:873
#define UINT64_FORMAT
Definition c.h:565
uint64_t uint64
Definition c.h:547
uint32_t uint32
Definition c.h:546
size_t Size
Definition c.h:619
#define TYPEALIGN_DOWN(ALIGNVAL, LEN)
Definition c.h:831
#define DEBUG1
Definition elog.h:30
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
#define palloc_object(type)
Definition fe_memutils.h:74
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define palloc0_array(type, count)
Definition fe_memutils.h:77
#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:160
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition mcxt.c:1725
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
#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:130
PGDLLIMPORT int pg_numa_init(void)
Definition pg_numa.c:123
static Datum Int64GetDatum(int64 X)
Definition postgres.h:423
Size pg_get_shmem_pagesize(void)
Definition shmem.c:738
TupleDesc CreateTemplateTupleDesc(int natts)
Definition tupdesc.c:182
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition tupdesc.c:842

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, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, 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 117 of file pg_buffercache_pages.c.

118{
120 Datum result;
121 MemoryContext oldcontext;
122 BufferCachePagesContext *fctx; /* User function context. */
123 TupleDesc tupledesc;
125 HeapTuple tuple;
126
127 if (SRF_IS_FIRSTCALL())
128 {
129 int i;
130
132
133 /* Switch context when allocating stuff to be used in later calls */
134 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
135
136 /* Create a user function context for cross-call persistence */
138
139 /*
140 * To smoothly support upgrades from version 1.0 of this extension
141 * transparently handle the (non-)existence of the pinning_backends
142 * column. We unfortunately have to get the result type for that... -
143 * we can't use the result type determined by the function definition
144 * without potentially crashing when somebody uses the old (or even
145 * wrong) function definition though.
146 */
148 elog(ERROR, "return type must be a row type");
149
152 elog(ERROR, "incorrect number of output arguments");
153
154 /* Construct a tuple descriptor for the result rows. */
156 TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
157 INT4OID, -1, 0);
158 TupleDescInitEntry(tupledesc, (AttrNumber) 2, "relfilenode",
159 OIDOID, -1, 0);
160 TupleDescInitEntry(tupledesc, (AttrNumber) 3, "reltablespace",
161 OIDOID, -1, 0);
162 TupleDescInitEntry(tupledesc, (AttrNumber) 4, "reldatabase",
163 OIDOID, -1, 0);
164 TupleDescInitEntry(tupledesc, (AttrNumber) 5, "relforknumber",
165 INT2OID, -1, 0);
166 TupleDescInitEntry(tupledesc, (AttrNumber) 6, "relblocknumber",
167 INT8OID, -1, 0);
168 TupleDescInitEntry(tupledesc, (AttrNumber) 7, "isdirty",
169 BOOLOID, -1, 0);
170 TupleDescInitEntry(tupledesc, (AttrNumber) 8, "usage_count",
171 INT2OID, -1, 0);
172
174 TupleDescInitEntry(tupledesc, (AttrNumber) 9, "pinning_backends",
175 INT4OID, -1, 0);
176
177 fctx->tupdesc = BlessTupleDesc(tupledesc);
178
179 /* Allocate NBuffers worth of BufferCachePagesRec records. */
180 fctx->record = (BufferCachePagesRec *)
182 sizeof(BufferCachePagesRec) * NBuffers);
183
184 /* Set max calls and remember the user function context. */
185 funcctx->max_calls = NBuffers;
186 funcctx->user_fctx = fctx;
187
188 /* Return to original context when allocating transient memory */
189 MemoryContextSwitchTo(oldcontext);
190
191 /*
192 * Scan through all the buffers, saving the relevant fields in the
193 * fctx->record structure.
194 *
195 * We don't hold the partition locks, so we don't get a consistent
196 * snapshot across all buffers, but we do grab the buffer header
197 * locks, so the information of each buffer is self-consistent.
198 */
199 for (i = 0; i < NBuffers; i++)
200 {
203
205
207 /* Lock each buffer header before inspecting. */
209
210 fctx->record[i].bufferid = BufferDescriptorGetBuffer(bufHdr);
211 fctx->record[i].relfilenumber = BufTagGetRelNumber(&bufHdr->tag);
212 fctx->record[i].reltablespace = bufHdr->tag.spcOid;
213 fctx->record[i].reldatabase = bufHdr->tag.dbOid;
214 fctx->record[i].forknum = BufTagGetForkNum(&bufHdr->tag);
215 fctx->record[i].blocknum = bufHdr->tag.blockNum;
216 fctx->record[i].usagecount = BUF_STATE_GET_USAGECOUNT(buf_state);
217 fctx->record[i].pinning_backends = BUF_STATE_GET_REFCOUNT(buf_state);
218
219 if (buf_state & BM_DIRTY)
220 fctx->record[i].isdirty = true;
221 else
222 fctx->record[i].isdirty = false;
223
224 /* Note if the buffer is valid, and has storage created */
226 fctx->record[i].isvalid = true;
227 else
228 fctx->record[i].isvalid = false;
229
231 }
232 }
233
235
236 /* Get the saved state */
237 fctx = funcctx->user_fctx;
238
239 if (funcctx->call_cntr < funcctx->max_calls)
240 {
241 uint32 i = funcctx->call_cntr;
243 bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
244
245 values[0] = Int32GetDatum(fctx->record[i].bufferid);
246 nulls[0] = false;
247
248 /*
249 * Set all fields except the bufferid to null if the buffer is unused
250 * or not valid.
251 */
252 if (fctx->record[i].blocknum == InvalidBlockNumber ||
253 fctx->record[i].isvalid == false)
254 {
255 nulls[1] = true;
256 nulls[2] = true;
257 nulls[3] = true;
258 nulls[4] = true;
259 nulls[5] = true;
260 nulls[6] = true;
261 nulls[7] = true;
262 /* unused for v1.0 callers, but the array is always long enough */
263 nulls[8] = true;
264 }
265 else
266 {
267 values[1] = ObjectIdGetDatum(fctx->record[i].relfilenumber);
268 nulls[1] = false;
269 values[2] = ObjectIdGetDatum(fctx->record[i].reltablespace);
270 nulls[2] = false;
271 values[3] = ObjectIdGetDatum(fctx->record[i].reldatabase);
272 nulls[3] = false;
273 values[4] = Int16GetDatum(fctx->record[i].forknum);
274 nulls[4] = false;
275 values[5] = Int64GetDatum((int64) fctx->record[i].blocknum);
276 nulls[5] = false;
277 values[6] = BoolGetDatum(fctx->record[i].isdirty);
278 nulls[6] = false;
279 values[7] = UInt16GetDatum(fctx->record[i].usagecount);
280 nulls[7] = false;
281 /* unused for v1.0 callers, but the array is always long enough */
282 values[8] = Int32GetDatum(fctx->record[i].pinning_backends);
283 nulls[8] = false;
284 }
285
286 /* Build and return the tuple. */
287 tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
288 result = HeapTupleGetDatum(tuple);
289
290 SRF_RETURN_NEXT(funcctx, result);
291 }
292 else
294}
#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:543
#define NUM_BUFFERCACHE_PAGES_MIN_ELEM
#define NUM_BUFFERCACHE_PAGES_ELEM
static Datum Int16GetDatum(int16 X)
Definition postgres.h:182
static Datum UInt16GetDatum(uint16 X)
Definition postgres.h:202
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:262

References BlessTupleDesc(), BM_DIRTY, BM_TAG_VALID, BM_VALID, BoolGetDatum(), BUF_STATE_GET_REFCOUNT, BUF_STATE_GET_USAGECOUNT, BufferDescriptorGetBuffer(), BufTagGetForkNum(), BufTagGetRelNumber(), CHECK_FOR_INTERRUPTS, CreateTemplateTupleDesc(), CurrentMemoryContext, elog, ERROR, fb(), get_call_result_type(), GetBufferDescriptor(), heap_form_tuple(), HeapTupleGetDatum(), i, Int16GetDatum(), Int32GetDatum(), Int64GetDatum(), InvalidBlockNumber, LockBufHdr(), MemoryContextAllocHuge(), MemoryContextSwitchTo(), NBuffers, NUM_BUFFERCACHE_PAGES_ELEM, NUM_BUFFERCACHE_PAGES_MIN_ELEM, ObjectIdGetDatum(), palloc_object, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TupleDescInitEntry(), TYPEFUNC_COMPOSITE, UInt16GetDatum(), UnlockBufHdr(), and values.

◆ pg_buffercache_summary()

Datum pg_buffercache_summary ( PG_FUNCTION_ARGS  )

Definition at line 608 of file pg_buffercache_pages.c.

609{
610 Datum result;
611 TupleDesc tupledesc;
612 HeapTuple tuple;
615
621
622 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
623 elog(ERROR, "return type must be a row type");
624
625 for (int i = 0; i < NBuffers; i++)
626 {
629
631
632 /*
633 * This function summarizes the state of all headers. Locking the
634 * buffer headers wouldn't provide an improved result as the state of
635 * the buffer can still change after we release the lock and it'd
636 * noticeably increase the cost of the function.
637 */
640
641 if (buf_state & BM_VALID)
642 {
643 buffers_used++;
645
646 if (buf_state & BM_DIRTY)
648 }
649 else
651
654 }
655
656 memset(nulls, 0, sizeof(nulls));
661
662 if (buffers_used != 0)
664 else
665 nulls[4] = true;
666
667 /* Build and return the tuple. */
668 tuple = heap_form_tuple(tupledesc, values, nulls);
669 result = HeapTupleGetDatum(tuple);
670
671 PG_RETURN_DATUM(result);
672}
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:512

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

676{
677 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
678 int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0};
679 int dirty[BM_MAX_USAGE_COUNT + 1] = {0};
680 int pinned[BM_MAX_USAGE_COUNT + 1] = {0};
682 bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0};
683
684 InitMaterializedSRF(fcinfo, 0);
685
686 for (int i = 0; i < NBuffers; i++)
687 {
690 int usage_count;
691
693
696
697 if (buf_state & BM_DIRTY)
698 dirty[usage_count]++;
699
701 pinned[usage_count]++;
702 }
703
704 for (int i = 0; i < BM_MAX_USAGE_COUNT + 1; i++)
705 {
706 values[0] = Int32GetDatum(i);
708 values[2] = Int32GetDatum(dirty[i]);
709 values[3] = Int32GetDatum(pinned[i]);
710
711 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
712 }
713
714 return (Datum) 0;
715}
#define BM_MAX_USAGE_COUNT
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_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 113 of file pg_buffercache_pages.c.

Referenced by pg_buffercache_os_pages_internal().