PostgreSQL Source Code  git master
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-2024, 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 "utils/builtins.h"
23 
24 /* ----------
25  * The max bytes for showing identifiers of MemoryContext.
26  * ----------
27  */
28 #define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE 1024
29 
30 /*
31  * PutMemoryContextsStatsTupleStore
32  * One recursion level for pg_get_backend_memory_contexts.
33  */
34 static void
37  const char *parent, int level)
38 {
39 #define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 9
40 
44  MemoryContext child;
45  const char *name;
46  const char *ident;
47 
49 
50  name = context->name;
51  ident = context->ident;
52 
53  /*
54  * To be consistent with logging output, we label dynahash contexts with
55  * just the hash table name as with MemoryContextStatsPrint().
56  */
57  if (ident && strcmp(name, "dynahash") == 0)
58  {
59  name = ident;
60  ident = NULL;
61  }
62 
63  /* Examine the context itself */
64  memset(&stat, 0, sizeof(stat));
65  (*context->methods->stats) (context, NULL, (void *) &level, &stat, true);
66 
67  memset(values, 0, sizeof(values));
68  memset(nulls, 0, sizeof(nulls));
69 
70  if (name)
72  else
73  nulls[0] = true;
74 
75  if (ident)
76  {
77  int idlen = strlen(ident);
78  char clipped_ident[MEMORY_CONTEXT_IDENT_DISPLAY_SIZE];
79 
80  /*
81  * Some identifiers such as SQL query string can be very long,
82  * truncate oversize identifiers.
83  */
86 
87  memcpy(clipped_ident, ident, idlen);
88  clipped_ident[idlen] = '\0';
89  values[1] = CStringGetTextDatum(clipped_ident);
90  }
91  else
92  nulls[1] = true;
93 
94  if (parent)
95  values[2] = CStringGetTextDatum(parent);
96  else
97  nulls[2] = true;
98 
99  values[3] = Int32GetDatum(level);
100  values[4] = Int64GetDatum(stat.totalspace);
101  values[5] = Int64GetDatum(stat.nblocks);
102  values[6] = Int64GetDatum(stat.freespace);
103  values[7] = Int64GetDatum(stat.freechunks);
104  values[8] = Int64GetDatum(stat.totalspace - stat.freespace);
105  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
106 
107  for (child = context->firstchild; child != NULL; child = child->nextchild)
108  {
109  PutMemoryContextsStatsTupleStore(tupstore, tupdesc,
110  child, name, level + 1);
111  }
112 }
113 
114 /*
115  * pg_get_backend_memory_contexts
116  * SQL SRF showing backend memory context.
117  */
118 Datum
120 {
121  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
122 
123  InitMaterializedSRF(fcinfo, 0);
125  TopMemoryContext, NULL, 0);
126 
127  return (Datum) 0;
128 }
129 
130 /*
131  * pg_log_backend_memory_contexts
132  * Signal a backend or an auxiliary process to log its memory contexts.
133  *
134  * By default, only superusers are allowed to signal to log the memory
135  * contexts because allowing any users to issue this request at an unbounded
136  * rate would cause lots of log messages and which can lead to denial of
137  * service. Additional roles can be permitted with GRANT.
138  *
139  * On receipt of this signal, a backend or an auxiliary process sets the flag
140  * in the signal handler, which causes the next CHECK_FOR_INTERRUPTS()
141  * or process-specific interrupt handler to log the memory contexts.
142  */
143 Datum
145 {
146  int pid = PG_GETARG_INT32(0);
147  PGPROC *proc;
148  ProcNumber procNumber = INVALID_PROC_NUMBER;
149 
150  /*
151  * See if the process with given pid is a backend or an auxiliary process.
152  */
153  proc = BackendPidGetProc(pid);
154  if (proc == NULL)
155  proc = AuxiliaryPidGetProc(pid);
156 
157  /*
158  * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
159  * isn't valid; but by the time we reach kill(), a process for which we
160  * get a valid proc here might have terminated on its own. There's no way
161  * to acquire a lock on an arbitrary process to prevent that. But since
162  * this mechanism is usually used to debug a backend or an auxiliary
163  * process running and consuming lots of memory, that it might end on its
164  * own first and its memory contexts are not logged is not a problem.
165  */
166  if (proc == NULL)
167  {
168  /*
169  * This is just a warning so a loop-through-resultset will not abort
170  * if one backend terminated on its own during the run.
171  */
173  (errmsg("PID %d is not a PostgreSQL server process", pid)));
174  PG_RETURN_BOOL(false);
175  }
176 
177  procNumber = GetNumberFromPGProc(proc);
178  if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, procNumber) < 0)
179  {
180  /* Again, just a warning to allow loops */
182  (errmsg("could not send signal to process %d: %m", pid)));
183  PG_RETURN_BOOL(false);
184  }
185 
186  PG_RETURN_BOOL(true);
187 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define Assert(condition)
Definition: c.h:858
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ereport(elevel,...)
Definition: elog.h:149
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#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:359
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
#define ident
Definition: indent_codes.h:47
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
MemoryContext TopMemoryContext
Definition: mcxt.c:149
Datum pg_log_backend_memory_contexts(PG_FUNCTION_ARGS)
Definition: mcxtfuncs.c:144
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS
static void PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, const char *parent, int level)
Definition: mcxtfuncs.c:35
#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE
Definition: mcxtfuncs.c:28
Datum pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
Definition: mcxtfuncs.c:119
#define MemoryContextIsValid(context)
Definition: memnodes.h:145
uintptr_t Datum
Definition: postgres.h:64
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define GetNumberFromPGProc(proc)
Definition: proc.h:429
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3183
#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:257
@ PROCSIG_LOG_MEMORY_CONTEXT
Definition: procsignal.h:37
tree context
Definition: radixtree.h:1833
PGPROC * AuxiliaryPidGetProc(int pid)
Definition: proc.c:1018
MemoryContext nextchild
Definition: memnodes.h:130
Definition: proc.h:157
TupleDesc setDesc
Definition: execnodes.h:340
Tuplestorestate * setResult
Definition: execnodes.h:339
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:750
const char * name
#define stat
Definition: win32_port.h:284