1/*-------------------------------------------------------------------------
4 * Functions to show backend memory context.
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/mcxtfuncs.c
13 *-------------------------------------------------------------------------
27 * The max bytes for showing identifiers of MemoryContext.
30 #define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE 1024
34 * Used for storage of transient identifiers for
35 * pg_get_backend_memory_contexts.
45 * Convert an IntList to an array of INT4OIDs.
66 * PutMemoryContextsStatsTupleStore
67 * Add details for the given MemoryContext to 'tupstore'.
72 HTAB *context_id_lookup)
74#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 10
87 * Figure out the transient context_id of this context and each of its
102 /* Examine the context itself */
107 memset(nulls, 0,
sizeof(nulls));
113 * To be consistent with logging output, we label dynahash contexts with
114 * just the hash table name as with MemoryContextStatsPrint().
116 if (
ident && strcmp(
name,
"dynahash") == 0)
129 int idlen = strlen(
ident);
133 * Some identifiers such as SQL query string can be very long,
134 * truncate oversize identifiers.
139 memcpy(clipped_ident,
ident, idlen);
140 clipped_ident[idlen] =
'0円';
146 switch (context->type)
148 case T_AllocSetContext:
151 case T_GenerationContext:
179 * pg_get_backend_memory_contexts
180 * SQL SRF showing backend memory context.
189 HTAB *context_id_lookup;
195 context_id_lookup =
hash_create(
"pg_get_backend_memory_contexts",
203 * Here we use a non-recursive algorithm to visit all MemoryContexts
204 * starting with TopMemoryContext. The reason we avoid using a recursive
205 * algorithm is because we want to assign the context_id breadth-first.
206 * I.e. all contexts at level 1 are assigned IDs before contexts at level
207 * 2. Because contexts closer to TopMemoryContext are less likely to
208 * change, this makes the assigned context_id more stable. Otherwise, if
209 * the first child of TopMemoryContext obtained an additional grandchild,
210 * the context_id for the second child of TopMemoryContext would change.
214 /* TopMemoryContext will always have a context_id of 1 */
223 * Record the context_id that we've assigned to each MemoryContext.
224 * PutMemoryContextsStatsTupleStore needs this to populate the "path"
225 * column with the parent context_ids.
238 * Append all children onto the contexts list so they're processed by
239 * subsequent iterations.
251 * pg_log_backend_memory_contexts
252 * Signal a backend or an auxiliary process to log its memory contexts.
254 * By default, only superusers are allowed to signal to log the memory
255 * contexts because allowing any users to issue this request at an unbounded
256 * rate would cause lots of log messages and which can lead to denial of
257 * service. Additional roles can be permitted with GRANT.
259 * On receipt of this signal, a backend or an auxiliary process sets the flag
260 * in the signal handler, which causes the next CHECK_FOR_INTERRUPTS()
261 * or process-specific interrupt handler to log the memory contexts.
271 * See if the process with given pid is a backend or an auxiliary process.
278 * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
279 * isn't valid; but by the time we reach kill(), a process for which we
280 * get a valid proc here might have terminated on its own. There's no way
281 * to acquire a lock on an arbitrary process to prevent that. But since
282 * this mechanism is usually used to debug a backend or an auxiliary
283 * process running and consuming lots of memory, that it might end on its
284 * own first and its memory contexts are not logged is not a problem.
289 * This is just a warning so a loop-through-resultset will not abort
290 * if one backend terminated on its own during the run.
293 (
errmsg(
"PID %d is not a PostgreSQL server process", pid)));
300 /* Again, just a warning to allow loops */
302 (
errmsg(
"could not send signal to process %d: %m", pid)));
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
void hash_destroy(HTAB *hashp)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define PG_GETARG_INT32(n)
#define PG_RETURN_BOOL(x)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Assert(PointerIsAligned(start, uint64))
List * lappend(List *list, void *datum)
List * lcons_int(int datum, List *list)
void list_free(List *list)
int pg_mbcliplen(const char *mbstr, int len, int limit)
MemoryContext TopMemoryContext
MemoryContext CurrentMemoryContext
struct MemoryContextId MemoryContextId
static Datum int_list_to_array(const List *list)
static void PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, HTAB *context_id_lookup)
Datum pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS
#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE
Datum pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
#define MemoryContextIsValid(context)
static int list_length(const List *l)
#define foreach_current_index(var_or_cell)
#define foreach_ptr(type, var, lst)
#define foreach_int(var, lst)
static Datum Int64GetDatum(int64 X)
static Datum PointerGetDatum(const void *X)
static Datum Int32GetDatum(int32 X)
#define GetNumberFromPGProc(proc)
PGPROC * BackendPidGetProc(int pid)
#define INVALID_PROC_NUMBER
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
@ PROCSIG_LOG_MEMORY_CONTEXT
PGPROC * AuxiliaryPidGetProc(int pid)
const MemoryContextMethods * methods
void(* stats)(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
Tuplestorestate * setResult
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)