PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
mcxtfuncs.c File Reference
#include "postgres.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "access/twophase.h"
#include "catalog/pg_authid_d.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/acl.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/wait_event_types.h"
Include dependency graph for mcxtfuncs.c:

Go to the source code of this file.

Macros

#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE   1024
 
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS   10
 
#define MEMSTATS_WAIT_TIMEOUT   100
 
#define PG_GET_PROCESS_MEMORY_CONTEXTS_COLS   12
 

Functions

static Datum int_list_to_array (const List *list)
 
static void PutMemoryContextsStatsTupleStore (Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, HTAB *context_id_lookup)
 
const char * ContextTypeToString (NodeTag type)
 
Datum pg_get_backend_memory_contexts (PG_FUNCTION_ARGS)
 
Datum pg_log_backend_memory_contexts (PG_FUNCTION_ARGS)
 
Datum pg_get_process_memory_contexts (PG_FUNCTION_ARGS)
 
Size MemoryContextReportingShmemSize (void)
 
void MemoryContextReportingShmemInit (void)
 

Variables

struct MemoryStatsBackendStatememCxtState = NULL
 
struct MemoryStatsCtlmemCxtArea = NULL
 

Macro Definition Documentation

◆ MEMORY_CONTEXT_IDENT_DISPLAY_SIZE

#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE   1024

Definition at line 36 of file mcxtfuncs.c.

◆ MEMSTATS_WAIT_TIMEOUT

#define MEMSTATS_WAIT_TIMEOUT   100

Definition at line 354 of file mcxtfuncs.c.

◆ PG_GET_BACKEND_MEMORY_CONTEXTS_COLS

#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS   10

◆ PG_GET_PROCESS_MEMORY_CONTEXTS_COLS

#define PG_GET_PROCESS_MEMORY_CONTEXTS_COLS   12

Function Documentation

◆ ContextTypeToString()

const char * ContextTypeToString ( NodeTag  type)

Definition at line 165 of file mcxtfuncs.c.

166{
167 const char *context_type;
168
169 switch (type)
170 {
171 case T_AllocSetContext:
172 context_type = "AllocSet";
173 break;
174 case T_GenerationContext:
175 context_type = "Generation";
176 break;
177 case T_SlabContext:
178 context_type = "Slab";
179 break;
180 case T_BumpContext:
181 context_type = "Bump";
182 break;
183 default:
184 context_type = "???";
185 break;
186 }
187 return context_type;
188}
const char * type

References type.

Referenced by pg_get_process_memory_contexts(), and PutMemoryContextsStatsTupleStore().

◆ int_list_to_array()

static Datum int_list_to_array ( const List list)
static

Definition at line 45 of file mcxtfuncs.c.

46{
47 Datum *datum_array;
48 int length;
49 ArrayType *result_array;
50
51 length = list_length(list);
52 datum_array = (Datum *) palloc(length * sizeof(Datum));
53
55 datum_array[foreach_current_index(i)] = Int32GetDatum(i);
56
57 result_array = construct_array_builtin(datum_array, length, INT4OID);
58
59 return PointerGetDatum(result_array);
60}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
int i
Definition: isn.c:77
void * palloc(Size size)
Definition: mcxt.c:1943
static int list_length(const List *l)
Definition: pg_list.h:152
#define foreach_current_index(var_or_cell)
Definition: pg_list.h:403
#define foreach_int(var, lst)
Definition: pg_list.h:470
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217

References construct_array_builtin(), foreach_current_index, foreach_int, i, Int32GetDatum(), sort-test::list, list_length(), palloc(), and PointerGetDatum().

Referenced by PutMemoryContextsStatsTupleStore().

◆ MemoryContextReportingShmemInit()

void MemoryContextReportingShmemInit ( void  )

Definition at line 637 of file mcxtfuncs.c.

638{
639 bool found;
640
642 ShmemInitStruct("MemoryStatsCtl",
643 sizeof(MemoryStatsCtl), &found);
644
645 if (!found)
646 {
649 }
650
652 ShmemInitStruct("MemoryStatsBackendState",
654 &found);
655
656 if (found)
657 return;
658
659 for (int i = 0; i < (MaxBackends + NUM_AUXILIARY_PROCS); i++)
660 {
664 }
665}
void ConditionVariableInit(ConditionVariable *cv)
#define InvalidDsaPointer
Definition: dsa.h:78
#define DSA_HANDLE_INVALID
Definition: dsa.h:139
int MaxBackends
Definition: globals.c:147
void LWLockInitialize(LWLock *lock, int tranche_id)
Definition: lwlock.c:721
@ LWTRANCHE_MEMORY_CONTEXT_REPORTING_PROC
Definition: lwlock.h:225
@ LWTRANCHE_MEMORY_CONTEXT_REPORTING_STATE
Definition: lwlock.h:224
struct MemoryStatsBackendState * memCxtState
Definition: mcxtfuncs.c:37
struct MemoryStatsCtl * memCxtArea
Definition: mcxtfuncs.c:38
#define NUM_AUXILIARY_PROCS
Definition: proc.h:447
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
dsa_pointer memstats_dsa_pointer
Definition: memutils.h:381
dsa_handle memstats_dsa_handle
Definition: memutils.h:366
LWLock lw_lock
Definition: memutils.h:367

References ConditionVariableInit(), DSA_HANDLE_INVALID, i, InvalidDsaPointer, MemoryStatsCtl::lw_lock, LWLockInitialize(), LWTRANCHE_MEMORY_CONTEXT_REPORTING_PROC, LWTRANCHE_MEMORY_CONTEXT_REPORTING_STATE, MaxBackends, memCxtArea, memCxtState, MemoryStatsCtl::memstats_dsa_handle, MemoryStatsBackendState::memstats_dsa_pointer, NUM_AUXILIARY_PROCS, and ShmemInitStruct().

Referenced by CreateOrAttachShmemStructs().

◆ MemoryContextReportingShmemSize()

Size MemoryContextReportingShmemSize ( void  )

Definition at line 619 of file mcxtfuncs.c.

620{
621 Size sz = 0;
622 Size TotalProcs = 0;
623
624 TotalProcs = add_size(TotalProcs, NUM_AUXILIARY_PROCS);
625 TotalProcs = add_size(TotalProcs, MaxBackends);
626 sz = add_size(sz, mul_size(TotalProcs, sizeof(MemoryStatsBackendState)));
627
628 sz = add_size(sz, sizeof(MemoryStatsCtl));
629
630 return sz;
631}
size_t Size
Definition: c.h:576
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510

References add_size(), MaxBackends, mul_size(), and NUM_AUXILIARY_PROCS.

Referenced by CalculateShmemSize().

◆ pg_get_backend_memory_contexts()

Datum pg_get_backend_memory_contexts ( PG_FUNCTION_ARGS  )

Definition at line 195 of file mcxtfuncs.c.

196{
197 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
198 int context_id;
199 List *contexts;
200 HASHCTL ctl;
201 HTAB *context_id_lookup;
202
203 ctl.keysize = sizeof(MemoryContext);
204 ctl.entrysize = sizeof(MemoryStatsContextId);
206
207 context_id_lookup = hash_create("pg_get_backend_memory_contexts",
208 256,
209 &ctl,
211
212 InitMaterializedSRF(fcinfo, 0);
213
214 /*
215 * Here we use a non-recursive algorithm to visit all MemoryContexts
216 * starting with TopMemoryContext. The reason we avoid using a recursive
217 * algorithm is because we want to assign the context_id breadth-first.
218 * I.e. all contexts at level 1 are assigned IDs before contexts at level
219 * 2. Because contexts closer to TopMemoryContext are less likely to
220 * change, this makes the assigned context_id more stable. Otherwise, if
221 * the first child of TopMemoryContext obtained an additional grandchild,
222 * the context_id for the second child of TopMemoryContext would change.
223 */
224 contexts = list_make1(TopMemoryContext);
225
226 /* TopMemoryContext will always have a context_id of 1 */
227 context_id = 1;
228
230 {
232 bool found;
233
234 /*
235 * Record the context_id that we've assigned to each MemoryContext.
236 * PutMemoryContextsStatsTupleStore needs this to populate the "path"
237 * column with the parent context_ids.
238 */
239 entry = (MemoryStatsContextId *) hash_search(context_id_lookup, &cur,
240 HASH_ENTER, &found);
241 entry->context_id = context_id++;
242 Assert(!found);
243
245 rsinfo->setDesc,
246 cur,
247 context_id_lookup);
248
249 /*
250 * Append all children onto the contexts list so they're processed by
251 * subsequent iterations.
252 */
253 for (MemoryContext c = cur->firstchild; c != NULL; c = c->nextchild)
254 contexts = lappend(contexts, c);
255 }
256
257 hash_destroy(context_id_lookup);
258
259 return (Datum) 0;
260}
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:956
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:866
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
struct cursor * cur
Definition: ecpg.c:29
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
Assert(PointerIsAligned(start, uint64))
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
List * lappend(List *list, void *datum)
Definition: list.c:339
MemoryContext TopMemoryContext
Definition: mcxt.c:165
MemoryContext CurrentMemoryContext
Definition: mcxt.c:159
static void PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, HTAB *context_id_lookup)
Definition: mcxtfuncs.c:67
struct MemoryStatsContextId MemoryStatsContextId
#define list_make1(x1)
Definition: pg_list.h:212
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
char * c
tree ctl
Definition: radixtree.h:1838
Definition: dynahash.c:220
Definition: pg_list.h:54
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358

References Assert(), MemoryStatsContextId::context_id, ctl, cur, CurrentMemoryContext, foreach_ptr, HASH_BLOBS, HASH_CONTEXT, hash_create(), hash_destroy(), HASH_ELEM, HASH_ENTER, hash_search(), InitMaterializedSRF(), lappend(), list_make1, PutMemoryContextsStatsTupleStore(), ReturnSetInfo::setDesc, ReturnSetInfo::setResult, and TopMemoryContext.

◆ pg_get_process_memory_contexts()

Datum pg_get_process_memory_contexts ( PG_FUNCTION_ARGS  )

Definition at line 356 of file mcxtfuncs.c.

357{
358 int pid = PG_GETARG_INT32(0);
359 bool summary = PG_GETARG_BOOL(1);
360 double timeout = PG_GETARG_FLOAT8(2);
361 PGPROC *proc;
362 ProcNumber procNumber = INVALID_PROC_NUMBER;
363 bool proc_is_aux = false;
364 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
365 MemoryStatsEntry *memcxt_info;
366 TimestampTz start_timestamp;
367
368 /*
369 * See if the process with given pid is a backend or an auxiliary process
370 * and remember the type for when we requery the process later.
371 */
372 proc = BackendPidGetProc(pid);
373 if (proc == NULL)
374 {
375 proc = AuxiliaryPidGetProc(pid);
376 proc_is_aux = true;
377 }
378
379 /*
380 * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
381 * isn't valid; this is however not a problem and leave with a WARNING.
382 * See comment in pg_log_backend_memory_contexts for a discussion on this.
383 */
384 if (proc == NULL)
385 {
386 /*
387 * This is just a warning so a loop-through-resultset will not abort
388 * if one backend terminated on its own during the run.
389 */
391 errmsg("PID %d is not a PostgreSQL server process", pid));
393 }
394
395 InitMaterializedSRF(fcinfo, 0);
396
397 procNumber = GetNumberFromPGProc(proc);
398
399 LWLockAcquire(&memCxtState[procNumber].lw_lock, LW_EXCLUSIVE);
400 memCxtState[procNumber].summary = summary;
401 LWLockRelease(&memCxtState[procNumber].lw_lock);
402
403 start_timestamp = GetCurrentTimestamp();
404
405 /*
406 * Send a signal to a PostgreSQL process, informing it we want it to
407 * produce information about its memory contexts.
408 */
409 if (SendProcSignal(pid, PROCSIG_GET_MEMORY_CONTEXT, procNumber) < 0)
410 {
412 errmsg("could not send signal to process %d: %m", pid));
414 }
415
416 /*
417 * Even if the proc has published statistics, the may not be due to the
418 * current request, but previously published stats. Check if the stats
419 * are updated by comparing the timestamp, if the stats are newer than our
420 * previously recorded timestamp from before sending the procsignal, they
421 * must by definition be updated. Wait for the timeout specified by the
422 * user, following which display old statistics if available or return
423 * NULL.
424 */
425 while (1)
426 {
427 long msecs;
428
429 /*
430 * We expect to come out of sleep when the requested process has
431 * finished publishing the statistics, verified using the valid DSA
432 * pointer.
433 *
434 * Make sure that the information belongs to pid we requested
435 * information for, Otherwise loop back and wait for the server
436 * process to finish publishing statistics.
437 */
438 LWLockAcquire(&memCxtState[procNumber].lw_lock, LW_EXCLUSIVE);
439
440 /*
441 * Note in procnumber.h file says that a procNumber can be re-used for
442 * a different backend immediately after a backend exits. In case an
443 * old process' data was there and not updated by the current process
444 * in the slot identified by the procNumber, the pid of the requested
445 * process and the proc_id might not match.
446 */
447 if (memCxtState[procNumber].proc_id == pid)
448 {
449 /*
450 * Break if the latest stats have been read, indicated by
451 * statistics timestamp being newer than the current request
452 * timestamp.
453 */
454 msecs = TimestampDifferenceMilliseconds(start_timestamp,
455 memCxtState[procNumber].stats_timestamp);
456
457 if (DsaPointerIsValid(memCxtState[procNumber].memstats_dsa_pointer)
458 && msecs > 0)
459 break;
460 }
461 LWLockRelease(&memCxtState[procNumber].lw_lock);
462
463 /*
464 * Recheck the state of the backend before sleeping on the condition
465 * variable to ensure the process is still alive. Only check the
466 * relevant process type based on the earlier PID check.
467 */
468 if (proc_is_aux)
469 proc = AuxiliaryPidGetProc(pid);
470 else
471 proc = BackendPidGetProc(pid);
472
473 /*
474 * The process ending during memory context processing is not an
475 * error.
476 */
477 if (proc == NULL)
478 {
480 errmsg("PID %d is no longer a PostgreSQL server process",
481 pid));
483 }
484
485 msecs = TimestampDifferenceMilliseconds(start_timestamp, GetCurrentTimestamp());
486
487 /*
488 * If we haven't already exceeded the timeout value, sleep for the
489 * remainder of the timeout on the condition variable.
490 */
491 if (msecs > 0 && msecs < (timeout * 1000))
492 {
493 /*
494 * Wait for the timeout as defined by the user. If no updated
495 * statistics are available within the allowed time then display
496 * previously published statistics if there are any. If no
497 * previous statistics are available then return NULL. The timer
498 * is defined in milliseconds since that's what the condition
499 * variable sleep uses.
500 */
501 if (ConditionVariableTimedSleep(&memCxtState[procNumber].memcxt_cv,
502 ((timeout * 1000) - msecs), WAIT_EVENT_MEM_CXT_PUBLISH))
503 {
504 LWLockAcquire(&memCxtState[procNumber].lw_lock, LW_EXCLUSIVE);
505 /* Displaying previously published statistics if available */
506 if (DsaPointerIsValid(memCxtState[procNumber].memstats_dsa_pointer))
507 break;
508 else
509 {
510 LWLockRelease(&memCxtState[procNumber].lw_lock);
512 }
513 }
514 }
515 else
516 {
517 LWLockAcquire(&memCxtState[procNumber].lw_lock, LW_EXCLUSIVE);
518 /* Displaying previously published statistics if available */
519 if (DsaPointerIsValid(memCxtState[procNumber].memstats_dsa_pointer))
520 break;
521 else
522 {
523 LWLockRelease(&memCxtState[procNumber].lw_lock);
525 }
526 }
527 }
528
529 /*
530 * We should only reach here with a valid DSA handle, either containing
531 * updated statistics or previously published statistics (identified by
532 * the timestamp.
533 */
535 /* Attach to the dsa area if we have not already done so */
536 if (MemoryStatsDsaArea == NULL)
537 {
539
542 MemoryContextSwitchTo(oldcontext);
544 }
545
546 /*
547 * Backend has finished publishing the stats, project them.
548 */
549 memcxt_info = (MemoryStatsEntry *)
550 dsa_get_address(MemoryStatsDsaArea, memCxtState[procNumber].memstats_dsa_pointer);
551
552#define PG_GET_PROCESS_MEMORY_CONTEXTS_COLS 12
553 for (int i = 0; i < memCxtState[procNumber].total_stats; i++)
554 {
555 ArrayType *path_array;
556 int path_length;
559 char *name;
560 char *ident;
561 Datum *path_datum = NULL;
562 int *path_int = NULL;
563
564 memset(values, 0, sizeof(values));
565 memset(nulls, 0, sizeof(nulls));
566
567 if (DsaPointerIsValid(memcxt_info[i].name))
568 {
569 name = (char *) dsa_get_address(MemoryStatsDsaArea, memcxt_info[i].name);
571 }
572 else
573 nulls[0] = true;
574
575 if (DsaPointerIsValid(memcxt_info[i].ident))
576 {
577 ident = (char *) dsa_get_address(MemoryStatsDsaArea, memcxt_info[i].ident);
579 }
580 else
581 nulls[1] = true;
582
584
585 path_length = memcxt_info[i].path_length;
586 path_datum = (Datum *) palloc(path_length * sizeof(Datum));
587 if (DsaPointerIsValid(memcxt_info[i].path))
588 {
589 path_int = (int *) dsa_get_address(MemoryStatsDsaArea, memcxt_info[i].path);
590 for (int j = 0; j < path_length; j++)
591 path_datum[j] = Int32GetDatum(path_int[j]);
592 path_array = construct_array_builtin(path_datum, path_length, INT4OID);
593 values[3] = PointerGetDatum(path_array);
594 }
595 else
596 nulls[3] = true;
597
598 values[4] = Int32GetDatum(memcxt_info[i].levels);
599 values[5] = Int64GetDatum(memcxt_info[i].totalspace);
600 values[6] = Int64GetDatum(memcxt_info[i].nblocks);
601 values[7] = Int64GetDatum(memcxt_info[i].freespace);
602 values[8] = Int64GetDatum(memcxt_info[i].freechunks);
603 values[9] = Int64GetDatum(memcxt_info[i].totalspace -
604 memcxt_info[i].freespace);
605 values[10] = Int32GetDatum(memcxt_info[i].num_agg_stats);
606 values[11] = TimestampTzGetDatum(memCxtState[procNumber].stats_timestamp);
607
608 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
609 values, nulls);
610 }
611 LWLockRelease(&memCxtState[procNumber].lw_lock);
612
614
616}
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1757
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define CStringGetTextDatum(s)
Definition: builtins.h:97
bool ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
int64 TimestampTz
Definition: timestamp.h:39
dsa_area * dsa_attach(dsa_handle handle)
Definition: dsa.c:510
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
Definition: dsa.c:942
void dsa_pin_mapping(dsa_area *area)
Definition: dsa.c:635
#define DsaPointerIsValid(x)
Definition: dsa.h:106
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define WARNING
Definition: elog.h:36
#define ereport(elevel,...)
Definition: elog.h:149
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
Datum path_length(PG_FUNCTION_ARGS)
Definition: geo_ops.c:1792
#define ident
Definition: indent_codes.h:47
int j
Definition: isn.c:78
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1182
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1902
@ LW_EXCLUSIVE
Definition: lwlock.h:114
dsa_area * MemoryStatsDsaArea
Definition: mcxt.c:175
const char * ContextTypeToString(NodeTag type)
Definition: mcxtfuncs.c:165
#define PG_GET_PROCESS_MEMORY_CONTEXTS_COLS
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define GetNumberFromPGProc(proc)
Definition: proc.h:425
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3196
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int ProcNumber
Definition: procnumber.h:24
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
Definition: procsignal.c:283
@ PROCSIG_GET_MEMORY_CONTEXT
Definition: procsignal.h:38
PGPROC * AuxiliaryPidGetProc(int pid)
Definition: proc.c:1092
Definition: proc.h:163
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52
const char * name

References Assert(), AuxiliaryPidGetProc(), BackendPidGetProc(), ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), construct_array_builtin(), ContextTypeToString(), CStringGetTextDatum, CurrentMemoryContext, dsa_attach(), dsa_get_address(), DSA_HANDLE_INVALID, dsa_pin_mapping(), DsaPointerIsValid, ereport, errmsg(), GetCurrentTimestamp(), GetNumberFromPGProc, i, ident, InitMaterializedSRF(), Int32GetDatum(), Int64GetDatum(), INVALID_PROC_NUMBER, j, LW_EXCLUSIVE, MemoryStatsCtl::lw_lock, LWLockAcquire(), LWLockRelease(), memCxtArea, memCxtState, MemoryContextSwitchTo(), MemoryStatsDsaArea, MemoryStatsCtl::memstats_dsa_handle, name, palloc(), path_length(), PG_GET_PROCESS_MEMORY_CONTEXTS_COLS, PG_GETARG_BOOL, PG_GETARG_FLOAT8, PG_GETARG_INT32, PG_RETURN_NULL, PointerGetDatum(), PROCSIG_GET_MEMORY_CONTEXT, SendProcSignal(), ReturnSetInfo::setDesc, ReturnSetInfo::setResult, MemoryStatsBackendState::summary, TimestampDifferenceMilliseconds(), TimestampTzGetDatum(), TopMemoryContext, MemoryStatsBackendState::total_stats, tuplestore_putvalues(), type, values, and WARNING.

◆ pg_log_backend_memory_contexts()

Datum pg_log_backend_memory_contexts ( PG_FUNCTION_ARGS  )

Definition at line 276 of file mcxtfuncs.c.

277{
278 int pid = PG_GETARG_INT32(0);
279 PGPROC *proc;
280 ProcNumber procNumber = INVALID_PROC_NUMBER;
281
282 /*
283 * See if the process with given pid is a backend or an auxiliary process.
284 */
285 proc = BackendPidGetProc(pid);
286 if (proc == NULL)
287 proc = AuxiliaryPidGetProc(pid);
288
289 /*
290 * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
291 * isn't valid; but by the time we reach kill(), a process for which we
292 * get a valid proc here might have terminated on its own. There's no way
293 * to acquire a lock on an arbitrary process to prevent that. But since
294 * this mechanism is usually used to debug a backend or an auxiliary
295 * process running and consuming lots of memory, that it might end on its
296 * own first and its memory contexts are not logged is not a problem.
297 */
298 if (proc == NULL)
299 {
300 /*
301 * This is just a warning so a loop-through-resultset will not abort
302 * if one backend terminated on its own during the run.
303 */
305 (errmsg("PID %d is not a PostgreSQL server process", pid)));
306 PG_RETURN_BOOL(false);
307 }
308
309 procNumber = GetNumberFromPGProc(proc);
310 if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, procNumber) < 0)
311 {
312 /* Again, just a warning to allow loops */
314 (errmsg("could not send signal to process %d: %m", pid)));
315 PG_RETURN_BOOL(false);
316 }
317
318 PG_RETURN_BOOL(true);
319}
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
@ PROCSIG_LOG_MEMORY_CONTEXT
Definition: procsignal.h:37

References AuxiliaryPidGetProc(), BackendPidGetProc(), ereport, errmsg(), GetNumberFromPGProc, INVALID_PROC_NUMBER, PG_GETARG_INT32, PG_RETURN_BOOL, PROCSIG_LOG_MEMORY_CONTEXT, SendProcSignal(), and WARNING.

◆ PutMemoryContextsStatsTupleStore()

static void PutMemoryContextsStatsTupleStore ( Tuplestorestate tupstore,
TupleDesc  tupdesc,
MemoryContext  context,
HTAB context_id_lookup 
)
static

Definition at line 67 of file mcxtfuncs.c.

70{
71#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 10
72
76 List *path = NIL;
77 const char *name;
78 const char *ident;
79 const char *type;
80
82
83 /*
84 * Figure out the transient context_id of this context and each of its
85 * ancestors.
86 */
87 for (MemoryContext cur = context; cur != NULL; cur = cur->parent)
88 {
90 bool found;
91
92 entry = hash_search(context_id_lookup, &cur, HASH_FIND, &found);
93
94 if (!found)
95 elog(ERROR, "hash table corrupted");
96 path = lcons_int(entry->context_id, path);
97 }
98
99 /* Examine the context itself */
100 memset(&stat, 0, sizeof(stat));
101 (*context->methods->stats) (context, NULL, NULL, &stat, true);
102
103 memset(values, 0, sizeof(values));
104 memset(nulls, 0, sizeof(nulls));
105
106 name = context->name;
107 ident = context->ident;
108
109 /*
110 * To be consistent with logging output, we label dynahash contexts with
111 * just the hash table name as with MemoryContextStatsPrint().
112 */
113 if (ident && strcmp(name, "dynahash") == 0)
114 {
115 name = ident;
116 ident = NULL;
117 }
118
119 if (name)
121 else
122 nulls[0] = true;
123
124 if (ident)
125 {
126 int idlen = strlen(ident);
127 char clipped_ident[MEMORY_CONTEXT_IDENT_DISPLAY_SIZE];
128
129 /*
130 * Some identifiers such as SQL query string can be very long,
131 * truncate oversize identifiers.
132 */
135
136 memcpy(clipped_ident, ident, idlen);
137 clipped_ident[idlen] = '\0';
138 values[1] = CStringGetTextDatum(clipped_ident);
139 }
140 else
141 nulls[1] = true;
142
143 type = ContextTypeToString(context->type);
144
146 values[3] = Int32GetDatum(list_length(path)); /* level */
147 values[4] = int_list_to_array(path);
148 values[5] = Int64GetDatum(stat.totalspace);
149 values[6] = Int64GetDatum(stat.nblocks);
150 values[7] = Int64GetDatum(stat.freespace);
151 values[8] = Int64GetDatum(stat.freechunks);
152 values[9] = Int64GetDatum(stat.totalspace - stat.freespace);
153
154 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
155 list_free(path);
156}
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
@ HASH_FIND
Definition: hsearch.h:113
List * lcons_int(int datum, List *list)
Definition: list.c:513
void list_free(List *list)
Definition: list.c:1546
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
static Datum int_list_to_array(const List *list)
Definition: mcxtfuncs.c:45
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS
#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE
Definition: mcxtfuncs.c:36
#define MemoryContextIsValid(context)
Definition: memnodes.h:145
#define NIL
Definition: pg_list.h:68
const char * ident
Definition: memnodes.h:132
const MemoryContextMethods * methods
Definition: memnodes.h:126
const char * name
Definition: memnodes.h:131
void(* stats)(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
Definition: memnodes.h:102
#define stat
Definition: win32_port.h:274

References Assert(), MemoryStatsContextId::context_id, ContextTypeToString(), CStringGetTextDatum, cur, elog, ERROR, HASH_FIND, hash_search(), MemoryContextData::ident, ident, Int32GetDatum(), Int64GetDatum(), int_list_to_array(), lcons_int(), list_free(), list_length(), MEMORY_CONTEXT_IDENT_DISPLAY_SIZE, MemoryContextIsValid, MemoryContextData::methods, name, MemoryContextData::name, NIL, PG_GET_BACKEND_MEMORY_CONTEXTS_COLS, pg_mbcliplen(), stat, MemoryContextMethods::stats, tuplestore_putvalues(), type, and values.

Referenced by pg_get_backend_memory_contexts().

Variable Documentation

◆ memCxtArea

◆ memCxtState