/* Only need to touch memory once per backend process lifetime */ staticbool firstNumaTouch = true;
Datum
pg_buffercache_pages(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
Datum result;
MemoryContext oldcontext;
BufferCachePagesContext *fctx; /* User function context. */
TupleDesc tupledesc;
TupleDesc expected_tupledesc;
HeapTuple tuple;
if (SRF_IS_FIRSTCALL())
{ int i;
funcctx = SRF_FIRSTCALL_INIT();
/* Switch context when allocating stuff to be used in later calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* Create a user function context for cross-call persistence */
fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext));
/* *Tosmoothlysupportupgradesfromversion1.0ofthisextension *transparentlyhandlethe(non-)existenceofthepinning_backends *column.Weunfortunatelyhavetogettheresulttypeforthat...- *wecan'tusetheresulttypedeterminedbythefunctiondefinition *withoutpotentiallycrashingwhensomebodyusestheold(oreven *wrong)functiondefinitionthough.
*/ if (get_call_result_type(fcinfo, NULL, &expected_tupledesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
if (expected_tupledesc->natts < NUM_BUFFERCACHE_PAGES_MIN_ELEM ||
expected_tupledesc->natts > NUM_BUFFERCACHE_PAGES_ELEM)
elog(ERROR, "incorrect number of output arguments");
/* Note if the buffer is valid, and has storage created */ if ((buf_state & BM_VALID) && (buf_state & BM_TAG_VALID))
fctx->record[i].isvalid = true; else
fctx->record[i].isvalid = false;
UnlockBufHdr(bufHdr, buf_state);
}
}
funcctx = SRF_PERCALL_SETUP();
/* Get the saved state */
fctx = funcctx->user_fctx;
if (funcctx->call_cntr < funcctx->max_calls)
{
uint32 i = funcctx->call_cntr;
Datum values[NUM_BUFFERCACHE_PAGES_ELEM]; bool nulls[NUM_BUFFERCACHE_PAGES_ELEM];
/* *InquireaboutNUMAmemorymappingsforsharedbuffers. * *ReturnsNUMAnodeIDforeachmemorypageusedbythebuffer.Buffersmay *besmallerorlargerthanOSmemorypages.Foreachbufferwereturnone *entryforeachmemorypageusedbythebuffer(ifthebufferissmaller, *itonlyusesapartofonememorypage). * *Weexpectbothsizes(forbuffersandmemorypages)tobeapower-of-2,so *oneisalwaysamultipleoftheother. * *Inordertogetreliableresultswealsoneedtotouchmemorypages,so *thattheinquiryaboutNUMAmemorynodedoesn'treturn-2(whichindicates *unmapped/unallocatedpages).
*/
Datum
pg_buffercache_numa_pages(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
MemoryContext oldcontext;
BufferCacheNumaContext *fctx; /* User function context. */
TupleDesc tupledesc;
TupleDesc expected_tupledesc;
HeapTuple tuple;
Datum result;
if (SRF_IS_FIRSTCALL())
{ int i,
idx;
Size os_page_size; void **os_page_ptrs; int *os_page_status;
uint64 os_page_count; int pages_per_buffer; int max_entries; char *startptr,
*endptr;
if (pg_numa_init() == -1)
elog(ERROR, "libnuma initialization failed or NUMA is not supported on this platform");
/* Used to determine the NUMA node for all OS pages at once */
os_page_ptrs = palloc0(sizeof(void *) * os_page_count);
os_page_status = palloc(sizeof(int) * os_page_count);
/* Fill pointers for all the memory pages. */
idx = 0; for (char *ptr = startptr; ptr < endptr; ptr += os_page_size)
{
os_page_ptrs[idx++] = ptr;
/* Only need to touch memory once per backend process lifetime */ if (firstNumaTouch)
pg_numa_touch_mem_if_required(ptr);
}
/* Query NUMA status for all the pointers */ if (pg_numa_query_pages(0, os_page_count, os_page_ptrs, os_page_status) == -1)
elog(ERROR, "failed NUMA pages inquiry: %m");
/* Initialize the multi-call context, load entries about buffers */
funcctx = SRF_FIRSTCALL_INIT();
/* Switch context when allocating stuff to be used in later calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* Create a user function context for cross-call persistence */
fctx = (BufferCacheNumaContext *) palloc(sizeof(BufferCacheNumaContext));
if (get_call_result_type(fcinfo, NULL, &expected_tupledesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
if (expected_tupledesc->natts != NUM_BUFFERCACHE_NUMA_ELEM)
elog(ERROR, "incorrect number of output arguments");
/* Construct a tuple descriptor for the result rows. */
tupledesc = CreateTemplateTupleDesc(expected_tupledesc->natts);
TupleDescInitEntry(tupledesc, (AttrNumber) 1, "bufferid",
INT4OID, -1, 0);
TupleDescInitEntry(tupledesc, (AttrNumber) 2, "os_page_num",
INT8OID, -1, 0);
TupleDescInitEntry(tupledesc, (AttrNumber) 3, "numa_node",
INT4OID, -1, 0);
/* Lock each buffer header before inspecting. */
buf_state = LockBufHdr(bufHdr);
bufferid = BufferDescriptorGetBuffer(bufHdr);
UnlockBufHdr(bufHdr, buf_state);
/* start of the first page of this buffer */
startptr_buff = (char *) TYPEALIGN_DOWN(os_page_size, buffptr);
/* end of the buffer (no need to align to memory page) */
endptr_buff = buffptr + BLCKSZ;
Assert(startptr_buff < endptr_buff);
/* calculate ID of the first page for this buffer */
page_num = (startptr_buff - startptr) / os_page_size;
/* Add an entry for each OS page overlapping with this buffer. */ for (char *ptr = startptr_buff; ptr < endptr_buff; ptr += os_page_size)
{
fctx->record[idx].bufferid = bufferid;
fctx->record[idx].page_num = page_num;
fctx->record[idx].numa_node = os_page_status[page_num];
/* advance to the next entry/page */
++idx;
++page_num;
}
}
/* Set max calls and remember the user function context. */
funcctx->max_calls = idx;
funcctx->user_fctx = fctx;
/* Remember this backend touched the pages */
firstNumaTouch = false;
}
funcctx = SRF_PERCALL_SETUP();
/* Get the saved state */
fctx = funcctx->user_fctx;
if (funcctx->call_cntr < funcctx->max_calls)
{
uint32 i = funcctx->call_cntr;
Datum values[NUM_BUFFERCACHE_NUMA_ELEM]; bool nulls[NUM_BUFFERCACHE_NUMA_ELEM];
/* status is valid node number */ if (fctx->record[i].numa_node >= 0)
{
values[2] = Int32GetDatum(fctx->record[i].numa_node);
nulls[2] = false;
} else
{ /* some kind of error (e.g. pages moved to swap) */
values[2] = (Datum) 0;
nulls[2] = true;
}
/* Build and return the tuple. */
tuple = heap_form_tuple(fctx->tupdesc, values, nulls);
result = HeapTupleGetDatum(tuple);
Datum
pg_buffercache_summary(PG_FUNCTION_ARGS)
{
Datum result;
TupleDesc tupledesc;
HeapTuple tuple;
Datum values[NUM_BUFFERCACHE_SUMMARY_ELEM]; bool nulls[NUM_BUFFERCACHE_SUMMARY_ELEM];
/* Build and return the tuple. */
tuple = heap_form_tuple(tupledesc, values, nulls);
result = HeapTupleGetDatum(tuple);
PG_RETURN_DATUM(result);
}
Datum
pg_buffercache_usage_counts(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; int usage_counts[BM_MAX_USAGE_COUNT + 1] = {0}; int dirty[BM_MAX_USAGE_COUNT + 1] = {0}; int pinned[BM_MAX_USAGE_COUNT + 1] = {0};
Datum values[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM]; bool nulls[NUM_BUFFERCACHE_USAGE_COUNTS_ELEM] = {0};
InitMaterializedSRF(fcinfo, 0);
for (int i = 0; i < NBuffers; i++)
{
BufferDesc *bufHdr = GetBufferDescriptor(i);
uint32 buf_state = pg_atomic_read_u32(&bufHdr->state); int usage_count;
/* *Helperfunctiontocheckiftheuserhassuperuserprivileges.
*/ staticvoid
pg_buffercache_superuser_check(char *func_name)
{ if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to use %s()",
func_name)));
}
/* *Trytoevictasharedbuffer.
*/
Datum
pg_buffercache_evict(PG_FUNCTION_ARGS)
{
Datum result;
TupleDesc tupledesc;
HeapTuple tuple;
Datum values[NUM_BUFFERCACHE_EVICT_ELEM]; bool nulls[NUM_BUFFERCACHE_EVICT_ELEM] = {0};
if (RelationUsesLocalBuffers(rel))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("relation uses local buffers, %s() is intended to be used for shared buffers only", "pg_buffercache_evict_relation")));
tuple = heap_form_tuple(tupledesc, values, nulls);
result = HeapTupleGetDatum(tuple);
PG_RETURN_DATUM(result);
}
Messung V0.5 in Prozent
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.63Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.