PostgreSQL Source Code  git master
mcxtfuncs.c File Reference
#include "postgres.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/hsearch.h"
Include dependency graph for mcxtfuncs.c:

Go to the source code of this file.

Data Structures

struct  MemoryContextId
 

Macros

#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE   1024
 
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS   11
 

Typedefs

typedef struct MemoryContextId MemoryContextId
 

Functions

static void get_memory_context_name_and_ident (MemoryContext context, const char **const name, const char **const ident)
 
static Datum int_list_to_array (const List *list)
 
static void PutMemoryContextsStatsTupleStore (Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, HTAB *context_id_lookup)
 
Datum pg_get_backend_memory_contexts (PG_FUNCTION_ARGS)
 
Datum pg_log_backend_memory_contexts (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ MEMORY_CONTEXT_IDENT_DISPLAY_SIZE

#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE   1024

Definition at line 30 of file mcxtfuncs.c.

◆ PG_GET_BACKEND_MEMORY_CONTEXTS_COLS

#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS   11

Typedef Documentation

◆ MemoryContextId

Function Documentation

◆ get_memory_context_name_and_ident()

static void get_memory_context_name_and_ident ( MemoryContext  context,
const char **const  name,
const char **const  ident 
)
static

Definition at line 48 of file mcxtfuncs.c.

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 }
#define ident
Definition: indent_codes.h:47
tree context
Definition: radixtree.h:1835
const char * name

References context, ident, and name.

Referenced by PutMemoryContextsStatsTupleStore().

◆ int_list_to_array()

static Datum int_list_to_array ( const List list)
static

Definition at line 70 of file mcxtfuncs.c.

71 {
72  Datum *datum_array;
73  int length;
74  ArrayType *result_array;
75 
76  length = list_length(list);
77  datum_array = (Datum *) palloc(length * sizeof(Datum));
78 
80  datum_array[foreach_current_index(i)] = Int32GetDatum(i);
81 
82  result_array = construct_array_builtin(datum_array, length, INT4OID);
83 
84  return PointerGetDatum(result_array);
85 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
int i
Definition: isn.c:73
void * palloc(Size size)
Definition: mcxt.c:1317
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:322
uintptr_t Datum
Definition: postgres.h:64
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212

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

Referenced by PutMemoryContextsStatsTupleStore().

◆ pg_get_backend_memory_contexts()

Datum pg_get_backend_memory_contexts ( PG_FUNCTION_ARGS  )

Definition at line 206 of file mcxtfuncs.c.

207 {
208  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
209  int context_id;
210  List *contexts;
211  HASHCTL ctl;
212  HTAB *context_id_lookup;
213 
214  ctl.keysize = sizeof(MemoryContext);
215  ctl.entrysize = sizeof(MemoryContextId);
216  ctl.hcxt = CurrentMemoryContext;
217 
218  context_id_lookup = hash_create("pg_get_backend_memory_contexts",
219  256,
220  &ctl,
222 
223  InitMaterializedSRF(fcinfo, 0);
224 
225  /*
226  * Here we use a non-recursive algorithm to visit all MemoryContexts
227  * starting with TopMemoryContext. The reason we avoid using a recursive
228  * algorithm is because we want to assign the context_id breadth-first.
229  * I.e. all contexts at level 1 are assigned IDs before contexts at level
230  * 2. Because contexts closer to TopMemoryContext are less likely to
231  * change, this makes the assigned context_id more stable. Otherwise, if
232  * the first child of TopMemoryContext obtained an additional grandchild,
233  * the context_id for the second child of TopMemoryContext would change.
234  */
235  contexts = list_make1(TopMemoryContext);
236 
237  /* TopMemoryContext will always have a context_id of 1 */
238  context_id = 1;
239 
240  foreach_ptr(MemoryContextData, cur, contexts)
241  {
242  MemoryContextId *entry;
243  bool found;
244 
245  /*
246  * Record the context_id that we've assigned to each MemoryContext.
247  * PutMemoryContextsStatsTupleStore needs this to populate the "path"
248  * column with the parent context_ids.
249  */
250  entry = (MemoryContextId *) hash_search(context_id_lookup, &cur,
251  HASH_ENTER, &found);
252  entry->context_id = context_id++;
253  Assert(!found);
254 
256  rsinfo->setDesc,
257  cur,
258  context_id_lookup);
259 
260  /*
261  * Append all children onto the contexts list so they're processed by
262  * subsequent iterations.
263  */
264  for (MemoryContext c = cur->firstchild; c != NULL; c = c->nextchild)
265  contexts = lappend(contexts, c);
266  }
267 
268  hash_destroy(context_id_lookup);
269 
270  return (Datum) 0;
271 }
#define Assert(condition)
Definition: c.h:858
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:865
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:352
struct cursor * cur
Definition: ecpg.c:28
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
@ 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:149
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
struct MemoryContextId MemoryContextId
static void PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore, TupleDesc tupdesc, MemoryContext context, HTAB *context_id_lookup)
Definition: mcxtfuncs.c:92
#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:1853
Definition: dynahash.c:220
Definition: pg_list.h:54
TupleDesc setDesc
Definition: execnodes.h:340
Tuplestorestate * setResult
Definition: execnodes.h:339

References Assert, MemoryContextId::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_log_backend_memory_contexts()

Datum pg_log_backend_memory_contexts ( PG_FUNCTION_ARGS  )

Definition at line 287 of file mcxtfuncs.c.

288 {
289  int pid = PG_GETARG_INT32(0);
290  PGPROC *proc;
291  ProcNumber procNumber = INVALID_PROC_NUMBER;
292 
293  /*
294  * See if the process with given pid is a backend or an auxiliary process.
295  */
296  proc = BackendPidGetProc(pid);
297  if (proc == NULL)
298  proc = AuxiliaryPidGetProc(pid);
299 
300  /*
301  * BackendPidGetProc() and AuxiliaryPidGetProc() return NULL if the pid
302  * isn't valid; but by the time we reach kill(), a process for which we
303  * get a valid proc here might have terminated on its own. There's no way
304  * to acquire a lock on an arbitrary process to prevent that. But since
305  * this mechanism is usually used to debug a backend or an auxiliary
306  * process running and consuming lots of memory, that it might end on its
307  * own first and its memory contexts are not logged is not a problem.
308  */
309  if (proc == NULL)
310  {
311  /*
312  * This is just a warning so a loop-through-resultset will not abort
313  * if one backend terminated on its own during the run.
314  */
316  (errmsg("PID %d is not a PostgreSQL server process", pid)));
317  PG_RETURN_BOOL(false);
318  }
319 
320  procNumber = GetNumberFromPGProc(proc);
321  if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, procNumber) < 0)
322  {
323  /* Again, just a warning to allow loops */
325  (errmsg("could not send signal to process %d: %m", pid)));
326  PG_RETURN_BOOL(false);
327  }
328 
329  PG_RETURN_BOOL(true);
330 }
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define WARNING
Definition: elog.h:36
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define GetNumberFromPGProc(proc)
Definition: proc.h:428
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3200
#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
PGPROC * AuxiliaryPidGetProc(int pid)
Definition: proc.c:1018
Definition: proc.h:157

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 92 of file mcxtfuncs.c.

95 {
96 #define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS 11
97 
101  List *path = NIL;
102  const char *name;
103  const char *ident;
104  const char *type;
105 
107 
108  /*
109  * Figure out the transient context_id of this context and each of its
110  * ancestors.
111  */
112  for (MemoryContext cur = context; cur != NULL; cur = cur->parent)
113  {
114  MemoryContextId *entry;
115  bool found;
116 
117  entry = hash_search(context_id_lookup, &cur, HASH_FIND, &found);
118 
119  if (!found)
120  elog(ERROR, "hash table corrupted");
121  path = lcons_int(entry->context_id, path);
122  }
123 
124  /* Examine the context itself */
125  memset(&stat, 0, sizeof(stat));
126  (*context->methods->stats) (context, NULL, NULL, &stat, true);
127 
128  memset(values, 0, sizeof(values));
129  memset(nulls, 0, sizeof(nulls));
130 
132 
133  if (name)
135  else
136  nulls[0] = true;
137 
138  if (ident)
139  {
140  int idlen = strlen(ident);
141  char clipped_ident[MEMORY_CONTEXT_IDENT_DISPLAY_SIZE];
142 
143  /*
144  * Some identifiers such as SQL query string can be very long,
145  * truncate oversize identifiers.
146  */
149 
150  memcpy(clipped_ident, ident, idlen);
151  clipped_ident[idlen] = '\0';
152  values[1] = CStringGetTextDatum(clipped_ident);
153  }
154  else
155  nulls[1] = true;
156 
157  if (context->parent)
158  {
159  const char *parent_name,
160  *parent_ident;
161 
162  get_memory_context_name_and_ident(context->parent, &parent_name,
163  &parent_ident);
164  values[2] = CStringGetTextDatum(parent_name);
165  }
166  else
167  nulls[2] = true;
168 
169  switch (context->type)
170  {
171  case T_AllocSetContext:
172  type = "AllocSet";
173  break;
174  case T_GenerationContext:
175  type = "Generation";
176  break;
177  case T_SlabContext:
178  type = "Slab";
179  break;
180  case T_BumpContext:
181  type = "Bump";
182  break;
183  default:
184  type = "???";
185  break;
186  }
187 
189  values[4] = Int32GetDatum(list_length(path)); /* level */
190  values[5] = int_list_to_array(path);
191  values[6] = Int64GetDatum(stat.totalspace);
192  values[7] = Int64GetDatum(stat.nblocks);
193  values[8] = Int64GetDatum(stat.freespace);
194  values[9] = Int64GetDatum(stat.freechunks);
195  values[10] = Int64GetDatum(stat.totalspace - stat.freespace);
196 
197  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
198  list_free(path);
199 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
@ 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 void get_memory_context_name_and_ident(MemoryContext context, const char **const name, const char **const ident)
Definition: mcxtfuncs.c:48
static Datum int_list_to_array(const List *list)
Definition: mcxtfuncs.c:70
#define PG_GET_BACKEND_MEMORY_CONTEXTS_COLS
#define MEMORY_CONTEXT_IDENT_DISPLAY_SIZE
Definition: mcxtfuncs.c:30
#define MemoryContextIsValid(context)
Definition: memnodes.h:145
#define NIL
Definition: pg_list.h:68
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:782
const char * type
#define stat
Definition: win32_port.h:284

References Assert, context, MemoryContextId::context_id, CStringGetTextDatum, cur, elog, ERROR, get_memory_context_name_and_ident(), HASH_FIND, hash_search(), ident, Int32GetDatum(), Int64GetDatum(), int_list_to_array(), lcons_int(), list_free(), list_length(), MEMORY_CONTEXT_IDENT_DISPLAY_SIZE, MemoryContextIsValid, name, NIL, PG_GET_BACKEND_MEMORY_CONTEXTS_COLS, pg_mbcliplen(), stat, tuplestore_putvalues(), type, and values.

Referenced by pg_get_backend_memory_contexts().