|
18 | 18 | #include "funcapi.h"
|
19 | 19 | #include "miscadmin.h"
|
20 | 20 | #include "mb/pg_wchar.h"
|
| 21 | +#include "storage/proc.h" |
| 22 | +#include "storage/procarray.h" |
21 | 23 | #include "utils/builtins.h"
|
22 | 24 |
|
23 | 25 | /* ----------
|
@@ -61,7 +63,7 @@ PutMemoryContextsStatsTupleStore(Tuplestorestate *tupstore,
|
61 | 63 |
|
62 | 64 | /* Examine the context itself */
|
63 | 65 | memset(&stat, 0, sizeof(stat));
|
64 |
| - (*context->methods->stats) (context, NULL, (void *) &level, &stat); |
| 66 | + (*context->methods->stats) (context, NULL, (void *) &level, &stat, true); |
65 | 67 |
|
66 | 68 | memset(values, 0, sizeof(values));
|
67 | 69 | memset(nulls, 0, sizeof(nulls));
|
@@ -155,3 +157,59 @@ pg_get_backend_memory_contexts(PG_FUNCTION_ARGS)
|
155 | 157 |
|
156 | 158 | return (Datum) 0;
|
157 | 159 | }
|
| 160 | + |
| 161 | +/* |
| 162 | + * pg_log_backend_memory_contexts |
| 163 | + * Signal a backend process to log its memory contexts. |
| 164 | + * |
| 165 | + * Only superusers are allowed to signal to log the memory contexts |
| 166 | + * because allowing any users to issue this request at an unbounded |
| 167 | + * rate would cause lots of log messages and which can lead to |
| 168 | + * denial of service. |
| 169 | + * |
| 170 | + * On receipt of this signal, a backend sets the flag in the signal |
| 171 | + * handler, which causes the next CHECK_FOR_INTERRUPTS() to log the |
| 172 | + * memory contexts. |
| 173 | + */ |
| 174 | +Datum |
| 175 | +pg_log_backend_memory_contexts(PG_FUNCTION_ARGS) |
| 176 | +{ |
| 177 | + int pid = PG_GETARG_INT32(0); |
| 178 | + PGPROC *proc = BackendPidGetProc(pid); |
| 179 | + |
| 180 | + /* |
| 181 | + * BackendPidGetProc returns NULL if the pid isn't valid; but by the time |
| 182 | + * we reach kill(), a process for which we get a valid proc here might |
| 183 | + * have terminated on its own. There's no way to acquire a lock on an |
| 184 | + * arbitrary process to prevent that. But since this mechanism is usually |
| 185 | + * used to debug a backend running and consuming lots of memory, that it |
| 186 | + * might end on its own first and its memory contexts are not logged is |
| 187 | + * not a problem. |
| 188 | + */ |
| 189 | + if (proc == NULL) |
| 190 | + { |
| 191 | + /* |
| 192 | + * This is just a warning so a loop-through-resultset will not abort |
| 193 | + * if one backend terminated on its own during the run. |
| 194 | + */ |
| 195 | + ereport(WARNING, |
| 196 | + (errmsg("PID %d is not a PostgreSQL server process", pid))); |
| 197 | + PG_RETURN_BOOL(false); |
| 198 | + } |
| 199 | + |
| 200 | + /* Only allow superusers to log memory contexts. */ |
| 201 | + if (!superuser()) |
| 202 | + ereport(ERROR, |
| 203 | + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 204 | + errmsg("must be a superuser to log memory contexts"))); |
| 205 | + |
| 206 | + if (SendProcSignal(pid, PROCSIG_LOG_MEMORY_CONTEXT, proc->backendId) < 0) |
| 207 | + { |
| 208 | + /* Again, just a warning to allow loops */ |
| 209 | + ereport(WARNING, |
| 210 | + (errmsg("could not send signal to process %d: %m", pid))); |
| 211 | + PG_RETURN_BOOL(false); |
| 212 | + } |
| 213 | + |
| 214 | + PG_RETURN_BOOL(true); |
| 215 | +} |
0 commit comments