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  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 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

◆ pg_buffercache_evict()

Datum pg_buffercache_evict ( PG_FUNCTION_ARGS  )

Definition at line 737 of file pg_buffercache_pages.c.

738{
739 Datum result;
740 TupleDesc tupledesc;
741 HeapTuple tuple;
743 bool nulls[NUM_BUFFERCACHE_EVICT_ELEM] = {0};
744
746 bool buffer_flushed;
747
748 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
749 elog(ERROR, "return type must be a row type");
750
751 pg_buffercache_superuser_check("pg_buffercache_evict");
752
754 elog(ERROR, "bad buffer ID: %d", buf);
755
758
759 tuple = heap_form_tuple(tupledesc, values, nulls);
760 result = HeapTupleGetDatum(tuple);
761
762 PG_RETURN_DATUM(result);
763}
static Datum values[MAXATTR]
Definition bootstrap.c:188
int Buffer
Definition buf.h:23
bool EvictUnpinnedBuffer(Buffer buf, bool *buffer_flushed)
Definition bufmgr.c:7736
#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:1036
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 819 of file pg_buffercache_pages.c.

820{
821 Datum result;
822 TupleDesc tupledesc;
823 HeapTuple tuple;
825 bool nulls[NUM_BUFFERCACHE_EVICT_ALL_ELEM] = {0};
826
830
831 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
832 elog(ERROR, "return type must be a row type");
833
834 pg_buffercache_superuser_check("pg_buffercache_evict_all");
835
838
842
843 tuple = heap_form_tuple(tupledesc, values, nulls);
844 result = HeapTupleGetDatum(tuple);
845
846 PG_RETURN_DATUM(result);
847}
void EvictAllUnpinnedBuffers(int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
Definition bufmgr.c:7765
int32_t int32
Definition c.h:596
#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, TYPEFUNC_COMPOSITE, and values.

◆ pg_buffercache_evict_relation()

Datum pg_buffercache_evict_relation ( PG_FUNCTION_ARGS  )

Definition at line 769 of file pg_buffercache_pages.c.

770{
771 Datum result;
772 TupleDesc tupledesc;
773 HeapTuple tuple;
775 bool nulls[NUM_BUFFERCACHE_EVICT_RELATION_ELEM] = {0};
776
777 Oid relOid;
778 Relation rel;
779
783
784 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
785 elog(ERROR, "return type must be a row type");
786
787 pg_buffercache_superuser_check("pg_buffercache_evict_relation");
788
789 relOid = PG_GETARG_OID(0);
790
791 rel = relation_open(relOid, AccessShareLock);
792
796 errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
797 "pg_buffercache_evict_relation")));
798
801
803
807
808 tuple = heap_form_tuple(tupledesc, values, nulls);
809 result = HeapTupleGetDatum(tuple);
810
811 PG_RETURN_DATUM(result);
812}
void EvictRelUnpinnedBuffers(Relation rel, int32 *buffers_evicted, int32 *buffers_flushed, int32 *buffers_skipped)
Definition bufmgr.c:7815
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereport(elevel,...)
Definition elog.h:150
#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: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 853 of file pg_buffercache_pages.c.

854{
855
856 Datum result;
857 TupleDesc tupledesc;
858 HeapTuple tuple;
860 bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ELEM] = {0};
861
864
865 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
866 elog(ERROR, "return type must be a row type");
867
868 pg_buffercache_superuser_check("pg_buffercache_mark_dirty");
869
871 elog(ERROR, "bad buffer ID: %d", buf);
872
875
876 tuple = heap_form_tuple(tupledesc, values, nulls);
877 result = HeapTupleGetDatum(tuple);
878
879 PG_RETURN_DATUM(result);
880}
bool MarkDirtyUnpinnedBuffer(Buffer buf, bool *buffer_already_dirty)
Definition bufmgr.c:7922
#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 935 of file pg_buffercache_pages.c.

936{
937 Datum result;
938 TupleDesc tupledesc;
939 HeapTuple tuple;
941 bool nulls[NUM_BUFFERCACHE_MARK_DIRTY_ALL_ELEM] = {0};
942
946
947 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
948 elog(ERROR, "return type must be a row type");
949
950 pg_buffercache_superuser_check("pg_buffercache_mark_dirty_all");
951
954
958
959 tuple = heap_form_tuple(tupledesc, values, nulls);
960 result = HeapTupleGetDatum(tuple);
961
962 PG_RETURN_DATUM(result);
963}
void MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
Definition bufmgr.c:8015
#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 886 of file pg_buffercache_pages.c.

887{
888 Datum result;
889 TupleDesc tupledesc;
890 HeapTuple tuple;
893
894 Oid relOid;
895 Relation rel;
896
900
901 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
902 elog(ERROR, "return type must be a row type");
903
904 pg_buffercache_superuser_check("pg_buffercache_mark_dirty_relation");
905
906 relOid = PG_GETARG_OID(0);
907
908 rel = relation_open(relOid, AccessShareLock);
909
913 errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only",
914 "pg_buffercache_mark_dirty_relation")));
915
918
920
924
925 tuple = heap_form_tuple(tupledesc, values, nulls);
926 result = HeapTupleGetDatum(tuple);
927
928 PG_RETURN_DATUM(result);
929}
void MarkDirtyRelUnpinnedBuffers(Relation rel, int32 *buffers_dirtied, int32 *buffers_already_dirty, int32 *buffers_skipped)
Definition bufmgr.c:7958
#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 604 of file pg_buffercache_pages.c.

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

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

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

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

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

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, TupleDescFinalize(), TupleDescInitEntry(), TYPEFUNC_COMPOSITE, UInt16GetDatum(), UnlockBufHdr(), and values.

◆ pg_buffercache_summary()

Datum pg_buffercache_summary ( PG_FUNCTION_ARGS  )

Definition at line 611 of file pg_buffercache_pages.c.

612{
613 Datum result;
614 TupleDesc tupledesc;
615 HeapTuple tuple;
618
624
625 if (get_call_result_type(fcinfo, NULL, &tupledesc) != TYPEFUNC_COMPOSITE)
626 elog(ERROR, "return type must be a row type");
627
628 for (int i = 0; i < NBuffers; i++)
629 {
632
634
635 /*
636 * This function summarizes the state of all headers. Locking the
637 * buffer headers wouldn't provide an improved result as the state of
638 * the buffer can still change after we release the lock and it'd
639 * noticeably increase the cost of the function.
640 */
643
644 if (buf_state & BM_VALID)
645 {
646 buffers_used++;
648
649 if (buf_state & BM_DIRTY)
651 }
652 else
654
657 }
658
659 memset(nulls, 0, sizeof(nulls));
664
665 if (buffers_used != 0)
667 else
668 nulls[4] = true;
669
670 /* Build and return the tuple. */
671 tuple = heap_form_tuple(tupledesc, values, nulls);
672 result = HeapTupleGetDatum(tuple);
673
674 PG_RETURN_DATUM(result);
675}
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:502

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

679{
680 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
681 int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0};
682 int dirty[BM_MAX_USAGE_COUNT + 1] = {0};
683 int pinned[BM_MAX_USAGE_COUNT + 1] = {0};
685 bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0};
686
687 InitMaterializedSRF(fcinfo, 0);
688
689 for (int i = 0; i < NBuffers; i++)
690 {
693 int usage_count;
694
696
699
700 if (buf_state & BM_DIRTY)
701 dirty[usage_count]++;
702
704 pinned[usage_count]++;
705 }
706
707 for (int i = 0; i < BM_MAX_USAGE_COUNT + 1; i++)
708 {
709 values[0] = Int32GetDatum(i);
711 values[2] = Int32GetDatum(dirty[i]);
712 values[3] = Int32GetDatum(pinned[i]);
713
714 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
715 }
716
717 return (Datum) 0;
718}
#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:785

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

Referenced by pg_buffercache_os_pages_internal().