PostgreSQL Source Code git master
Loading...
Searching...
No Matches
mcxtfuncs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * mcxtfuncs.c
4 * Functions to show backend memory context.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/utils/adt/mcxtfuncs.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "funcapi.h"
19#include "mb/pg_wchar.h"
20#include "storage/proc.h"
21#include "storage/procarray.h"
22#include "storage/procsignal.h"
23#include "utils/array.h"
24#include "utils/builtins.h"
25#include "utils/hsearch.h"
26
27/* ----------
28 * The max bytes for showing identifiers of MemoryContext.
29 * ----------
30 */
31#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE 1024
32
33/*
34 * MemoryContextId
35 * Used for storage of transient identifiers for
36 * pg_get_backend_memory_contexts.
37 */
43
44/*
45 * int_list_to_array
46 * Convert an IntList to an array of INT4OIDs.
47 */
48static Datum
50{
52 int length;
54
55 length = list_length(list);
57
58 foreach_int(i, list)
60
62
64}
65
66/*
67 * PutMemoryContextsStatsTupleStore
68 * Add details for the given MemoryContext to 'tupstore'.
69 */
70static void
72 TupleDesc tupdesc, MemoryContext context,
74{
75#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 10
76
80 List *path = NIL;
81 const char *name;
82 const char *ident;
83 const char *type;
84
86
87 /*
88 * Figure out the transient context_id of this context and each of its
89 * ancestors.
90 */
91 for (MemoryContext cur = context; cur != NULL; cur = cur->parent)
92 {
93 MemoryContextId *entry;
94 bool found;
95
96 entry = hash_search(context_id_lookup, &cur, HASH_FIND, &found);
97
98 if (!found)
99 elog(ERROR, "hash table corrupted");
100 path = lcons_int(entry->context_id, path);
101 }
102
103 /* Examine the context itself */
104 memset(&stat, 0, sizeof(stat));
105 (*context->methods->stats) (context, NULL, NULL, &stat, true);
106
107 memset(values, 0, sizeof(values));
108 memset(nulls, 0, sizeof(nulls));
109
110 name = context->name;
111 ident = context->ident;
112
113 /*
114 * To be consistent with logging output, we label dynahash contexts with
115 * just the hash table name as with MemoryContextStatsPrint().
116 */
117 if (ident && strcmp(name, "dynahash") == 0)
118 {
119 name = ident;
120 ident = NULL;
121 }
122
123 if (name)
125 else
126 nulls[0] = true;
127
128 if (ident)
129 {
130 int idlen = strlen(ident);
132
133 /*
134 * Some identifiers such as SQL query string can be very long,
135 * truncate oversize identifiers.
136 */
139
141 clipped_ident[idlen] = '\0';
143 }
144 else
145 nulls[1] = true;
146
147 switch (context->type)
148 {
150 type = "AllocSet";
151 break;
153 type = "Generation";
154 break;
155 case T_SlabContext:
156 type = "Slab";
157 break;
158 case T_BumpContext:
159 type = "Bump";
160 break;
161 default:
162 type = "???";
163 break;
164 }
165
167 values[3] = Int32GetDatum(list_length(path)); /* level */
168 values[4] = int_list_to_array(path);
169 values[5] = Int64GetDatum(stat.totalspace);
170 values[6] = Int64GetDatum(stat.nblocks);
171 values[7] = Int64GetDatum(stat.freespace);
172 values[8] = Int64GetDatum(stat.freechunks);
173 values[9] = Int64GetDatum(stat.totalspace - stat.freespace);
174
175 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
176 list_free(path);
177}
178
179/*
180 * pg_get_backend_memory_contexts
181 * SQL SRF showing backend memory context.
182 */
183Datum
185{
186 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
187 int context_id;
188 List *contexts;
189 HASHCTL ctl;
191
192 ctl.keysize = sizeof(MemoryContext);
193 ctl.entrysize = sizeof(MemoryContextId);
195
196 context_id_lookup = hash_create("pg_get_backend_memory_contexts",
197 256,
198 &ctl,
200
201 InitMaterializedSRF(fcinfo, 0);
202
203 /*
204 * Here we use a non-recursive algorithm to visit all MemoryContexts
205 * starting with TopMemoryContext. The reason we avoid using a recursive
206 * algorithm is because we want to assign the context_id breadth-first.
207 * I.e. all contexts at level 1 are assigned IDs before contexts at level
208 * 2. Because contexts closer to TopMemoryContext are less likely to
209 * change, this makes the assigned context_id more stable. Otherwise, if
210 * the first child of TopMemoryContext obtained an additional grandchild,
211 * the context_id for the second child of TopMemoryContext would change.
212 */
214
215 /* TopMemoryContext will always have a context_id of 1 */
216 context_id = 1;
217
219 {
220 MemoryContextId *entry;
221 bool found;
222
223 /*
224 * Record the context_id that we've assigned to each MemoryContext.
225 * PutMemoryContextsStatsTupleStore needs this to populate the "path"
226 * column with the parent context_ids.
227 */
229 HASH_ENTER, &found);
230 entry->context_id = context_id++;
231 Assert(!found);
232
234 rsinfo->setDesc,
235 cur,
237
238 /*
239 * Append all children onto the contexts list so they're processed by
240 * subsequent iterations.
241 */
242 for (MemoryContext c = cur->firstchild; c != NULL; c = c->nextchild)
244 }
245
247
248 return (Datum) 0;
249}
250
251/*
252 * pg_log_backend_memory_contexts
253 * Signal a backend or an auxiliary process to log its memory contexts.
254 *
255 * By default, only superusers are allowed to signal to log the memory
256 * contexts because allowing any users to issue this request at an unbounded
257 * rate would cause lots of log messages and which can lead to denial of
258 * service. Additional roles can be permitted with GRANT.
259 *
260 * On receipt of this signal, a backend or an auxiliary process sets the flag
261 * in the signal handler, which causes the next CHECK_FOR_INTERRUPTS()
262 * or process-specific interrupt handler to log the memory contexts.
263 */
264Datum
266{
267 int pid = PG_GETARG_INT32(0);
268 PGPROC *proc;
269 ProcNumber procNumber = INVALID_PROC_NUMBER;
270
271 /*
272 * See if the process with given pid is a backend or an auxiliary process.
273 */
274 proc = BackendPidGetProc(pid);
275 if (proc == NULL)
276 proc = AuxiliaryPidGetProc(pid);
277
278 /*
279 * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
280 * isn't valid; but by the time we reach kill(), a process for which we
281 * get a valid proc here might have terminated on its own. There's no way
282 * to acquire a lock on an arbitrary process to prevent that. But since
283 * this mechanism is usually used to debug a backend or an auxiliary
284 * process running and consuming lots of memory, that it might end on its
285 * own first and its memory contexts are not logged is not a problem.
286 */
287 if (proc == NULL)
288 {
289 /*
290 * This is just a warning so a loop-through-resultset will not abort
291 * if one backend terminated on its own during the run.
292 */
294 (errmsg("PID %d is not a PostgreSQL server process", pid)));
295 PG_RETURN_BOOL(false);
296 }
297
298 procNumber = GetNumberFromPGProc(proc);
299 if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, procNumber) < 0)
300 {
301 /* Again, just a warning to allow loops */
303 (errmsg("could not send signal to process %d: %m", pid)));
304 PG_RETURN_BOOL(false);
305 }
306
307 PG_RETURN_BOOL(true);
308}
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
static Datum values[MAXATTR]
Definition bootstrap.c:147
#define CStringGetTextDatum(s)
Definition builtins.h:98
#define Assert(condition)
Definition c.h:885
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:358
void hash_destroy(HTAB *hashp)
Definition dynahash.c:865
struct cursor * cur
Definition ecpg.c:29
int errmsg(const char *fmt,...)
Definition elog.c:1093
#define WARNING
Definition elog.h:36
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_array(type, count)
Definition fe_memutils.h:76
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition funcapi.c:76
@ HASH_FIND
Definition hsearch.h:113
@ 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
#define ident
int i
Definition isn.c:77
List * lappend(List *list, void *datum)
Definition list.c:339
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:1211
MemoryContext TopMemoryContext
Definition mcxt.c:166
MemoryContext CurrentMemoryContext
Definition mcxt.c:160
static Datum int_list_to_array(const List *list)
Definition mcxtfuncs.c:49
static void PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, HTAB *context_id_lookup)
Definition mcxtfuncs.c:71
Datum pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
Definition mcxtfuncs.c:265
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS
#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE
Definition mcxtfuncs.c:31
Datum pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
Definition mcxtfuncs.c:184
#define MemoryContextIsValid(context)
Definition memnodes.h:145
struct MemoryContextData * MemoryContext
Definition palloc.h:36
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
#define foreach_current_index(var_or_cell)
Definition pg_list.h:403
#define list_make1(x1)
Definition pg_list.h:212
#define foreach_ptr(type, var, lst)
Definition pg_list.h:469
#define foreach_int(var, lst)
Definition pg_list.h:470
static Datum Int64GetDatum(int64 X)
Definition postgres.h:423
static Datum PointerGetDatum(const void *X)
Definition postgres.h:352
uint64_t Datum
Definition postgres.h:70
static Datum Int32GetDatum(int32 X)
Definition postgres.h:222
char * c
static int fb(int x)
#define GetNumberFromPGProc(proc)
Definition proc.h:505
PGPROC * BackendPidGetProc(int pid)
Definition procarray.c:3160
#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:286
@ PROCSIG_LOG_MEMORY_CONTEXT
Definition procsignal.h:37
tree ctl
Definition radixtree.h:1838
PGPROC * AuxiliaryPidGetProc(int pid)
Definition proc.c:1083
Size keysize
Definition dynahash.c:237
Definition pg_list.h:54
const char * ident
Definition memnodes.h:132
const MemoryContextMethods * methods
Definition memnodes.h:126
const char * name
Definition memnodes.h:131
MemoryContext context
Definition mcxtfuncs.c:40
void(* stats)(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
Definition memnodes.h:102
Definition proc.h:176
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition tuplestore.c:784
const char * type
const char * name
#define stat
Definition win32_port.h:74