PostgreSQL Source Code  git master
backend_status.c File Reference
#include "postgres.h"
#include "access/xact.h"
#include "libpq/libpq-be.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/ascii.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_AUXILIARY_PROCS)
 

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 BackendStatusShmemInit (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)
 
static int cmp_lbestatus (const void *a, const void *b)
 
PgBackendStatuspgstat_get_beentry_by_proc_number (ProcNumber procNumber)
 
LocalPgBackendStatuspgstat_get_local_beentry_by_proc_number (ProcNumber procNumber)
 
LocalPgBackendStatuspgstat_get_local_beentry_by_index (int idx)
 
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_AUXILIARY_PROCS)

Definition at line 35 of file backend_status.c.

Function Documentation

◆ BackendStatusShmemInit()

void BackendStatusShmemInit ( void  )

Definition at line 114 of file backend_status.c.

115 {
116  Size size;
117  bool found;
118  int i;
119  char *buffer;
120 
121  /* Create or attach to the shared array */
124  ShmemInitStruct("Backend Status Array", size, &found);
125 
126  if (!found)
127  {
128  /*
129  * We're the first - initialize.
130  */
132  }
133 
134  /* Create or attach to the shared appname buffer */
136  BackendAppnameBuffer = (char *)
137  ShmemInitStruct("Backend Application Name Buffer", size, &found);
138 
139  if (!found)
140  {
142 
143  /* Initialize st_appname pointers. */
144  buffer = BackendAppnameBuffer;
145  for (i = 0; i < NumBackendStatSlots; i++)
146  {
147  BackendStatusArray[i].st_appname = buffer;
148  buffer += NAMEDATALEN;
149  }
150  }
151 
152  /* Create or attach to the shared client hostname buffer */
154  BackendClientHostnameBuffer = (char *)
155  ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
156 
157  if (!found)
158  {
160 
161  /* Initialize st_clienthostname pointers. */
163  for (i = 0; i < NumBackendStatSlots; i++)
164  {
166  buffer += NAMEDATALEN;
167  }
168  }
169 
170  /* Create or attach to the shared activity buffer */
173  BackendActivityBuffer = (char *)
174  ShmemInitStruct("Backend Activity Buffer",
176  &found);
177 
178  if (!found)
179  {
181 
182  /* Initialize st_activity pointers. */
183  buffer = BackendActivityBuffer;
184  for (i = 0; i < NumBackendStatSlots; i++)
185  {
188  }
189  }
190 
191 #ifdef USE_SSL
192  /* Create or attach to the shared SSL status buffer */
194  BackendSslStatusBuffer = (PgBackendSSLStatus *)
195  ShmemInitStruct("Backend SSL Status Buffer", size, &found);
196 
197  if (!found)
198  {
199  PgBackendSSLStatus *ptr;
200 
201  MemSet(BackendSslStatusBuffer, 0, size);
202 
203  /* Initialize st_sslstatus pointers. */
204  ptr = BackendSslStatusBuffer;
205  for (i = 0; i < NumBackendStatSlots; i++)
206  {
208  ptr++;
209  }
210  }
211 #endif
212 
213 #ifdef ENABLE_GSS
214  /* Create or attach to the shared GSSAPI status buffer */
216  BackendGssStatusBuffer = (PgBackendGSSStatus *)
217  ShmemInitStruct("Backend GSS Status Buffer", size, &found);
218 
219  if (!found)
220  {
221  PgBackendGSSStatus *ptr;
222 
223  MemSet(BackendGssStatusBuffer, 0, size);
224 
225  /* Initialize st_gssstatus pointers. */
226  ptr = BackendGssStatusBuffer;
227  for (i = 0; i < NumBackendStatSlots; i++)
228  {
230  ptr++;
231  }
232  }
233 #endif
234 }
#define NumBackendStatSlots
static char * BackendClientHostnameBuffer
static char * BackendActivityBuffer
static char * BackendAppnameBuffer
static PgBackendStatus * BackendStatusArray
static Size BackendActivityBufferSize
int pgstat_track_activity_query_size
#define MemSet(start, val, len)
Definition: c.h:1023
size_t Size
Definition: c.h:608
int i
Definition: isn.c:72
#define NAMEDATALEN
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
static pg_noinline void Size size
Definition: slab.c:607
PgBackendGSSStatus * st_gssstatus
PgBackendSSLStatus * st_sslstatus
char * st_clienthostname

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

Referenced by CreateOrAttachShmemStructs().

◆ BackendStatusShmemSize()

Size BackendStatusShmemSize ( void  )

Definition at line 81 of file backend_status.c.

82 {
83  Size size;
84 
85  /* BackendStatusArray: */
87  /* BackendAppnameBuffer: */
88  size = add_size(size,
90  /* BackendClientHostnameBuffer: */
91  size = add_size(size,
93  /* BackendActivityBuffer: */
94  size = add_size(size,
96 #ifdef USE_SSL
97  /* BackendSslStatusBuffer: */
98  size = add_size(size,
100 #endif
101 #ifdef ENABLE_GSS
102  /* BackendGssStatusBuffer: */
103  size = add_size(size,
105 #endif
106  return size;
107 }
Size add_size(Size s1, Size s2)
Definition: shmem.c:493

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

Referenced by CalculateShmemSize().

◆ cmp_lbestatus()

static int cmp_lbestatus ( const void *  a,
const void *  b 
)
static

Definition at line 1047 of file backend_status.c.

1048 {
1049  const LocalPgBackendStatus *lbestatus1 = (const LocalPgBackendStatus *) a;
1050  const LocalPgBackendStatus *lbestatus2 = (const LocalPgBackendStatus *) b;
1051 
1052  return lbestatus1->proc_number - lbestatus2->proc_number;
1053 }
int b
Definition: isn.c:69
int a
Definition: isn.c:68

References a, b, and LocalPgBackendStatus::proc_number.

Referenced by pgstat_get_local_beentry_by_proc_number().

◆ pgstat_beinit()

void pgstat_beinit ( void  )

Definition at line 245 of file backend_status.c.

246 {
247  /* Initialize MyBEEntry */
251 
252  /* Set up a process-exit hook to clean up */
254 }
PgBackendStatus * MyBEEntry
static void pgstat_beshutdown_hook(int code, Datum arg)
#define Assert(condition)
Definition: c.h:861
ProcNumber MyProcNumber
Definition: globals.c:89
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26

References Assert, BackendStatusArray, INVALID_PROC_NUMBER, MyBEEntry, MyProcNumber, NumBackendStatSlots, on_shmem_exit(), and pgstat_beshutdown_hook().

Referenced by AuxiliaryProcessMainCommon(), and InitPostgres().

◆ pgstat_beshutdown_hook()

static void pgstat_beshutdown_hook ( int  code,
Datum  arg 
)
static

Definition at line 438 of file backend_status.c.

439 {
440  volatile PgBackendStatus *beentry = MyBEEntry;
441 
442  /*
443  * Clear my status entry, following the protocol of bumping st_changecount
444  * before and after. We use a volatile pointer here to ensure the
445  * compiler doesn't try to get cute.
446  */
448 
449  beentry->st_procpid = 0; /* mark invalid */
450 
451  PGSTAT_END_WRITE_ACTIVITY(beentry);
452 
453  /* so that functions can check if backend_status.c is up via MyBEEntry */
454  MyBEEntry = NULL;
455 }
#define PGSTAT_END_WRITE_ACTIVITY(beentry)
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)

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

Referenced by pgstat_beinit().

◆ pgstat_bestart()

void pgstat_bestart ( void  )

Definition at line 271 of file backend_status.c.

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

References application_name, Assert, B_BACKEND, B_BG_WORKER, B_WAL_SENDER, be_gssapi_get_auth(), be_gssapi_get_delegation(), 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_delegation, 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 AuxiliaryProcessMainCommon(), and InitPostgres().

◆ pgstat_clear_backend_activity_snapshot()

void pgstat_clear_backend_activity_snapshot ( void  )

Definition at line 465 of file backend_status.c.

466 {
467  /* Release memory, if any was allocated */
469  {
472  }
473 
474  /* Reset variables */
476  localNumBackends = 0;
477 }
static LocalPgBackendStatus * localBackendStatusTable
static int localNumBackends
static MemoryContext backendStatusSnapContext
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References backendStatusSnapContext, localBackendStatusTable, localNumBackends, and MemoryContextDelete().

Referenced by pgstat_clear_snapshot().

◆ pgstat_clip_activity()

char* pgstat_clip_activity ( const char *  raw_activity)

Definition at line 1162 of file backend_status.c.

1163 {
1164  char *activity;
1165  int rawlen;
1166  int cliplen;
1167 
1168  /*
1169  * Some callers, like pgstat_get_backend_current_activity(), do not
1170  * guarantee that the buffer isn't concurrently modified. We try to take
1171  * care that the buffer is always terminated by a NUL byte regardless, but
1172  * let's still be paranoid about the string's length. In those cases the
1173  * underlying buffer is guaranteed to be pgstat_track_activity_query_size
1174  * large.
1175  */
1176  activity = pnstrdup(raw_activity, pgstat_track_activity_query_size - 1);
1177 
1178  /* now double-guaranteed to be NUL terminated */
1179  rawlen = strlen(activity);
1180 
1181  /*
1182  * All supported server-encodings make it possible to determine the length
1183  * of a multi-byte character from its first byte (this is not the case for
1184  * client encodings, see GB18030). As st_activity is always stored using
1185  * server encoding, this allows us to perform multi-byte aware truncation,
1186  * even if the string earlier was truncated in the middle of a multi-byte
1187  * character.
1188  */
1189  cliplen = pg_mbcliplen(activity, rawlen,
1191 
1192  activity[cliplen] = '\0';
1193 
1194  return activity;
1195 }
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1083
static int cliplen(const char *str, int len, int limit)
Definition: mbutils.c:1150
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1707

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().

◆ pgstat_fetch_stat_numbackends()

int pgstat_fetch_stat_numbackends ( void  )

Definition at line 1146 of file backend_status.c.

1147 {
1149 
1150  return localNumBackends;
1151 }
static void pgstat_read_current_status(void)

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().

◆ pgstat_get_backend_current_activity()

const char* pgstat_get_backend_current_activity ( int  pid,
bool  checkUser 
)

Definition at line 883 of file backend_status.c.

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

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().

◆ pgstat_get_beentry_by_proc_number()

◆ pgstat_get_crashed_backend_activity()

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

Definition at line 961 of file backend_status.c.

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

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().

◆ pgstat_get_local_beentry_by_index()

LocalPgBackendStatus* pgstat_get_local_beentry_by_index ( int  idx)

Definition at line 1126 of file backend_status.c.

1127 {
1129 
1130  if (idx < 1 || idx > localNumBackends)
1131  return NULL;
1132 
1133  return &localBackendStatusTable[idx - 1];
1134 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259

References idx(), localBackendStatusTable, 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().

◆ pgstat_get_local_beentry_by_proc_number()

LocalPgBackendStatus* pgstat_get_local_beentry_by_proc_number ( ProcNumber  procNumber)

Definition at line 1095 of file backend_status.c.

1096 {
1098 
1100 
1101  /*
1102  * Since the localBackendStatusTable is in order by proc_number, we can
1103  * use bsearch() to search it efficiently.
1104  */
1105  key.proc_number = procNumber;
1106  return bsearch(&key, localBackendStatusTable, localNumBackends,
1108 }
static int cmp_lbestatus(const void *a, const void *b)

References cmp_lbestatus(), sort-test::key, localBackendStatusTable, localNumBackends, and pgstat_read_current_status().

Referenced by pg_stat_get_backend_subxact(), and pgstat_get_beentry_by_proc_number().

◆ pgstat_get_my_query_id()

uint64 pgstat_get_my_query_id ( void  )

Definition at line 1025 of file backend_status.c.

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

References MyBEEntry, and PgBackendStatus::st_query_id.

Referenced by _brin_begin_parallel(), _bt_begin_parallel(), ExecSerializePlan(), log_status_format(), parallel_vacuum_init(), write_csvlog(), and write_jsonlog().

◆ pgstat_read_current_status()

static void pgstat_read_current_status ( void  )
static

Definition at line 707 of file backend_status.c.

708 {
709  volatile PgBackendStatus *beentry;
710  LocalPgBackendStatus *localtable;
711  LocalPgBackendStatus *localentry;
712  char *localappname,
713  *localclienthostname,
714  *localactivity;
715 #ifdef USE_SSL
716  PgBackendSSLStatus *localsslstatus;
717 #endif
718 #ifdef ENABLE_GSS
719  PgBackendGSSStatus *localgssstatus;
720 #endif
721  ProcNumber procNumber;
722 
724  return; /* already done */
725 
727 
728  /*
729  * Allocate storage for local copy of state data. We can presume that
730  * none of these requests overflow size_t, because we already calculated
731  * the same values using mul_size during shmem setup. However, with
732  * probably-silly values of pgstat_track_activity_query_size and
733  * max_connections, the localactivity buffer could exceed 1GB, so use
734  * "huge" allocation for that one.
735  */
736  localtable = (LocalPgBackendStatus *)
739  localappname = (char *)
742  localclienthostname = (char *)
745  localactivity = (char *)
749 #ifdef USE_SSL
750  localsslstatus = (PgBackendSSLStatus *)
753 #endif
754 #ifdef ENABLE_GSS
755  localgssstatus = (PgBackendGSSStatus *)
758 #endif
759 
760  localNumBackends = 0;
761 
762  beentry = BackendStatusArray;
763  localentry = localtable;
764  for (procNumber = 0; procNumber < NumBackendStatSlots; procNumber++)
765  {
766  /*
767  * Follow the protocol of retrying if st_changecount changes while we
768  * copy the entry, or if it's odd. (The check for odd is needed to
769  * cover the case where we are able to completely copy the entry while
770  * the source backend is between increment steps.) We use a volatile
771  * pointer here to ensure the compiler doesn't try to get cute.
772  */
773  for (;;)
774  {
775  int before_changecount;
776  int after_changecount;
777 
778  pgstat_begin_read_activity(beentry, before_changecount);
779 
780  localentry->backendStatus.st_procpid = beentry->st_procpid;
781  /* Skip all the data-copying work if entry is not in use */
782  if (localentry->backendStatus.st_procpid > 0)
783  {
784  memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
785 
786  /*
787  * For each PgBackendStatus field that is a pointer, copy the
788  * pointed-to data, then adjust the local copy of the pointer
789  * field to point at the local copy of the data.
790  *
791  * strcpy is safe even if the string is modified concurrently,
792  * because there's always a \0 at the end of the buffer.
793  */
794  strcpy(localappname, (char *) beentry->st_appname);
795  localentry->backendStatus.st_appname = localappname;
796  strcpy(localclienthostname, (char *) beentry->st_clienthostname);
797  localentry->backendStatus.st_clienthostname = localclienthostname;
798  strcpy(localactivity, (char *) beentry->st_activity_raw);
799  localentry->backendStatus.st_activity_raw = localactivity;
800 #ifdef USE_SSL
801  if (beentry->st_ssl)
802  {
803  memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
804  localentry->backendStatus.st_sslstatus = localsslstatus;
805  }
806 #endif
807 #ifdef ENABLE_GSS
808  if (beentry->st_gss)
809  {
810  memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
811  localentry->backendStatus.st_gssstatus = localgssstatus;
812  }
813 #endif
814  }
815 
816  pgstat_end_read_activity(beentry, after_changecount);
817 
818  if (pgstat_read_activity_complete(before_changecount,
819  after_changecount))
820  break;
821 
822  /* Make sure we can break out of loop if stuck... */
824  }
825 
826  /* Only valid entries get included into the local array */
827  if (localentry->backendStatus.st_procpid > 0)
828  {
829  /*
830  * The BackendStatusArray index is exactly the ProcNumber of the
831  * source backend. Note that this means localBackendStatusTable
832  * is in order by proc_number. pgstat_get_beentry_by_proc_number()
833  * depends on that.
834  */
835  localentry->proc_number = procNumber;
836  ProcNumberGetTransactionIds(procNumber,
837  &localentry->backend_xid,
838  &localentry->backend_xmin,
839  &localentry->backend_subxact_count,
840  &localentry->backend_subxact_overflowed);
841 
842  localentry++;
843  localappname += NAMEDATALEN;
844  localclienthostname += NAMEDATALEN;
845  localactivity += pgstat_track_activity_query_size;
846 #ifdef USE_SSL
847  localsslstatus++;
848 #endif
849 #ifdef ENABLE_GSS
850  localgssstatus++;
851 #endif
853  }
854 
855  beentry++;
856  }
857 
858  /* Set the pointer only after completion of a valid table */
859  localBackendStatusTable = localtable;
860 }
static void pgstat_setup_backend_status_context(void)
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition: mcxt.c:1640
void ProcNumberGetTransactionIds(ProcNumber procNumber, TransactionId *xid, TransactionId *xmin, int *nsubxid, bool *overflowed)
Definition: procarray.c:3164
int ProcNumber
Definition: procnumber.h:24
TransactionId backend_xid
TransactionId backend_xmin

References LocalPgBackendStatus::backend_subxact_count, LocalPgBackendStatus::backend_subxact_overflowed, LocalPgBackendStatus::backend_xid, LocalPgBackendStatus::backend_xmin, LocalPgBackendStatus::backendStatus, BackendStatusArray, backendStatusSnapContext, CHECK_FOR_INTERRUPTS, localBackendStatusTable, 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, LocalPgBackendStatus::proc_number, ProcNumberGetTransactionIds(), 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_numbackends(), pgstat_get_local_beentry_by_index(), and pgstat_get_local_beentry_by_proc_number().

◆ pgstat_report_activity()

void pgstat_report_activity ( BackendState  state,
const char *  cmd_str 
)

Definition at line 501 of file backend_status.c.

502 {
503  volatile PgBackendStatus *beentry = MyBEEntry;
504  TimestampTz start_timestamp;
505  TimestampTz current_timestamp;
506  int len = 0;
507 
508  TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
509 
510  if (!beentry)
511  return;
512 
514  {
515  if (beentry->st_state != STATE_DISABLED)
516  {
517  volatile PGPROC *proc = MyProc;
518 
519  /*
520  * track_activities is disabled, but we last reported a
521  * non-disabled state. As our final update, change the state and
522  * clear fields we will not be updating anymore.
523  */
525  beentry->st_state = STATE_DISABLED;
526  beentry->st_state_start_timestamp = 0;
527  beentry->st_activity_raw[0] = '\0';
528  beentry->st_activity_start_timestamp = 0;
529  /* st_xact_start_timestamp and wait_event_info are also disabled */
530  beentry->st_xact_start_timestamp = 0;
531  beentry->st_query_id = UINT64CONST(0);
532  proc->wait_event_info = 0;
533  PGSTAT_END_WRITE_ACTIVITY(beentry);
534  }
535  return;
536  }
537 
538  /*
539  * To minimize the time spent modifying the entry, and avoid risk of
540  * errors inside the critical section, fetch all the needed data first.
541  */
542  start_timestamp = GetCurrentStatementStartTimestamp();
543  if (cmd_str != NULL)
544  {
545  /*
546  * Compute length of to-be-stored string unaware of multi-byte
547  * characters. For speed reasons that'll get corrected on read, rather
548  * than computed every write.
549  */
550  len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
551  }
552  current_timestamp = GetCurrentTimestamp();
553 
554  /*
555  * If the state has changed from "active" or "idle in transaction",
556  * calculate the duration.
557  */
558  if ((beentry->st_state == STATE_RUNNING ||
559  beentry->st_state == STATE_FASTPATH ||
560  beentry->st_state == STATE_IDLEINTRANSACTION ||
562  state != beentry->st_state)
563  {
564  long secs;
565  int usecs;
566 
568  current_timestamp,
569  &secs, &usecs);
570 
571  if (beentry->st_state == STATE_RUNNING ||
572  beentry->st_state == STATE_FASTPATH)
573  pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
574  else
575  pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
576  }
577 
578  /*
579  * Now update the status entry
580  */
582 
583  beentry->st_state = state;
584  beentry->st_state_start_timestamp = current_timestamp;
585 
586  /*
587  * If a new query is started, we reset the query identifier as it'll only
588  * be known after parse analysis, to avoid reporting last query's
589  * identifier.
590  */
591  if (state == STATE_RUNNING)
592  beentry->st_query_id = UINT64CONST(0);
593 
594  if (cmd_str != NULL)
595  {
596  memcpy((char *) beentry->st_activity_raw, cmd_str, len);
597  beentry->st_activity_raw[len] = '\0';
598  beentry->st_activity_start_timestamp = start_timestamp;
599  }
600 
601  PGSTAT_END_WRITE_ACTIVITY(beentry);
602 }
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1720
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1644
bool pgstat_track_activities
@ STATE_IDLEINTRANSACTION_ABORTED
@ STATE_IDLEINTRANSACTION
@ STATE_DISABLED
@ STATE_FASTPATH
@ STATE_RUNNING
int64 TimestampTz
Definition: timestamp.h:39
const void size_t len
#define pgstat_count_conn_txn_idle_time(n)
Definition: pgstat.h:593
#define pgstat_count_conn_active_time(n)
Definition: pgstat.h:591
int64 PgStat_Counter
Definition: pgstat.h:120
PGPROC * MyProc
Definition: proc.c:66
Definition: proc.h:162
uint32 wait_event_info
Definition: proc.h:279
Definition: regguts.h:323
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:878

References GetCurrentStatementStartTimestamp(), GetCurrentTimestamp(), len, 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 _brin_parallel_build_main(), _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_prepare(), 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(), pa_stream_abort(), parallel_vacuum_main(), ParallelQueryMain(), PostgresMain(), and worker_spi_main().

◆ pgstat_report_appname()

void pgstat_report_appname ( const char *  appname)

Definition at line 651 of file backend_status.c.

652 {
653  volatile PgBackendStatus *beentry = MyBEEntry;
654  int len;
655 
656  if (!beentry)
657  return;
658 
659  /* This should be unnecessary if GUC did its job, but be safe */
660  len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
661 
662  /*
663  * Update my status entry, following the protocol of bumping
664  * st_changecount before and after. We use a volatile pointer here to
665  * ensure the compiler doesn't try to get cute.
666  */
668 
669  memcpy((char *) beentry->st_appname, appname, len);
670  beentry->st_appname[len] = '\0';
671 
672  PGSTAT_END_WRITE_ACTIVITY(beentry);
673 }

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

Referenced by assign_application_name(), and pgstat_bestart().

◆ pgstat_report_query_id()

void pgstat_report_query_id ( uint64  query_id,
bool  force 
)

Definition at line 611 of file backend_status.c.

612 {
613  volatile PgBackendStatus *beentry = MyBEEntry;
614 
615  /*
616  * if track_activities is disabled, st_query_id should already have been
617  * reset
618  */
619  if (!beentry || !pgstat_track_activities)
620  return;
621 
622  /*
623  * We only report the top-level query identifiers. The stored query_id is
624  * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
625  * with an explicit call to this function using the force flag. If the
626  * saved query identifier is not zero it means that it's not a top-level
627  * command, so ignore the one provided unless it's an explicit call to
628  * reset the identifier.
629  */
630  if (beentry->st_query_id != 0 && !force)
631  return;
632 
633  /*
634  * Update my status entry, following the protocol of bumping
635  * st_changecount before and after. We use a volatile pointer here to
636  * ensure the compiler doesn't try to get cute.
637  */
639  beentry->st_query_id = query_id;
640  PGSTAT_END_WRITE_ACTIVITY(beentry);
641 }

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

Referenced by _brin_parallel_build_main(), _bt_parallel_build_main(), exec_bind_message(), exec_execute_message(), exec_simple_query(), ExecutorStart(), parallel_vacuum_main(), parse_analyze_fixedparams(), parse_analyze_varparams(), and parse_analyze_withcb().

◆ pgstat_report_xact_timestamp()

void pgstat_report_xact_timestamp ( TimestampTz  tstamp)

Definition at line 680 of file backend_status.c.

681 {
682  volatile PgBackendStatus *beentry = MyBEEntry;
683 
684  if (!pgstat_track_activities || !beentry)
685  return;
686 
687  /*
688  * Update my status entry, following the protocol of bumping
689  * st_changecount before and after. We use a volatile pointer here to
690  * ensure the compiler doesn't try to get cute.
691  */
693 
694  beentry->st_xact_start_timestamp = tstamp;
695 
696  PGSTAT_END_WRITE_ACTIVITY(beentry);
697 }

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().

◆ pgstat_setup_backend_status_context()

static void pgstat_setup_backend_status_context ( void  )
static

Definition at line 480 of file backend_status.c.

481 {
484  "Backend Status Snapshot",
486 }
MemoryContext TopMemoryContext
Definition: mcxt.c:149
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, backendStatusSnapContext, and TopMemoryContext.

Referenced by pgstat_read_current_status().

Variable Documentation

◆ BackendActivityBuffer

char* BackendActivityBuffer = NULL
static

Definition at line 53 of file backend_status.c.

Referenced by BackendStatusShmemInit(), and pgstat_get_crashed_backend_activity().

◆ BackendActivityBufferSize

Size BackendActivityBufferSize = 0
static

Definition at line 54 of file backend_status.c.

Referenced by BackendStatusShmemInit(), and pgstat_get_crashed_backend_activity().

◆ BackendAppnameBuffer

char* BackendAppnameBuffer = NULL
static

Definition at line 51 of file backend_status.c.

Referenced by BackendStatusShmemInit().

◆ BackendClientHostnameBuffer

char* BackendClientHostnameBuffer = NULL
static

Definition at line 52 of file backend_status.c.

Referenced by BackendStatusShmemInit().

◆ BackendStatusArray

◆ backendStatusSnapContext

◆ localBackendStatusTable

◆ localNumBackends

◆ MyBEEntry

◆ pgstat_track_activities

◆ pgstat_track_activity_query_size