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