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 "port/atomics.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/sinvaladt.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 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)
 
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 37 of file backend_status.c.

Function Documentation

◆ BackendStatusShmemSize()

Size BackendStatusShmemSize ( void  )

Definition at line 83 of file backend_status.c.

84 {
85  Size size;
86 
87  /* BackendStatusArray: */
89  /* BackendAppnameBuffer: */
90  size = add_size(size,
92  /* BackendClientHostnameBuffer: */
93  size = add_size(size,
95  /* BackendActivityBuffer: */
96  size = add_size(size,
98 #ifdef USE_SSL
99  /* BackendSslStatusBuffer: */
100  size = add_size(size,
102 #endif
103 #ifdef ENABLE_GSS
104  /* BackendGssStatusBuffer: */
105  size = add_size(size,
107 #endif
108  return size;
109 }
#define NumBackendStatSlots
int pgstat_track_activity_query_size
size_t Size
Definition: c.h:592
#define NAMEDATALEN
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
static pg_noinline void Size size
Definition: slab.c:607

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 1049 of file backend_status.c.

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

References a, b, and LocalPgBackendStatus::proc_number.

Referenced by pgstat_get_local_beentry_by_proc_number().

◆ CreateSharedBackendStatus()

void CreateSharedBackendStatus ( void  )

Definition at line 116 of file backend_status.c.

117 {
118  Size size;
119  bool found;
120  int i;
121  char *buffer;
122 
123  /* Create or attach to the shared array */
126  ShmemInitStruct("Backend Status Array", size, &found);
127 
128  if (!found)
129  {
130  /*
131  * We're the first - initialize.
132  */
134  }
135 
136  /* Create or attach to the shared appname buffer */
138  BackendAppnameBuffer = (char *)
139  ShmemInitStruct("Backend Application Name Buffer", size, &found);
140 
141  if (!found)
142  {
144 
145  /* Initialize st_appname pointers. */
146  buffer = BackendAppnameBuffer;
147  for (i = 0; i < NumBackendStatSlots; i++)
148  {
149  BackendStatusArray[i].st_appname = buffer;
150  buffer += NAMEDATALEN;
151  }
152  }
153 
154  /* Create or attach to the shared client hostname buffer */
156  BackendClientHostnameBuffer = (char *)
157  ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
158 
159  if (!found)
160  {
162 
163  /* Initialize st_clienthostname pointers. */
165  for (i = 0; i < NumBackendStatSlots; i++)
166  {
168  buffer += NAMEDATALEN;
169  }
170  }
171 
172  /* Create or attach to the shared activity buffer */
175  BackendActivityBuffer = (char *)
176  ShmemInitStruct("Backend Activity Buffer",
178  &found);
179 
180  if (!found)
181  {
183 
184  /* Initialize st_activity pointers. */
185  buffer = BackendActivityBuffer;
186  for (i = 0; i < NumBackendStatSlots; i++)
187  {
190  }
191  }
192 
193 #ifdef USE_SSL
194  /* Create or attach to the shared SSL status buffer */
196  BackendSslStatusBuffer = (PgBackendSSLStatus *)
197  ShmemInitStruct("Backend SSL Status Buffer", size, &found);
198 
199  if (!found)
200  {
201  PgBackendSSLStatus *ptr;
202 
203  MemSet(BackendSslStatusBuffer, 0, size);
204 
205  /* Initialize st_sslstatus pointers. */
206  ptr = BackendSslStatusBuffer;
207  for (i = 0; i < NumBackendStatSlots; i++)
208  {
210  ptr++;
211  }
212  }
213 #endif
214 
215 #ifdef ENABLE_GSS
216  /* Create or attach to the shared GSSAPI status buffer */
218  BackendGssStatusBuffer = (PgBackendGSSStatus *)
219  ShmemInitStruct("Backend GSS Status Buffer", size, &found);
220 
221  if (!found)
222  {
223  PgBackendGSSStatus *ptr;
224 
225  MemSet(BackendGssStatusBuffer, 0, size);
226 
227  /* Initialize st_gssstatus pointers. */
228  ptr = BackendGssStatusBuffer;
229  for (i = 0; i < NumBackendStatSlots; i++)
230  {
232  ptr++;
233  }
234  }
235 #endif
236 }
static char * BackendClientHostnameBuffer
static char * BackendActivityBuffer
static char * BackendAppnameBuffer
static PgBackendStatus * BackendStatusArray
static Size BackendActivityBufferSize
#define MemSet(start, val, len)
Definition: c.h:1007
int i
Definition: isn.c:73
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
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().

◆ pgstat_beinit()

void pgstat_beinit ( void  )

Definition at line 247 of file backend_status.c.

248 {
249  /* Initialize MyBEEntry */
253 
254  /* Set up a process-exit hook to clean up */
256 }
PgBackendStatus * MyBEEntry
static void pgstat_beshutdown_hook(int code, Datum arg)
ProcNumber MyProcNumber
Definition: globals.c:87
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
Assert(fmt[strlen(fmt) - 1] !='\n')
#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 440 of file backend_status.c.

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

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

468 {
469  /* Release memory, if any was allocated */
471  {
474  }
475 
476  /* Reset variables */
478  localNumBackends = 0;
479 }
static LocalPgBackendStatus * localBackendStatusTable
static int localNumBackends
static MemoryContext backendStatusSnapContext
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442

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 1164 of file backend_status.c.

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

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 1148 of file backend_status.c.

1149 {
1151 
1152  return localNumBackends;
1153 }
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 885 of file backend_status.c.

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

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

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 1128 of file backend_status.c.

1129 {
1131 
1132  if (idx < 1 || idx > localNumBackends)
1133  return NULL;
1134 
1135  return &localBackendStatusTable[idx - 1];
1136 }
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 1097 of file backend_status.c.

1098 {
1100 
1102 
1103  /*
1104  * Since the localBackendStatusTable is in order by proc_number, we can
1105  * use bsearch() to search it efficiently.
1106  */
1107  key.proc_number = procNumber;
1108  return bsearch(&key, localBackendStatusTable, localNumBackends,
1110 }
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 1027 of file backend_status.c.

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

References MyBEEntry, and PgBackendStatus::st_query_id.

Referenced by ExecSerializePlan(), log_status_format(), write_csvlog(), and write_jsonlog().

◆ pgstat_read_current_status()

static void pgstat_read_current_status ( void  )
static

Definition at line 709 of file backend_status.c.

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

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

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 653 of file backend_status.c.

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

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 613 of file backend_status.c.

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

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_fixedparams(), parse_analyze_varparams(), and parse_analyze_withcb().

◆ pgstat_report_xact_timestamp()

void pgstat_report_xact_timestamp ( TimestampTz  tstamp)

Definition at line 682 of file backend_status.c.

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

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 482 of file backend_status.c.

483 {
486  "Backend Status Snapshot",
488 }
MemoryContext TopMemoryContext
Definition: mcxt.c:137
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, backendStatusSnapContext, and TopMemoryContext.

Referenced by pgstat_read_current_status().

Variable Documentation

◆ BackendActivityBuffer

char* BackendActivityBuffer = NULL
static

◆ BackendActivityBufferSize

Size BackendActivityBufferSize = 0
static

◆ BackendAppnameBuffer

char* BackendAppnameBuffer = NULL
static

Definition at line 53 of file backend_status.c.

Referenced by CreateSharedBackendStatus().

◆ BackendClientHostnameBuffer

char* BackendClientHostnameBuffer = NULL
static

Definition at line 54 of file backend_status.c.

Referenced by CreateSharedBackendStatus().

◆ BackendStatusArray

◆ backendStatusSnapContext

◆ localBackendStatusTable

◆ localNumBackends

◆ MyBEEntry

◆ pgstat_track_activities

◆ pgstat_track_activity_query_size