PostgreSQL Source Code  git master
backend_status.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "libpq/libpq.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "port/atomics.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "storage/sinvaladt.h"
#include "utils/ascii.h"
#include "utils/backend_status.h"
#include "utils/guc.h"
#include "utils/memutils.h"
Include dependency graph for backend_status.c:

Go to the source code of this file.

Macros

#define NumBackendStatSlots   (MaxBackends + NUM_AUXPROCTYPES)
 

Functions

static void pgstat_beshutdown_hook (int code, Datum arg)
 
static void pgstat_read_current_status (void)
 
static void pgstat_setup_backend_status_context (void)
 
Size BackendStatusShmemSize (void)
 
void CreateSharedBackendStatus (void)
 
void pgstat_beinit (void)
 
void pgstat_bestart (void)
 
void pgstat_clear_backend_activity_snapshot (void)
 
void pgstat_report_activity (BackendState state, const char *cmd_str)
 
void pgstat_report_query_id (uint64 query_id, bool force)
 
void pgstat_report_appname (const char *appname)
 
void pgstat_report_xact_timestamp (TimestampTz tstamp)
 
const char * pgstat_get_backend_current_activity (int pid, bool checkUser)
 
const char * pgstat_get_crashed_backend_activity (int pid, char *buffer, int buflen)
 
uint64 pgstat_get_my_query_id (void)
 
PgBackendStatuspgstat_fetch_stat_beentry (int beid)
 
LocalPgBackendStatuspgstat_fetch_stat_local_beentry (int beid)
 
int pgstat_fetch_stat_numbackends (void)
 
char * pgstat_clip_activity (const char *raw_activity)
 

Variables

bool pgstat_track_activities = false
 
int pgstat_track_activity_query_size = 1024
 
PgBackendStatusMyBEEntry = NULL
 
static PgBackendStatusBackendStatusArray = NULL
 
static char * BackendAppnameBuffer = NULL
 
static char * BackendClientHostnameBuffer = NULL
 
static char * BackendActivityBuffer = NULL
 
static Size BackendActivityBufferSize = 0
 
static LocalPgBackendStatuslocalBackendStatusTable = NULL
 
static int localNumBackends = 0
 
static MemoryContext backendStatusSnapContext
 

Macro Definition Documentation

◆ NumBackendStatSlots

#define NumBackendStatSlots   (MaxBackends + NUM_AUXPROCTYPES)

Function Documentation

◆ BackendStatusShmemSize()

Size BackendStatusShmemSize ( void  )

Definition at line 84 of file backend_status.c.

References add_size(), mul_size(), NAMEDATALEN, NumBackendStatSlots, and pgstat_track_activity_query_size.

Referenced by CreateSharedMemoryAndSemaphores().

85 {
86  Size size;
87 
88  /* BackendStatusArray: */
90  /* BackendAppnameBuffer: */
91  size = add_size(size,
93  /* BackendClientHostnameBuffer: */
94  size = add_size(size,
96  /* BackendActivityBuffer: */
97  size = add_size(size,
99 #ifdef USE_SSL
100  /* BackendSslStatusBuffer: */
101  size = add_size(size,
103 #endif
104 #ifdef ENABLE_GSS
105  /* BackendGssStatusBuffer: */
106  size = add_size(size,
108 #endif
109  return size;
110 }
int pgstat_track_activity_query_size
#define NAMEDATALEN
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
size_t Size
Definition: c.h:540
#define NumBackendStatSlots

◆ CreateSharedBackendStatus()

void CreateSharedBackendStatus ( void  )

Definition at line 117 of file backend_status.c.

References BackendActivityBuffer, BackendActivityBufferSize, BackendAppnameBuffer, BackendClientHostnameBuffer, i, MemSet, mul_size(), NAMEDATALEN, NumBackendStatSlots, pgstat_track_activity_query_size, ShmemInitStruct(), PgBackendStatus::st_activity_raw, PgBackendStatus::st_appname, PgBackendStatus::st_clienthostname, PgBackendStatus::st_gssstatus, and PgBackendStatus::st_sslstatus.

Referenced by CreateSharedMemoryAndSemaphores().

118 {
119  Size size;
120  bool found;
121  int i;
122  char *buffer;
123 
124  /* Create or attach to the shared array */
127  ShmemInitStruct("Backend Status Array", size, &found);
128 
129  if (!found)
130  {
131  /*
132  * We're the first - initialize.
133  */
134  MemSet(BackendStatusArray, 0, size);
135  }
136 
137  /* Create or attach to the shared appname buffer */
139  BackendAppnameBuffer = (char *)
140  ShmemInitStruct("Backend Application Name Buffer", size, &found);
141 
142  if (!found)
143  {
144  MemSet(BackendAppnameBuffer, 0, size);
145 
146  /* Initialize st_appname pointers. */
147  buffer = BackendAppnameBuffer;
148  for (i = 0; i < NumBackendStatSlots; i++)
149  {
150  BackendStatusArray[i].st_appname = buffer;
151  buffer += NAMEDATALEN;
152  }
153  }
154 
155  /* Create or attach to the shared client hostname buffer */
157  BackendClientHostnameBuffer = (char *)
158  ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
159 
160  if (!found)
161  {
163 
164  /* Initialize st_clienthostname pointers. */
166  for (i = 0; i < NumBackendStatSlots; i++)
167  {
169  buffer += NAMEDATALEN;
170  }
171  }
172 
173  /* Create or attach to the shared activity buffer */
176  BackendActivityBuffer = (char *)
177  ShmemInitStruct("Backend Activity Buffer",
179  &found);
180 
181  if (!found)
182  {
184 
185  /* Initialize st_activity pointers. */
186  buffer = BackendActivityBuffer;
187  for (i = 0; i < NumBackendStatSlots; i++)
188  {
191  }
192  }
193 
194 #ifdef USE_SSL
195  /* Create or attach to the shared SSL status buffer */
197  BackendSslStatusBuffer = (PgBackendSSLStatus *)
198  ShmemInitStruct("Backend SSL Status Buffer", size, &found);
199 
200  if (!found)
201  {
202  PgBackendSSLStatus *ptr;
203 
204  MemSet(BackendSslStatusBuffer, 0, size);
205 
206  /* Initialize st_sslstatus pointers. */
207  ptr = BackendSslStatusBuffer;
208  for (i = 0; i < NumBackendStatSlots; i++)
209  {
211  ptr++;
212  }
213  }
214 #endif
215 
216 #ifdef ENABLE_GSS
217  /* Create or attach to the shared GSSAPI status buffer */
219  BackendGssStatusBuffer = (PgBackendGSSStatus *)
220  ShmemInitStruct("Backend GSS Status Buffer", size, &found);
221 
222  if (!found)
223  {
224  PgBackendGSSStatus *ptr;
225 
226  MemSet(BackendGssStatusBuffer, 0, size);
227 
228  /* Initialize st_gssstatus pointers. */
229  ptr = BackendGssStatusBuffer;
230  for (i = 0; i < NumBackendStatSlots; i++)
231  {
233  ptr++;
234  }
235  }
236 #endif
237 }
static PgBackendStatus * BackendStatusArray
#define MemSet(start, val, len)
Definition: c.h:1008
int pgstat_track_activity_query_size
char * st_clienthostname
#define NAMEDATALEN
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
static char * BackendActivityBuffer
static Size BackendActivityBufferSize
size_t Size
Definition: c.h:540
static char * BackendAppnameBuffer
int i
PgBackendSSLStatus * st_sslstatus
static char * BackendClientHostnameBuffer
PgBackendGSSStatus * st_gssstatus
#define NumBackendStatSlots

◆ pgstat_beinit()

void pgstat_beinit ( void  )

Definition at line 249 of file backend_status.c.

References Assert, InvalidBackendId, MaxBackends, MyAuxProcType, MyBackendId, NotAnAuxProcess, on_shmem_exit(), and pgstat_beshutdown_hook().

Referenced by AuxiliaryProcessMain(), and InitPostgres().

250 {
251  /* Initialize MyBEEntry */
253  {
256  }
257  else
258  {
259  /* Must be an auxiliary process */
261 
262  /*
263  * Assign the MyBEEntry for an auxiliary process. Since it doesn't
264  * have a BackendId, the slot is statically allocated based on the
265  * auxiliary process type (MyAuxProcType). Backends use slots indexed
266  * in the range from 1 to MaxBackends (inclusive), so we use
267  * MaxBackends + AuxBackendType + 1 as the index of the slot for an
268  * auxiliary process.
269  */
271  }
272 
273  /* Set up a process-exit hook to clean up */
275 }
PgBackendStatus * MyBEEntry
static PgBackendStatus * BackendStatusArray
BackendId MyBackendId
Definition: globals.c:84
int MaxBackends
Definition: globals.c:139
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
#define InvalidBackendId
Definition: backendid.h:23
AuxProcType MyAuxProcType
Definition: bootstrap.c:71
#define Assert(condition)
Definition: c.h:804
static void pgstat_beshutdown_hook(int code, Datum arg)

◆ pgstat_beshutdown_hook()

static void pgstat_beshutdown_hook ( int  code,
Datum  arg 
)
static

Definition at line 458 of file backend_status.c.

References MyBEEntry, PGSTAT_BEGIN_WRITE_ACTIVITY, PGSTAT_END_WRITE_ACTIVITY, and PgBackendStatus::st_procpid.

Referenced by pgstat_beinit().

459 {
460  volatile PgBackendStatus *beentry = MyBEEntry;
461 
462  /*
463  * Clear my status entry, following the protocol of bumping st_changecount
464  * before and after. We use a volatile pointer here to ensure the
465  * compiler doesn't try to get cute.
466  */
468 
469  beentry->st_procpid = 0; /* mark invalid */
470 
471  PGSTAT_END_WRITE_ACTIVITY(beentry);
472 }
PgBackendStatus * MyBEEntry
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
#define PGSTAT_END_WRITE_ACTIVITY(beentry)

◆ pgstat_bestart()

void pgstat_bestart ( void  )

Definition at line 292 of file backend_status.c.

References application_name, Assert, B_BACKEND, B_BG_WORKER, B_WAL_SENDER, be_gssapi_get_auth(), be_gssapi_get_enc(), be_gssapi_get_princ(), be_tls_get_cipher(), be_tls_get_cipher_bits(), be_tls_get_peer_issuer_name(), be_tls_get_peer_serial(), be_tls_get_peer_subject_name(), be_tls_get_version(), GetSessionUserId(), Port::gss, PgBackendGSSStatus::gss_auth, PgBackendGSSStatus::gss_enc, PgBackendGSSStatus::gss_princ, InvalidOid, MemSet, MyBackendType, MyBEEntry, MyDatabaseId, MyProcPid, MyProcPort, MyStartTimestamp, NAMEDATALEN, PGSTAT_BEGIN_WRITE_ACTIVITY, PGSTAT_END_WRITE_ACTIVITY, pgstat_report_appname(), pgstat_track_activity_query_size, PROGRESS_COMMAND_INVALID, Port::raddr, Port::remote_hostname, PgBackendSSLStatus::ssl_bits, PgBackendSSLStatus::ssl_cipher, PgBackendSSLStatus::ssl_client_dn, PgBackendSSLStatus::ssl_client_serial, Port::ssl_in_use, PgBackendSSLStatus::ssl_issuer_dn, PgBackendSSLStatus::ssl_version, PgBackendStatus::st_activity_raw, PgBackendStatus::st_activity_start_timestamp, PgBackendStatus::st_appname, PgBackendStatus::st_backendType, PgBackendStatus::st_changecount, PgBackendStatus::st_clientaddr, PgBackendStatus::st_clienthostname, PgBackendStatus::st_databaseid, PgBackendStatus::st_gss, PgBackendStatus::st_gssstatus, PgBackendStatus::st_proc_start_timestamp, PgBackendStatus::st_procpid, PgBackendStatus::st_progress_command, PgBackendStatus::st_progress_command_target, PgBackendStatus::st_query_id, PgBackendStatus::st_ssl, PgBackendStatus::st_sslstatus, PgBackendStatus::st_state, PgBackendStatus::st_state_start_timestamp, PgBackendStatus::st_userid, PgBackendStatus::st_xact_start_timestamp, STATE_UNDEFINED, strlcpy(), and unvolatize.

Referenced by AuxiliaryProcessMain(), and InitPostgres().

293 {
294  volatile PgBackendStatus *vbeentry = MyBEEntry;
295  PgBackendStatus lbeentry;
296 #ifdef USE_SSL
297  PgBackendSSLStatus lsslstatus;
298 #endif
299 #ifdef ENABLE_GSS
300  PgBackendGSSStatus lgssstatus;
301 #endif
302 
303  /* pgstats state must be initialized from pgstat_beinit() */
304  Assert(vbeentry != NULL);
305 
306  /*
307  * To minimize the time spent modifying the PgBackendStatus entry, and
308  * avoid risk of errors inside the critical section, we first copy the
309  * shared-memory struct to a local variable, then modify the data in the
310  * local variable, then copy the local variable back to shared memory.
311  * Only the last step has to be inside the critical section.
312  *
313  * Most of the data we copy from shared memory is just going to be
314  * overwritten, but the struct's not so large that it's worth the
315  * maintenance hassle to copy only the needful fields.
316  */
317  memcpy(&lbeentry,
318  unvolatize(PgBackendStatus *, vbeentry),
319  sizeof(PgBackendStatus));
320 
321  /* These structs can just start from zeroes each time, though */
322 #ifdef USE_SSL
323  memset(&lsslstatus, 0, sizeof(lsslstatus));
324 #endif
325 #ifdef ENABLE_GSS
326  memset(&lgssstatus, 0, sizeof(lgssstatus));
327 #endif
328 
329  /*
330  * Now fill in all the fields of lbeentry, except for strings that are
331  * out-of-line data. Those have to be handled separately, below.
332  */
333  lbeentry.st_procpid = MyProcPid;
334  lbeentry.st_backendType = MyBackendType;
336  lbeentry.st_activity_start_timestamp = 0;
337  lbeentry.st_state_start_timestamp = 0;
338  lbeentry.st_xact_start_timestamp = 0;
339  lbeentry.st_databaseid = MyDatabaseId;
340 
341  /* We have userid for client-backends, wal-sender and bgworker processes */
342  if (lbeentry.st_backendType == B_BACKEND
343  || lbeentry.st_backendType == B_WAL_SENDER
344  || lbeentry.st_backendType == B_BG_WORKER)
345  lbeentry.st_userid = GetSessionUserId();
346  else
347  lbeentry.st_userid = InvalidOid;
348 
349  /*
350  * We may not have a MyProcPort (eg, if this is the autovacuum process).
351  * If so, use all-zeroes client address, which is dealt with specially in
352  * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
353  */
354  if (MyProcPort)
355  memcpy(&lbeentry.st_clientaddr, &MyProcPort->raddr,
356  sizeof(lbeentry.st_clientaddr));
357  else
358  MemSet(&lbeentry.st_clientaddr, 0, sizeof(lbeentry.st_clientaddr));
359 
360 #ifdef USE_SSL
362  {
363  lbeentry.st_ssl = true;
370  }
371  else
372  {
373  lbeentry.st_ssl = false;
374  }
375 #else
376  lbeentry.st_ssl = false;
377 #endif
378 
379 #ifdef ENABLE_GSS
380  if (MyProcPort && MyProcPort->gss != NULL)
381  {
382  const char *princ = be_gssapi_get_princ(MyProcPort);
383 
384  lbeentry.st_gss = true;
385  lgssstatus.gss_auth = be_gssapi_get_auth(MyProcPort);
386  lgssstatus.gss_enc = be_gssapi_get_enc(MyProcPort);
387  if (princ)
388  strlcpy(lgssstatus.gss_princ, princ, NAMEDATALEN);
389  }
390  else
391  {
392  lbeentry.st_gss = false;
393  }
394 #else
395  lbeentry.st_gss = false;
396 #endif
397 
398  lbeentry.st_state = STATE_UNDEFINED;
401  lbeentry.st_query_id = UINT64CONST(0);
402 
403  /*
404  * we don't zero st_progress_param here to save cycles; nobody should
405  * examine it until st_progress_command has been set to something other
406  * than PROGRESS_COMMAND_INVALID
407  */
408 
409  /*
410  * We're ready to enter the critical section that fills the shared-memory
411  * status entry. We follow the protocol of bumping st_changecount before
412  * and after; and make sure it's even afterwards. We use a volatile
413  * pointer here to ensure the compiler doesn't try to get cute.
414  */
415  PGSTAT_BEGIN_WRITE_ACTIVITY(vbeentry);
416 
417  /* make sure we'll memcpy the same st_changecount back */
418  lbeentry.st_changecount = vbeentry->st_changecount;
419 
420  memcpy(unvolatize(PgBackendStatus *, vbeentry),
421  &lbeentry,
422  sizeof(PgBackendStatus));
423 
424  /*
425  * We can write the out-of-line strings and structs using the pointers
426  * that are in lbeentry; this saves some de-volatilizing messiness.
427  */
428  lbeentry.st_appname[0] = '\0';
431  NAMEDATALEN);
432  else
433  lbeentry.st_clienthostname[0] = '\0';
434  lbeentry.st_activity_raw[0] = '\0';
435  /* Also make sure the last byte in each string area is always 0 */
436  lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
437  lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
439 
440 #ifdef USE_SSL
441  memcpy(lbeentry.st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
442 #endif
443 #ifdef ENABLE_GSS
444  memcpy(lbeentry.st_gssstatus, &lgssstatus, sizeof(PgBackendGSSStatus));
445 #endif
446 
447  PGSTAT_END_WRITE_ACTIVITY(vbeentry);
448 
449  /* Update app name to current GUC setting */
450  if (application_name)
452 }
char ssl_issuer_dn[NAMEDATALEN]
char gss_princ[NAMEDATALEN]
PgBackendStatus * MyBEEntry
char ssl_cipher[NAMEDATALEN]
Oid st_progress_command_target
int MyProcPid
Definition: globals.c:43
struct Port * MyProcPort
Definition: globals.c:46
const char * be_gssapi_get_princ(Port *port)
void pgstat_report_appname(const char *appname)
BackendType MyBackendType
Definition: miscinit.c:62
TimestampTz st_activity_start_timestamp
char ssl_client_dn[NAMEDATALEN]
char ssl_version[NAMEDATALEN]
SockAddr st_clientaddr
#define MemSet(start, val, len)
Definition: c.h:1008
bool ssl_in_use
Definition: libpq-be.h:209
int pgstat_track_activity_query_size
ProgressCommandType st_progress_command
char ssl_client_serial[NAMEDATALEN]
BackendState st_state
char * st_clienthostname
Oid GetSessionUserId(void)
Definition: miscinit.c:512
#define NAMEDATALEN
char * remote_hostname
Definition: libpq-be.h:133
SockAddr raddr
Definition: libpq-be.h:131
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
TimestampTz st_state_start_timestamp
bool be_gssapi_get_enc(Port *port)
TimestampTz MyStartTimestamp
Definition: globals.c:45
int be_tls_get_cipher_bits(Port *port)
Oid MyDatabaseId
Definition: globals.c:88
BackendType st_backendType
#define InvalidOid
Definition: postgres_ext.h:36
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define Assert(condition)
Definition: c.h:804
const char * be_tls_get_version(Port *port)
void be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len)
char * application_name
Definition: guc.c:621
void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len)
void * gss
Definition: libpq-be.h:203
#define PGSTAT_END_WRITE_ACTIVITY(beentry)
#define unvolatize(underlying_type, expr)
Definition: c.h:1245
void be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
TimestampTz st_xact_start_timestamp
const char * be_tls_get_cipher(Port *port)
TimestampTz st_proc_start_timestamp
PgBackendSSLStatus * st_sslstatus
PgBackendGSSStatus * st_gssstatus
bool be_gssapi_get_auth(Port *port)

◆ pgstat_clear_backend_activity_snapshot()

void pgstat_clear_backend_activity_snapshot ( void  )

Definition at line 482 of file backend_status.c.

References localNumBackends, and MemoryContextDelete().

Referenced by pgstat_clear_snapshot().

483 {
484  /* Release memory, if any was allocated */
486  {
489  }
490 
491  /* Reset variables */
493  localNumBackends = 0;
494 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
static MemoryContext backendStatusSnapContext
static LocalPgBackendStatus * localBackendStatusTable
static int localNumBackends

◆ pgstat_clip_activity()

char* pgstat_clip_activity ( const char *  raw_activity)

Definition at line 1114 of file backend_status.c.

References cliplen(), pg_mbcliplen(), pgstat_track_activity_query_size, and pnstrdup().

Referenced by pg_stat_get_activity(), pg_stat_get_backend_activity(), and pgstat_get_backend_current_activity().

1115 {
1116  char *activity;
1117  int rawlen;
1118  int cliplen;
1119 
1120  /*
1121  * Some callers, like pgstat_get_backend_current_activity(), do not
1122  * guarantee that the buffer isn't concurrently modified. We try to take
1123  * care that the buffer is always terminated by a NUL byte regardless, but
1124  * let's still be paranoid about the string's length. In those cases the
1125  * underlying buffer is guaranteed to be pgstat_track_activity_query_size
1126  * large.
1127  */
1128  activity = pnstrdup(raw_activity, pgstat_track_activity_query_size - 1);
1129 
1130  /* now double-guaranteed to be NUL terminated */
1131  rawlen = strlen(activity);
1132 
1133  /*
1134  * All supported server-encodings make it possible to determine the length
1135  * of a multi-byte character from its first byte (this is not the case for
1136  * client encodings, see GB18030). As st_activity is always stored using
1137  * server encoding, this allows us to perform multi-byte aware truncation,
1138  * even if the string earlier was truncated in the middle of a multi-byte
1139  * character.
1140  */
1141  cliplen = pg_mbcliplen(activity, rawlen,
1143 
1144  activity[cliplen] = '\0';
1145 
1146  return activity;
1147 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1310
int pgstat_track_activity_query_size
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1026
static int cliplen(const char *str, int len, int limit)
Definition: mbutils.c:1093

◆ pgstat_fetch_stat_beentry()

◆ pgstat_fetch_stat_local_beentry()

LocalPgBackendStatus* pgstat_fetch_stat_local_beentry ( int  beid)

Definition at line 1079 of file backend_status.c.

References localNumBackends, and pgstat_read_current_status().

Referenced by pg_stat_get_activity(), and pg_stat_get_progress_info().

1080 {
1082 
1083  if (beid < 1 || beid > localNumBackends)
1084  return NULL;
1085 
1086  return &localBackendStatusTable[beid - 1];
1087 }
static LocalPgBackendStatus * localBackendStatusTable
static int localNumBackends
static void pgstat_read_current_status(void)

◆ pgstat_fetch_stat_numbackends()

int pgstat_fetch_stat_numbackends ( void  )

Definition at line 1098 of file backend_status.c.

References localNumBackends, and pgstat_read_current_status().

Referenced by pg_stat_get_activity(), pg_stat_get_backend_idset(), pg_stat_get_db_numbackends(), and pg_stat_get_progress_info().

1099 {
1101 
1102  return localNumBackends;
1103 }
static int localNumBackends
static void pgstat_read_current_status(void)

◆ pgstat_get_backend_current_activity()

const char* pgstat_get_backend_current_activity ( int  pid,
bool  checkUser 
)

Definition at line 889 of file backend_status.c.

References BackendStatusArray, CHECK_FOR_INTERRUPTS, GetUserId(), i, MaxBackends, pgstat_begin_read_activity, pgstat_clip_activity(), pgstat_end_read_activity, pgstat_read_activity_complete, PgBackendStatus::st_activity_raw, PgBackendStatus::st_procpid, PgBackendStatus::st_userid, and superuser().

Referenced by DeadLockReport().

890 {
891  PgBackendStatus *beentry;
892  int i;
893 
894  beentry = BackendStatusArray;
895  for (i = 1; i <= MaxBackends; i++)
896  {
897  /*
898  * Although we expect the target backend's entry to be stable, that
899  * doesn't imply that anyone else's is. To avoid identifying the
900  * wrong backend, while we check for a match to the desired PID we
901  * must follow the protocol of retrying if st_changecount changes
902  * while we examine the entry, or if it's odd. (This might be
903  * unnecessary, since fetching or storing an int is almost certainly
904  * atomic, but let's play it safe.) We use a volatile pointer here to
905  * ensure the compiler doesn't try to get cute.
906  */
907  volatile PgBackendStatus *vbeentry = beentry;
908  bool found;
909 
910  for (;;)
911  {
912  int before_changecount;
913  int after_changecount;
914 
915  pgstat_begin_read_activity(vbeentry, before_changecount);
916 
917  found = (vbeentry->st_procpid == pid);
918 
919  pgstat_end_read_activity(vbeentry, after_changecount);
920 
921  if (pgstat_read_activity_complete(before_changecount,
922  after_changecount))
923  break;
924 
925  /* Make sure we can break out of loop if stuck... */
927  }
928 
929  if (found)
930  {
931  /* Now it is safe to use the non-volatile pointer */
932  if (checkUser && !superuser() && beentry->st_userid != GetUserId())
933  return "<insufficient privilege>";
934  else if (*(beentry->st_activity_raw) == '\0')
935  return "<command string not enabled>";
936  else
937  {
938  /* this'll leak a bit of memory, but that seems acceptable */
939  return pgstat_clip_activity(beentry->st_activity_raw);
940  }
941  }
942 
943  beentry++;
944  }
945 
946  /* If we get here, caller is in error ... */
947  return "<backend information not available>";
948 }
static PgBackendStatus * BackendStatusArray
char * pgstat_clip_activity(const char *raw_activity)
Oid GetUserId(void)
Definition: miscinit.c:478
bool superuser(void)
Definition: superuser.c:46
int MaxBackends
Definition: globals.c:139
#define pgstat_end_read_activity(beentry, after_changecount)
#define pgstat_begin_read_activity(beentry, before_changecount)
int i
#define pgstat_read_activity_complete(before_changecount, after_changecount)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120

◆ pgstat_get_crashed_backend_activity()

const char* pgstat_get_crashed_backend_activity ( int  pid,
char *  buffer,
int  buflen 
)

Definition at line 967 of file backend_status.c.

References ascii_safe_strlcpy(), BackendActivityBuffer, BackendActivityBufferSize, BackendStatusArray, i, MaxBackends, Min, pgstat_track_activity_query_size, PgBackendStatus::st_activity_raw, and PgBackendStatus::st_procpid.

Referenced by LogChildExit().

968 {
969  volatile PgBackendStatus *beentry;
970  int i;
971 
972  beentry = BackendStatusArray;
973 
974  /*
975  * We probably shouldn't get here before shared memory has been set up,
976  * but be safe.
977  */
978  if (beentry == NULL || BackendActivityBuffer == NULL)
979  return NULL;
980 
981  for (i = 1; i <= MaxBackends; i++)
982  {
983  if (beentry->st_procpid == pid)
984  {
985  /* Read pointer just once, so it can't change after validation */
986  const char *activity = beentry->st_activity_raw;
987  const char *activity_last;
988 
989  /*
990  * We mustn't access activity string before we verify that it
991  * falls within the BackendActivityBuffer. To make sure that the
992  * entire string including its ending is contained within the
993  * buffer, subtract one activity length from the buffer size.
994  */
997 
998  if (activity < BackendActivityBuffer ||
999  activity > activity_last)
1000  return NULL;
1001 
1002  /* If no string available, no point in a report */
1003  if (activity[0] == '\0')
1004  return NULL;
1005 
1006  /*
1007  * Copy only ASCII-safe characters so we don't run into encoding
1008  * problems when reporting the message; and be sure not to run off
1009  * the end of memory. As only ASCII characters are reported, it
1010  * doesn't seem necessary to perform multibyte aware clipping.
1011  */
1012  ascii_safe_strlcpy(buffer, activity,
1013  Min(buflen, pgstat_track_activity_query_size));
1014 
1015  return buffer;
1016  }
1017 
1018  beentry++;
1019  }
1020 
1021  /* PID not found */
1022  return NULL;
1023 }
static PgBackendStatus * BackendStatusArray
#define Min(x, y)
Definition: c.h:986
int pgstat_track_activity_query_size
void ascii_safe_strlcpy(char *dest, const char *src, size_t destsiz)
Definition: ascii.c:173
int MaxBackends
Definition: globals.c:139
static char * BackendActivityBuffer
static Size BackendActivityBufferSize
int i

◆ pgstat_get_my_query_id()

uint64 pgstat_get_my_query_id ( void  )

Definition at line 1031 of file backend_status.c.

References PgBackendStatus::st_query_id.

Referenced by ExecSerializePlan(), log_line_prefix(), and write_csvlog().

1032 {
1033  if (!MyBEEntry)
1034  return 0;
1035 
1036  /*
1037  * There's no need for a lock around pgstat_begin_read_activity /
1038  * pgstat_end_read_activity here as it's only called from
1039  * pg_stat_get_activity which is already protected, or from the same
1040  * backend which means that there won't be concurrent writes.
1041  */
1042  return MyBEEntry->st_query_id;
1043 }
PgBackendStatus * MyBEEntry

◆ pgstat_read_current_status()

static void pgstat_read_current_status ( void  )
static

Definition at line 724 of file backend_status.c.

References LocalPgBackendStatus::backend_xid, LocalPgBackendStatus::backend_xmin, BackendIdGetTransactionIds(), LocalPgBackendStatus::backendStatus, BackendStatusArray, CHECK_FOR_INTERRUPTS, i, localNumBackends, MemoryContextAlloc(), MemoryContextAllocHuge(), NAMEDATALEN, NumBackendStatSlots, pgstat_begin_read_activity, pgstat_end_read_activity, pgstat_read_activity_complete, pgstat_setup_backend_status_context(), pgstat_track_activity_query_size, PgBackendStatus::st_activity_raw, PgBackendStatus::st_appname, PgBackendStatus::st_clienthostname, PgBackendStatus::st_gss, PgBackendStatus::st_gssstatus, PgBackendStatus::st_procpid, PgBackendStatus::st_ssl, PgBackendStatus::st_sslstatus, and unvolatize.

Referenced by pgstat_fetch_stat_beentry(), pgstat_fetch_stat_local_beentry(), and pgstat_fetch_stat_numbackends().

725 {
726  volatile PgBackendStatus *beentry;
727  LocalPgBackendStatus *localtable;
728  LocalPgBackendStatus *localentry;
729  char *localappname,
730  *localclienthostname,
731  *localactivity;
732 #ifdef USE_SSL
733  PgBackendSSLStatus *localsslstatus;
734 #endif
735 #ifdef ENABLE_GSS
736  PgBackendGSSStatus *localgssstatus;
737 #endif
738  int i;
739 
741  return; /* already done */
742 
744 
745  /*
746  * Allocate storage for local copy of state data. We can presume that
747  * none of these requests overflow size_t, because we already calculated
748  * the same values using mul_size during shmem setup. However, with
749  * probably-silly values of pgstat_track_activity_query_size and
750  * max_connections, the localactivity buffer could exceed 1GB, so use
751  * "huge" allocation for that one.
752  */
753  localtable = (LocalPgBackendStatus *)
756  localappname = (char *)
759  localclienthostname = (char *)
761  NAMEDATALEN * NumBackendStatSlots);
762  localactivity = (char *)
764  pgstat_track_activity_query_size * NumBackendStatSlots);
765 #ifdef USE_SSL
766  localsslstatus = (PgBackendSSLStatus *)
769 #endif
770 #ifdef ENABLE_GSS
771  localgssstatus = (PgBackendGSSStatus *)
774 #endif
775 
776  localNumBackends = 0;
777 
778  beentry = BackendStatusArray;
779  localentry = localtable;
780  for (i = 1; i <= NumBackendStatSlots; i++)
781  {
782  /*
783  * Follow the protocol of retrying if st_changecount changes while we
784  * copy the entry, or if it's odd. (The check for odd is needed to
785  * cover the case where we are able to completely copy the entry while
786  * the source backend is between increment steps.) We use a volatile
787  * pointer here to ensure the compiler doesn't try to get cute.
788  */
789  for (;;)
790  {
791  int before_changecount;
792  int after_changecount;
793 
794  pgstat_begin_read_activity(beentry, before_changecount);
795 
796  localentry->backendStatus.st_procpid = beentry->st_procpid;
797  /* Skip all the data-copying work if entry is not in use */
798  if (localentry->backendStatus.st_procpid > 0)
799  {
800  memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
801 
802  /*
803  * For each PgBackendStatus field that is a pointer, copy the
804  * pointed-to data, then adjust the local copy of the pointer
805  * field to point at the local copy of the data.
806  *
807  * strcpy is safe even if the string is modified concurrently,
808  * because there's always a \0 at the end of the buffer.
809  */
810  strcpy(localappname, (char *) beentry->st_appname);
811  localentry->backendStatus.st_appname = localappname;
812  strcpy(localclienthostname, (char *) beentry->st_clienthostname);
813  localentry->backendStatus.st_clienthostname = localclienthostname;
814  strcpy(localactivity, (char *) beentry->st_activity_raw);
815  localentry->backendStatus.st_activity_raw = localactivity;
816 #ifdef USE_SSL
817  if (beentry->st_ssl)
818  {
819  memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
820  localentry->backendStatus.st_sslstatus = localsslstatus;
821  }
822 #endif
823 #ifdef ENABLE_GSS
824  if (beentry->st_gss)
825  {
826  memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
827  localentry->backendStatus.st_gssstatus = localgssstatus;
828  }
829 #endif
830  }
831 
832  pgstat_end_read_activity(beentry, after_changecount);
833 
834  if (pgstat_read_activity_complete(before_changecount,
835  after_changecount))
836  break;
837 
838  /* Make sure we can break out of loop if stuck... */
840  }
841 
842  beentry++;
843  /* Only valid entries get included into the local array */
844  if (localentry->backendStatus.st_procpid > 0)
845  {
847  &localentry->backend_xid,
848  &localentry->backend_xmin);
849 
850  localentry++;
851  localappname += NAMEDATALEN;
852  localclienthostname += NAMEDATALEN;
853  localactivity += pgstat_track_activity_query_size;
854 #ifdef USE_SSL
855  localsslstatus++;
856 #endif
857 #ifdef ENABLE_GSS
858  localgssstatus++;
859 #endif
861  }
862  }
863 
864  /* Set the pointer only after completion of a valid table */
865  localBackendStatusTable = localtable;
866 }
static PgBackendStatus * BackendStatusArray
static MemoryContext backendStatusSnapContext
static void pgstat_setup_backend_status_context(void)
TransactionId backend_xmin
static LocalPgBackendStatus * localBackendStatusTable
int pgstat_track_activity_query_size
char * st_clienthostname
static int localNumBackends
#define NAMEDATALEN
TransactionId backend_xid
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition: mcxt.c:1218
#define pgstat_end_read_activity(beentry, after_changecount)
PgBackendStatus backendStatus
void BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin)
Definition: sinvaladt.c:403
#define pgstat_begin_read_activity(beentry, before_changecount)
#define unvolatize(underlying_type, expr)
Definition: c.h:1245
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:863
int i
#define pgstat_read_activity_complete(before_changecount, after_changecount)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
PgBackendSSLStatus * st_sslstatus
PgBackendGSSStatus * st_gssstatus
#define NumBackendStatSlots

◆ pgstat_report_activity()

void pgstat_report_activity ( BackendState  state,
const char *  cmd_str 
)

Definition at line 518 of file backend_status.c.

References GetCurrentStatementStartTimestamp(), GetCurrentTimestamp(), Min, MyBEEntry, MyProc, PGSTAT_BEGIN_WRITE_ACTIVITY, pgstat_count_conn_active_time, pgstat_count_conn_txn_idle_time, PGSTAT_END_WRITE_ACTIVITY, pgstat_track_activities, pgstat_track_activity_query_size, PgBackendStatus::st_activity_raw, PgBackendStatus::st_activity_start_timestamp, PgBackendStatus::st_query_id, PgBackendStatus::st_state, PgBackendStatus::st_state_start_timestamp, PgBackendStatus::st_xact_start_timestamp, STATE_DISABLED, STATE_FASTPATH, STATE_IDLEINTRANSACTION, STATE_IDLEINTRANSACTION_ABORTED, STATE_RUNNING, TimestampDifference(), and PGPROC::wait_event_info.

Referenced by _bt_parallel_build_main(), apply_handle_begin(), apply_handle_begin_prepare(), apply_handle_commit(), apply_handle_commit_prepared(), apply_handle_prepare(), apply_handle_rollback_prepared(), apply_handle_stream_commit(), apply_handle_stream_start(), apply_handle_stream_stop(), apply_spooled_messages(), autovac_report_activity(), autovac_report_workitem(), exec_bind_message(), exec_execute_message(), exec_parse_message(), exec_replication_command(), exec_simple_query(), initialize_worker_spi(), LogicalRepApplyLoop(), parallel_vacuum_main(), ParallelQueryMain(), and PostgresMain().

519 {
520  volatile PgBackendStatus *beentry = MyBEEntry;
521  TimestampTz start_timestamp;
522  TimestampTz current_timestamp;
523  int len = 0;
524 
525  TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
526 
527  if (!beentry)
528  return;
529 
531  {
532  if (beentry->st_state != STATE_DISABLED)
533  {
534  volatile PGPROC *proc = MyProc;
535 
536  /*
537  * track_activities is disabled, but we last reported a
538  * non-disabled state. As our final update, change the state and
539  * clear fields we will not be updating anymore.
540  */
542  beentry->st_state = STATE_DISABLED;
543  beentry->st_state_start_timestamp = 0;
544  beentry->st_activity_raw[0] = '\0';
545  beentry->st_activity_start_timestamp = 0;
546  /* st_xact_start_timestamp and wait_event_info are also disabled */
547  beentry->st_xact_start_timestamp = 0;
548  beentry->st_query_id = UINT64CONST(0);
549  proc->wait_event_info = 0;
550  PGSTAT_END_WRITE_ACTIVITY(beentry);
551  }
552  return;
553  }
554 
555  /*
556  * To minimize the time spent modifying the entry, and avoid risk of
557  * errors inside the critical section, fetch all the needed data first.
558  */
559  start_timestamp = GetCurrentStatementStartTimestamp();
560  if (cmd_str != NULL)
561  {
562  /*
563  * Compute length of to-be-stored string unaware of multi-byte
564  * characters. For speed reasons that'll get corrected on read, rather
565  * than computed every write.
566  */
567  len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
568  }
569  current_timestamp = GetCurrentTimestamp();
570 
571  /*
572  * If the state has changed from "active" or "idle in transaction",
573  * calculate the duration.
574  */
575  if ((beentry->st_state == STATE_RUNNING ||
576  beentry->st_state == STATE_FASTPATH ||
577  beentry->st_state == STATE_IDLEINTRANSACTION ||
579  state != beentry->st_state)
580  {
581  long secs;
582  int usecs;
583 
585  current_timestamp,
586  &secs, &usecs);
587 
588  if (beentry->st_state == STATE_RUNNING ||
589  beentry->st_state == STATE_FASTPATH)
590  pgstat_count_conn_active_time(secs * 1000000 + usecs);
591  else
592  pgstat_count_conn_txn_idle_time(secs * 1000000 + usecs);
593  }
594 
595  /*
596  * Now update the status entry
597  */
599 
600  beentry->st_state = state;
601  beentry->st_state_start_timestamp = current_timestamp;
602 
603  /*
604  * If a new query is started, we reset the query identifier as it'll only
605  * be known after parse analysis, to avoid reporting last query's
606  * identifier.
607  */
608  if (state == STATE_RUNNING)
609  beentry->st_query_id = UINT64CONST(0);
610 
611  if (cmd_str != NULL)
612  {
613  memcpy((char *) beentry->st_activity_raw, cmd_str, len);
614  beentry->st_activity_raw[len] = '\0';
615  beentry->st_activity_start_timestamp = start_timestamp;
616  }
617 
618  PGSTAT_END_WRITE_ACTIVITY(beentry);
619 }
PgBackendStatus * MyBEEntry
uint32 wait_event_info
Definition: proc.h:226
TimestampTz st_activity_start_timestamp
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1580
PGPROC * MyProc
Definition: proc.c:68
int64 TimestampTz
Definition: timestamp.h:39
#define pgstat_count_conn_active_time(n)
Definition: pgstat.h:1064
#define Min(x, y)
Definition: c.h:986
int pgstat_track_activity_query_size
BackendState st_state
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
TimestampTz st_state_start_timestamp
#define pgstat_count_conn_txn_idle_time(n)
Definition: pgstat.h:1066
Definition: regguts.h:317
#define PGSTAT_END_WRITE_ACTIVITY(beentry)
TimestampTz st_xact_start_timestamp
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1656
Definition: proc.h:121
bool pgstat_track_activities
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:807

◆ pgstat_report_appname()

void pgstat_report_appname ( const char *  appname)

Definition at line 668 of file backend_status.c.

References MyBEEntry, NAMEDATALEN, pg_mbcliplen(), PGSTAT_BEGIN_WRITE_ACTIVITY, PGSTAT_END_WRITE_ACTIVITY, and PgBackendStatus::st_appname.

Referenced by assign_application_name(), and pgstat_bestart().

669 {
670  volatile PgBackendStatus *beentry = MyBEEntry;
671  int len;
672 
673  if (!beentry)
674  return;
675 
676  /* This should be unnecessary if GUC did its job, but be safe */
677  len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
678 
679  /*
680  * Update my status entry, following the protocol of bumping
681  * st_changecount before and after. We use a volatile pointer here to
682  * ensure the compiler doesn't try to get cute.
683  */
685 
686  memcpy((char *) beentry->st_appname, appname, len);
687  beentry->st_appname[len] = '\0';
688 
689  PGSTAT_END_WRITE_ACTIVITY(beentry);
690 }
PgBackendStatus * MyBEEntry
#define NAMEDATALEN
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1026
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
#define PGSTAT_END_WRITE_ACTIVITY(beentry)

◆ pgstat_report_query_id()

void pgstat_report_query_id ( uint64  query_id,
bool  force 
)

Definition at line 628 of file backend_status.c.

References MyBEEntry, PGSTAT_BEGIN_WRITE_ACTIVITY, PGSTAT_END_WRITE_ACTIVITY, pgstat_track_activities, and PgBackendStatus::st_query_id.

Referenced by exec_simple_query(), ExecutorStart(), parse_analyze(), parse_analyze_varparams(), and pg_analyze_and_rewrite_params().

629 {
630  volatile PgBackendStatus *beentry = MyBEEntry;
631 
632  /*
633  * if track_activities is disabled, st_query_id should already have been
634  * reset
635  */
636  if (!beentry || !pgstat_track_activities)
637  return;
638 
639  /*
640  * We only report the top-level query identifiers. The stored query_id is
641  * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
642  * with an explicit call to this function using the force flag. If the
643  * saved query identifier is not zero it means that it's not a top-level
644  * command, so ignore the one provided unless it's an explicit call to
645  * reset the identifier.
646  */
647  if (beentry->st_query_id != 0 && !force)
648  return;
649 
650  /*
651  * Update my status entry, following the protocol of bumping
652  * st_changecount before and after. We use a volatile pointer here to
653  * ensure the compiler doesn't try to get cute.
654  */
656  beentry->st_query_id = query_id;
657  PGSTAT_END_WRITE_ACTIVITY(beentry);
658 }
PgBackendStatus * MyBEEntry
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
#define PGSTAT_END_WRITE_ACTIVITY(beentry)
bool pgstat_track_activities

◆ pgstat_report_xact_timestamp()

void pgstat_report_xact_timestamp ( TimestampTz  tstamp)

Definition at line 697 of file backend_status.c.

References MyBEEntry, PGSTAT_BEGIN_WRITE_ACTIVITY, PGSTAT_END_WRITE_ACTIVITY, pgstat_track_activities, and PgBackendStatus::st_xact_start_timestamp.

Referenced by AbortTransaction(), CommitTransaction(), PrepareTransaction(), and StartTransaction().

698 {
699  volatile PgBackendStatus *beentry = MyBEEntry;
700 
701  if (!pgstat_track_activities || !beentry)
702  return;
703 
704  /*
705  * Update my status entry, following the protocol of bumping
706  * st_changecount before and after. We use a volatile pointer here to
707  * ensure the compiler doesn't try to get cute.
708  */
710 
711  beentry->st_xact_start_timestamp = tstamp;
712 
713  PGSTAT_END_WRITE_ACTIVITY(beentry);
714 }
PgBackendStatus * MyBEEntry
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
#define PGSTAT_END_WRITE_ACTIVITY(beentry)
TimestampTz st_xact_start_timestamp
bool pgstat_track_activities

◆ pgstat_setup_backend_status_context()

static void pgstat_setup_backend_status_context ( void  )
static

Definition at line 497 of file backend_status.c.

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, and TopMemoryContext.

Referenced by pgstat_read_current_status().

498 {
501  "Backend Status Snapshot",
503 }
#define AllocSetContextCreate
Definition: memutils.h:173
static MemoryContext backendStatusSnapContext
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:205
MemoryContext TopMemoryContext
Definition: mcxt.c:48

Variable Documentation

◆ BackendActivityBuffer

char* BackendActivityBuffer = NULL
static

◆ BackendActivityBufferSize

Size BackendActivityBufferSize = 0
static

◆ BackendAppnameBuffer

char* BackendAppnameBuffer = NULL
static

Definition at line 54 of file backend_status.c.

Referenced by CreateSharedBackendStatus().

◆ BackendClientHostnameBuffer

char* BackendClientHostnameBuffer = NULL
static

Definition at line 55 of file backend_status.c.

Referenced by CreateSharedBackendStatus().

◆ BackendStatusArray

PgBackendStatus* BackendStatusArray = NULL
static

◆ backendStatusSnapContext

MemoryContext backendStatusSnapContext
static

Definition at line 72 of file backend_status.c.

◆ localBackendStatusTable

LocalPgBackendStatus* localBackendStatusTable = NULL
static

Definition at line 67 of file backend_status.c.

◆ localNumBackends

◆ MyBEEntry

◆ pgstat_track_activities

◆ pgstat_track_activity_query_size