PostgreSQL Source Code  git master
backend_status.c
Go to the documentation of this file.
1 /* ----------
2  * backend_status.c
3  * Backend status reporting infrastructure.
4  *
5  * Copyright (c) 2001-2024, PostgreSQL Global Development Group
6  *
7  *
8  * IDENTIFICATION
9  * src/backend/utils/activity/backend_status.c
10  * ----------
11  */
12 #include "postgres.h"
13 
14 #include "access/xact.h"
15 #include "libpq/libpq.h"
16 #include "miscadmin.h"
17 #include "pg_trace.h"
18 #include "pgstat.h"
19 #include "port/atomics.h" /* for memory barriers */
20 #include "storage/ipc.h"
21 #include "storage/proc.h" /* for MyProc */
22 #include "storage/sinvaladt.h"
23 #include "utils/ascii.h"
24 #include "utils/backend_status.h"
25 #include "utils/guc.h" /* for application_name */
26 #include "utils/memutils.h"
27 
28 
29 /* ----------
30  * Total number of backends including auxiliary
31  *
32  * We reserve a slot for each possible BackendId, plus one for each
33  * possible auxiliary process type. (This scheme assumes there is not
34  * more than one of any auxiliary process type at a time.) MaxBackends
35  * includes autovacuum workers and background workers as well.
36  * ----------
37  */
38 #define NumBackendStatSlots (MaxBackends + NUM_AUXPROCTYPES)
39 
40 
41 /* ----------
42  * GUC parameters
43  * ----------
44  */
47 
48 
49 /* exposed so that backend_progress.c can access it */
51 
52 
54 static char *BackendAppnameBuffer = NULL;
55 static char *BackendClientHostnameBuffer = NULL;
56 static char *BackendActivityBuffer = NULL;
58 #ifdef USE_SSL
59 static PgBackendSSLStatus *BackendSslStatusBuffer = NULL;
60 #endif
61 #ifdef ENABLE_GSS
62 static PgBackendGSSStatus *BackendGssStatusBuffer = NULL;
63 #endif
64 
65 
66 /* Status for backends including auxiliary */
68 
69 /* Total number of backends including auxiliary */
70 static int localNumBackends = 0;
71 
73 
74 
75 static void pgstat_beshutdown_hook(int code, Datum arg);
76 static void pgstat_read_current_status(void);
77 static void pgstat_setup_backend_status_context(void);
78 
79 
80 /*
81  * Report shared-memory space needed by CreateSharedBackendStatus.
82  */
83 Size
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 }
111 
112 /*
113  * Initialize the shared status array and several string buffers
114  * during postmaster startup.
115  */
116 void
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 }
238 
239 /*
240  * Initialize pgstats backend activity state, and set up our on-proc-exit
241  * hook. Called from InitPostgres and AuxiliaryProcessMain. For auxiliary
242  * process, MyBackendId is invalid. Otherwise, MyBackendId must be set, but we
243  * must not have started any transaction yet (since the exit hook must run
244  * after the last transaction exit).
245  *
246  * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
247  */
248 void
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 0 to MaxBackends (exclusive), so we use
267  * MaxBackends + AuxProcType as the index of the slot for an auxiliary
268  * process.
269  */
271  }
272 
273  /* Set up a process-exit hook to clean up */
275 }
276 
277 
278 /* ----------
279  * pgstat_bestart() -
280  *
281  * Initialize this backend's entry in the PgBackendStatus array.
282  * Called from InitPostgres.
283  *
284  * Apart from auxiliary processes, MyBackendId, MyDatabaseId,
285  * session userid, and application_name must be set for a
286  * backend (hence, this cannot be combined with pgstat_beinit).
287  * Note also that we must be inside a transaction if this isn't an aux
288  * process, as we may need to do encoding conversion on some strings.
289  * ----------
290  */
291 void
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);
388  if (princ)
389  strlcpy(lgssstatus.gss_princ, princ, NAMEDATALEN);
390  }
391  else
392  {
393  lbeentry.st_gss = false;
394  }
395 #else
396  lbeentry.st_gss = false;
397 #endif
398 
399  lbeentry.st_state = STATE_UNDEFINED;
402  lbeentry.st_query_id = UINT64CONST(0);
403 
404  /*
405  * we don't zero st_progress_param here to save cycles; nobody should
406  * examine it until st_progress_command has been set to something other
407  * than PROGRESS_COMMAND_INVALID
408  */
409 
410  /*
411  * We're ready to enter the critical section that fills the shared-memory
412  * status entry. We follow the protocol of bumping st_changecount before
413  * and after; and make sure it's even afterwards. We use a volatile
414  * pointer here to ensure the compiler doesn't try to get cute.
415  */
416  PGSTAT_BEGIN_WRITE_ACTIVITY(vbeentry);
417 
418  /* make sure we'll memcpy the same st_changecount back */
419  lbeentry.st_changecount = vbeentry->st_changecount;
420 
421  memcpy(unvolatize(PgBackendStatus *, vbeentry),
422  &lbeentry,
423  sizeof(PgBackendStatus));
424 
425  /*
426  * We can write the out-of-line strings and structs using the pointers
427  * that are in lbeentry; this saves some de-volatilizing messiness.
428  */
429  lbeentry.st_appname[0] = '\0';
432  NAMEDATALEN);
433  else
434  lbeentry.st_clienthostname[0] = '\0';
435  lbeentry.st_activity_raw[0] = '\0';
436  /* Also make sure the last byte in each string area is always 0 */
437  lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
438  lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
440 
441 #ifdef USE_SSL
442  memcpy(lbeentry.st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
443 #endif
444 #ifdef ENABLE_GSS
445  memcpy(lbeentry.st_gssstatus, &lgssstatus, sizeof(PgBackendGSSStatus));
446 #endif
447 
448  PGSTAT_END_WRITE_ACTIVITY(vbeentry);
449 
450  /* Update app name to current GUC setting */
451  if (application_name)
453 }
454 
455 /*
456  * Clear out our entry in the PgBackendStatus array.
457  */
458 static void
460 {
461  volatile PgBackendStatus *beentry = MyBEEntry;
462 
463  /*
464  * Clear my status entry, following the protocol of bumping st_changecount
465  * before and after. We use a volatile pointer here to ensure the
466  * compiler doesn't try to get cute.
467  */
469 
470  beentry->st_procpid = 0; /* mark invalid */
471 
472  PGSTAT_END_WRITE_ACTIVITY(beentry);
473 
474  /* so that functions can check if backend_status.c is up via MyBEEntry */
475  MyBEEntry = NULL;
476 }
477 
478 /*
479  * Discard any data collected in the current transaction. Any subsequent
480  * request will cause new snapshots to be read.
481  *
482  * This is also invoked during transaction commit or abort to discard the
483  * no-longer-wanted snapshot.
484  */
485 void
487 {
488  /* Release memory, if any was allocated */
490  {
493  }
494 
495  /* Reset variables */
497  localNumBackends = 0;
498 }
499 
500 static void
502 {
505  "Backend Status Snapshot",
507 }
508 
509 
510 /* ----------
511  * pgstat_report_activity() -
512  *
513  * Called from tcop/postgres.c to report what the backend is actually doing
514  * (but note cmd_str can be NULL for certain cases).
515  *
516  * All updates of the status entry follow the protocol of bumping
517  * st_changecount before and after. We use a volatile pointer here to
518  * ensure the compiler doesn't try to get cute.
519  * ----------
520  */
521 void
523 {
524  volatile PgBackendStatus *beentry = MyBEEntry;
525  TimestampTz start_timestamp;
526  TimestampTz current_timestamp;
527  int len = 0;
528 
529  TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
530 
531  if (!beentry)
532  return;
533 
535  {
536  if (beentry->st_state != STATE_DISABLED)
537  {
538  volatile PGPROC *proc = MyProc;
539 
540  /*
541  * track_activities is disabled, but we last reported a
542  * non-disabled state. As our final update, change the state and
543  * clear fields we will not be updating anymore.
544  */
546  beentry->st_state = STATE_DISABLED;
547  beentry->st_state_start_timestamp = 0;
548  beentry->st_activity_raw[0] = '\0';
549  beentry->st_activity_start_timestamp = 0;
550  /* st_xact_start_timestamp and wait_event_info are also disabled */
551  beentry->st_xact_start_timestamp = 0;
552  beentry->st_query_id = UINT64CONST(0);
553  proc->wait_event_info = 0;
554  PGSTAT_END_WRITE_ACTIVITY(beentry);
555  }
556  return;
557  }
558 
559  /*
560  * To minimize the time spent modifying the entry, and avoid risk of
561  * errors inside the critical section, fetch all the needed data first.
562  */
563  start_timestamp = GetCurrentStatementStartTimestamp();
564  if (cmd_str != NULL)
565  {
566  /*
567  * Compute length of to-be-stored string unaware of multi-byte
568  * characters. For speed reasons that'll get corrected on read, rather
569  * than computed every write.
570  */
571  len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
572  }
573  current_timestamp = GetCurrentTimestamp();
574 
575  /*
576  * If the state has changed from "active" or "idle in transaction",
577  * calculate the duration.
578  */
579  if ((beentry->st_state == STATE_RUNNING ||
580  beentry->st_state == STATE_FASTPATH ||
581  beentry->st_state == STATE_IDLEINTRANSACTION ||
583  state != beentry->st_state)
584  {
585  long secs;
586  int usecs;
587 
589  current_timestamp,
590  &secs, &usecs);
591 
592  if (beentry->st_state == STATE_RUNNING ||
593  beentry->st_state == STATE_FASTPATH)
594  pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
595  else
596  pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
597  }
598 
599  /*
600  * Now update the status entry
601  */
603 
604  beentry->st_state = state;
605  beentry->st_state_start_timestamp = current_timestamp;
606 
607  /*
608  * If a new query is started, we reset the query identifier as it'll only
609  * be known after parse analysis, to avoid reporting last query's
610  * identifier.
611  */
612  if (state == STATE_RUNNING)
613  beentry->st_query_id = UINT64CONST(0);
614 
615  if (cmd_str != NULL)
616  {
617  memcpy((char *) beentry->st_activity_raw, cmd_str, len);
618  beentry->st_activity_raw[len] = '\0';
619  beentry->st_activity_start_timestamp = start_timestamp;
620  }
621 
622  PGSTAT_END_WRITE_ACTIVITY(beentry);
623 }
624 
625 /* --------
626  * pgstat_report_query_id() -
627  *
628  * Called to update top-level query identifier.
629  * --------
630  */
631 void
632 pgstat_report_query_id(uint64 query_id, bool force)
633 {
634  volatile PgBackendStatus *beentry = MyBEEntry;
635 
636  /*
637  * if track_activities is disabled, st_query_id should already have been
638  * reset
639  */
640  if (!beentry || !pgstat_track_activities)
641  return;
642 
643  /*
644  * We only report the top-level query identifiers. The stored query_id is
645  * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
646  * with an explicit call to this function using the force flag. If the
647  * saved query identifier is not zero it means that it's not a top-level
648  * command, so ignore the one provided unless it's an explicit call to
649  * reset the identifier.
650  */
651  if (beentry->st_query_id != 0 && !force)
652  return;
653 
654  /*
655  * Update my status entry, following the protocol of bumping
656  * st_changecount before and after. We use a volatile pointer here to
657  * ensure the compiler doesn't try to get cute.
658  */
660  beentry->st_query_id = query_id;
661  PGSTAT_END_WRITE_ACTIVITY(beentry);
662 }
663 
664 
665 /* ----------
666  * pgstat_report_appname() -
667  *
668  * Called to update our application name.
669  * ----------
670  */
671 void
672 pgstat_report_appname(const char *appname)
673 {
674  volatile PgBackendStatus *beentry = MyBEEntry;
675  int len;
676 
677  if (!beentry)
678  return;
679 
680  /* This should be unnecessary if GUC did its job, but be safe */
681  len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
682 
683  /*
684  * Update my status entry, following the protocol of bumping
685  * st_changecount before and after. We use a volatile pointer here to
686  * ensure the compiler doesn't try to get cute.
687  */
689 
690  memcpy((char *) beentry->st_appname, appname, len);
691  beentry->st_appname[len] = '\0';
692 
693  PGSTAT_END_WRITE_ACTIVITY(beentry);
694 }
695 
696 /*
697  * Report current transaction start timestamp as the specified value.
698  * Zero means there is no active transaction.
699  */
700 void
702 {
703  volatile PgBackendStatus *beentry = MyBEEntry;
704 
705  if (!pgstat_track_activities || !beentry)
706  return;
707 
708  /*
709  * Update my status entry, following the protocol of bumping
710  * st_changecount before and after. We use a volatile pointer here to
711  * ensure the compiler doesn't try to get cute.
712  */
714 
715  beentry->st_xact_start_timestamp = tstamp;
716 
717  PGSTAT_END_WRITE_ACTIVITY(beentry);
718 }
719 
720 /* ----------
721  * pgstat_read_current_status() -
722  *
723  * Copy the current contents of the PgBackendStatus array to local memory,
724  * if not already done in this transaction.
725  * ----------
726  */
727 static void
729 {
730  volatile PgBackendStatus *beentry;
731  LocalPgBackendStatus *localtable;
732  LocalPgBackendStatus *localentry;
733  char *localappname,
734  *localclienthostname,
735  *localactivity;
736 #ifdef USE_SSL
737  PgBackendSSLStatus *localsslstatus;
738 #endif
739 #ifdef ENABLE_GSS
740  PgBackendGSSStatus *localgssstatus;
741 #endif
742  int i;
743 
745  return; /* already done */
746 
748 
749  /*
750  * Allocate storage for local copy of state data. We can presume that
751  * none of these requests overflow size_t, because we already calculated
752  * the same values using mul_size during shmem setup. However, with
753  * probably-silly values of pgstat_track_activity_query_size and
754  * max_connections, the localactivity buffer could exceed 1GB, so use
755  * "huge" allocation for that one.
756  */
757  localtable = (LocalPgBackendStatus *)
760  localappname = (char *)
763  localclienthostname = (char *)
766  localactivity = (char *)
770 #ifdef USE_SSL
771  localsslstatus = (PgBackendSSLStatus *)
774 #endif
775 #ifdef ENABLE_GSS
776  localgssstatus = (PgBackendGSSStatus *)
779 #endif
780 
781  localNumBackends = 0;
782 
783  beentry = BackendStatusArray;
784  localentry = localtable;
785  for (i = 1; i <= NumBackendStatSlots; i++)
786  {
787  /*
788  * Follow the protocol of retrying if st_changecount changes while we
789  * copy the entry, or if it's odd. (The check for odd is needed to
790  * cover the case where we are able to completely copy the entry while
791  * the source backend is between increment steps.) We use a volatile
792  * pointer here to ensure the compiler doesn't try to get cute.
793  */
794  for (;;)
795  {
796  int before_changecount;
797  int after_changecount;
798 
799  pgstat_begin_read_activity(beentry, before_changecount);
800 
801  localentry->backendStatus.st_procpid = beentry->st_procpid;
802  /* Skip all the data-copying work if entry is not in use */
803  if (localentry->backendStatus.st_procpid > 0)
804  {
805  memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
806 
807  /*
808  * For each PgBackendStatus field that is a pointer, copy the
809  * pointed-to data, then adjust the local copy of the pointer
810  * field to point at the local copy of the data.
811  *
812  * strcpy is safe even if the string is modified concurrently,
813  * because there's always a \0 at the end of the buffer.
814  */
815  strcpy(localappname, (char *) beentry->st_appname);
816  localentry->backendStatus.st_appname = localappname;
817  strcpy(localclienthostname, (char *) beentry->st_clienthostname);
818  localentry->backendStatus.st_clienthostname = localclienthostname;
819  strcpy(localactivity, (char *) beentry->st_activity_raw);
820  localentry->backendStatus.st_activity_raw = localactivity;
821 #ifdef USE_SSL
822  if (beentry->st_ssl)
823  {
824  memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
825  localentry->backendStatus.st_sslstatus = localsslstatus;
826  }
827 #endif
828 #ifdef ENABLE_GSS
829  if (beentry->st_gss)
830  {
831  memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
832  localentry->backendStatus.st_gssstatus = localgssstatus;
833  }
834 #endif
835  }
836 
837  pgstat_end_read_activity(beentry, after_changecount);
838 
839  if (pgstat_read_activity_complete(before_changecount,
840  after_changecount))
841  break;
842 
843  /* Make sure we can break out of loop if stuck... */
845  }
846 
847  /* Only valid entries get included into the local array */
848  if (localentry->backendStatus.st_procpid > 0)
849  {
850  /*
851  * The BackendStatusArray index is exactly the BackendId of the
852  * source backend. Note that this means localBackendStatusTable
853  * is in order by backend_id. pgstat_get_beentry_by_backend_id()
854  * depends on that.
855  */
856  localentry->backend_id = i;
858  &localentry->backend_xid,
859  &localentry->backend_xmin,
860  &localentry->backend_subxact_count,
861  &localentry->backend_subxact_overflowed);
862 
863  localentry++;
864  localappname += NAMEDATALEN;
865  localclienthostname += NAMEDATALEN;
866  localactivity += pgstat_track_activity_query_size;
867 #ifdef USE_SSL
868  localsslstatus++;
869 #endif
870 #ifdef ENABLE_GSS
871  localgssstatus++;
872 #endif
874  }
875 
876  beentry++;
877  }
878 
879  /* Set the pointer only after completion of a valid table */
880  localBackendStatusTable = localtable;
881 }
882 
883 
884 /* ----------
885  * pgstat_get_backend_current_activity() -
886  *
887  * Return a string representing the current activity of the backend with
888  * the specified PID. This looks directly at the BackendStatusArray,
889  * and so will provide current information regardless of the age of our
890  * transaction's snapshot of the status array.
891  *
892  * It is the caller's responsibility to invoke this only for backends whose
893  * state is expected to remain stable while the result is in use. The
894  * only current use is in deadlock reporting, where we can expect that
895  * the target backend is blocked on a lock. (There are corner cases
896  * where the target's wait could get aborted while we are looking at it,
897  * but the very worst consequence is to return a pointer to a string
898  * that's been changed, so we won't worry too much.)
899  *
900  * Note: return strings for special cases match pg_stat_get_backend_activity.
901  * ----------
902  */
903 const char *
904 pgstat_get_backend_current_activity(int pid, bool checkUser)
905 {
906  PgBackendStatus *beentry;
907  int i;
908 
909  beentry = BackendStatusArray;
910  for (i = 1; i <= MaxBackends; i++)
911  {
912  /*
913  * Although we expect the target backend's entry to be stable, that
914  * doesn't imply that anyone else's is. To avoid identifying the
915  * wrong backend, while we check for a match to the desired PID we
916  * must follow the protocol of retrying if st_changecount changes
917  * while we examine the entry, or if it's odd. (This might be
918  * unnecessary, since fetching or storing an int is almost certainly
919  * atomic, but let's play it safe.) We use a volatile pointer here to
920  * ensure the compiler doesn't try to get cute.
921  */
922  volatile PgBackendStatus *vbeentry = beentry;
923  bool found;
924 
925  for (;;)
926  {
927  int before_changecount;
928  int after_changecount;
929 
930  pgstat_begin_read_activity(vbeentry, before_changecount);
931 
932  found = (vbeentry->st_procpid == pid);
933 
934  pgstat_end_read_activity(vbeentry, after_changecount);
935 
936  if (pgstat_read_activity_complete(before_changecount,
937  after_changecount))
938  break;
939 
940  /* Make sure we can break out of loop if stuck... */
942  }
943 
944  if (found)
945  {
946  /* Now it is safe to use the non-volatile pointer */
947  if (checkUser && !superuser() && beentry->st_userid != GetUserId())
948  return "<insufficient privilege>";
949  else if (*(beentry->st_activity_raw) == '\0')
950  return "<command string not enabled>";
951  else
952  {
953  /* this'll leak a bit of memory, but that seems acceptable */
954  return pgstat_clip_activity(beentry->st_activity_raw);
955  }
956  }
957 
958  beentry++;
959  }
960 
961  /* If we get here, caller is in error ... */
962  return "<backend information not available>";
963 }
964 
965 /* ----------
966  * pgstat_get_crashed_backend_activity() -
967  *
968  * Return a string representing the current activity of the backend with
969  * the specified PID. Like the function above, but reads shared memory with
970  * the expectation that it may be corrupt. On success, copy the string
971  * into the "buffer" argument and return that pointer. On failure,
972  * return NULL.
973  *
974  * This function is only intended to be used by the postmaster to report the
975  * query that crashed a backend. In particular, no attempt is made to
976  * follow the correct concurrency protocol when accessing the
977  * BackendStatusArray. But that's OK, in the worst case we'll return a
978  * corrupted message. We also must take care not to trip on ereport(ERROR).
979  * ----------
980  */
981 const char *
982 pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
983 {
984  volatile PgBackendStatus *beentry;
985  int i;
986 
987  beentry = BackendStatusArray;
988 
989  /*
990  * We probably shouldn't get here before shared memory has been set up,
991  * but be safe.
992  */
993  if (beentry == NULL || BackendActivityBuffer == NULL)
994  return NULL;
995 
996  for (i = 1; i <= MaxBackends; i++)
997  {
998  if (beentry->st_procpid == pid)
999  {
1000  /* Read pointer just once, so it can't change after validation */
1001  const char *activity = beentry->st_activity_raw;
1002  const char *activity_last;
1003 
1004  /*
1005  * We mustn't access activity string before we verify that it
1006  * falls within the BackendActivityBuffer. To make sure that the
1007  * entire string including its ending is contained within the
1008  * buffer, subtract one activity length from the buffer size.
1009  */
1012 
1013  if (activity < BackendActivityBuffer ||
1014  activity > activity_last)
1015  return NULL;
1016 
1017  /* If no string available, no point in a report */
1018  if (activity[0] == '\0')
1019  return NULL;
1020 
1021  /*
1022  * Copy only ASCII-safe characters so we don't run into encoding
1023  * problems when reporting the message; and be sure not to run off
1024  * the end of memory. As only ASCII characters are reported, it
1025  * doesn't seem necessary to perform multibyte aware clipping.
1026  */
1027  ascii_safe_strlcpy(buffer, activity,
1029 
1030  return buffer;
1031  }
1032 
1033  beentry++;
1034  }
1035 
1036  /* PID not found */
1037  return NULL;
1038 }
1039 
1040 /* ----------
1041  * pgstat_get_my_query_id() -
1042  *
1043  * Return current backend's query identifier.
1044  */
1045 uint64
1047 {
1048  if (!MyBEEntry)
1049  return 0;
1050 
1051  /*
1052  * There's no need for a lock around pgstat_begin_read_activity /
1053  * pgstat_end_read_activity here as it's only called from
1054  * pg_stat_get_activity which is already protected, or from the same
1055  * backend which means that there won't be concurrent writes.
1056  */
1057  return MyBEEntry->st_query_id;
1058 }
1059 
1060 /* ----------
1061  * cmp_lbestatus
1062  *
1063  * Comparison function for bsearch() on an array of LocalPgBackendStatus.
1064  * The backend_id field is used to compare the arguments.
1065  * ----------
1066  */
1067 static int
1068 cmp_lbestatus(const void *a, const void *b)
1069 {
1070  const LocalPgBackendStatus *lbestatus1 = (const LocalPgBackendStatus *) a;
1071  const LocalPgBackendStatus *lbestatus2 = (const LocalPgBackendStatus *) b;
1072 
1073  return lbestatus1->backend_id - lbestatus2->backend_id;
1074 }
1075 
1076 /* ----------
1077  * pgstat_get_beentry_by_backend_id() -
1078  *
1079  * Support function for the SQL-callable pgstat* functions. Returns
1080  * our local copy of the current-activity entry for one backend,
1081  * or NULL if the given beid doesn't identify any known session.
1082  *
1083  * The beid argument is the BackendId of the desired session
1084  * (note that this is unlike pgstat_get_local_beentry_by_index()).
1085  *
1086  * NB: caller is responsible for a check if the user is permitted to see
1087  * this info (especially the querystring).
1088  * ----------
1089  */
1092 {
1094 
1095  if (ret)
1096  return &ret->backendStatus;
1097 
1098  return NULL;
1099 }
1100 
1101 
1102 /* ----------
1103  * pgstat_get_local_beentry_by_backend_id() -
1104  *
1105  * Like pgstat_get_beentry_by_backend_id() but with locally computed additions
1106  * (like xid and xmin values of the backend)
1107  *
1108  * The beid argument is the BackendId of the desired session
1109  * (note that this is unlike pgstat_get_local_beentry_by_index()).
1110  *
1111  * NB: caller is responsible for checking if the user is permitted to see this
1112  * info (especially the querystring).
1113  * ----------
1114  */
1117 {
1119 
1121 
1122  /*
1123  * Since the localBackendStatusTable is in order by backend_id, we can use
1124  * bsearch() to search it efficiently.
1125  */
1126  key.backend_id = beid;
1127  return bsearch(&key, localBackendStatusTable, localNumBackends,
1129 }
1130 
1131 
1132 /* ----------
1133  * pgstat_get_local_beentry_by_index() -
1134  *
1135  * Like pgstat_get_beentry_by_backend_id() but with locally computed additions
1136  * (like xid and xmin values of the backend)
1137  *
1138  * The idx argument is a 1-based index in the localBackendStatusTable
1139  * (note that this is unlike pgstat_get_beentry_by_backend_id()).
1140  * Returns NULL if the argument is out of range (no current caller does that).
1141  *
1142  * NB: caller is responsible for a check if the user is permitted to see
1143  * this info (especially the querystring).
1144  * ----------
1145  */
1148 {
1150 
1151  if (idx < 1 || idx > localNumBackends)
1152  return NULL;
1153 
1154  return &localBackendStatusTable[idx - 1];
1155 }
1156 
1157 
1158 /* ----------
1159  * pgstat_fetch_stat_numbackends() -
1160  *
1161  * Support function for the SQL-callable pgstat* functions. Returns
1162  * the number of sessions known in the localBackendStatusTable, i.e.
1163  * the maximum 1-based index to pass to pgstat_get_local_beentry_by_index().
1164  * ----------
1165  */
1166 int
1168 {
1170 
1171  return localNumBackends;
1172 }
1173 
1174 /*
1175  * Convert a potentially unsafely truncated activity string (see
1176  * PgBackendStatus.st_activity_raw's documentation) into a correctly truncated
1177  * one.
1178  *
1179  * The returned string is allocated in the caller's memory context and may be
1180  * freed.
1181  */
1182 char *
1183 pgstat_clip_activity(const char *raw_activity)
1184 {
1185  char *activity;
1186  int rawlen;
1187  int cliplen;
1188 
1189  /*
1190  * Some callers, like pgstat_get_backend_current_activity(), do not
1191  * guarantee that the buffer isn't concurrently modified. We try to take
1192  * care that the buffer is always terminated by a NUL byte regardless, but
1193  * let's still be paranoid about the string's length. In those cases the
1194  * underlying buffer is guaranteed to be pgstat_track_activity_query_size
1195  * large.
1196  */
1197  activity = pnstrdup(raw_activity, pgstat_track_activity_query_size - 1);
1198 
1199  /* now double-guaranteed to be NUL terminated */
1200  rawlen = strlen(activity);
1201 
1202  /*
1203  * All supported server-encodings make it possible to determine the length
1204  * of a multi-byte character from its first byte (this is not the case for
1205  * client encodings, see GB18030). As st_activity is always stored using
1206  * server encoding, this allows us to perform multi-byte aware truncation,
1207  * even if the string earlier was truncated in the middle of a multi-byte
1208  * character.
1209  */
1210  cliplen = pg_mbcliplen(activity, rawlen,
1212 
1213  activity[cliplen] = '\0';
1214 
1215  return activity;
1216 }
Datum idx(PG_FUNCTION_ARGS)
Definition: _int_op.c:259
void ascii_safe_strlcpy(char *dest, const char *src, size_t destsiz)
Definition: ascii.c:174
AuxProcType MyAuxProcType
Definition: auxprocess.c:46
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1731
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1655
@ PROGRESS_COMMAND_INVALID
#define NumBackendStatSlots
int pgstat_fetch_stat_numbackends(void)
PgBackendStatus * MyBEEntry
uint64 pgstat_get_my_query_id(void)
void pgstat_clear_backend_activity_snapshot(void)
static LocalPgBackendStatus * localBackendStatusTable
static int localNumBackends
static void pgstat_beshutdown_hook(int code, Datum arg)
const char * pgstat_get_backend_current_activity(int pid, bool checkUser)
static char * BackendClientHostnameBuffer
static int cmp_lbestatus(const void *a, const void *b)
bool pgstat_track_activities
static MemoryContext backendStatusSnapContext
LocalPgBackendStatus * pgstat_get_local_beentry_by_index(int idx)
void CreateSharedBackendStatus(void)
static char * BackendActivityBuffer
static void pgstat_setup_backend_status_context(void)
void pgstat_report_query_id(uint64 query_id, bool force)
static char * BackendAppnameBuffer
PgBackendStatus * pgstat_get_beentry_by_backend_id(BackendId beid)
void pgstat_report_activity(BackendState state, const char *cmd_str)
void pgstat_report_xact_timestamp(TimestampTz tstamp)
const char * pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
static PgBackendStatus * BackendStatusArray
void pgstat_beinit(void)
Size BackendStatusShmemSize(void)
void pgstat_report_appname(const char *appname)
static Size BackendActivityBufferSize
LocalPgBackendStatus * pgstat_get_local_beentry_by_backend_id(BackendId beid)
static void pgstat_read_current_status(void)
int pgstat_track_activity_query_size
void pgstat_bestart(void)
char * pgstat_clip_activity(const char *raw_activity)
BackendState
@ STATE_UNDEFINED
@ STATE_IDLEINTRANSACTION_ABORTED
@ STATE_IDLEINTRANSACTION
@ STATE_DISABLED
@ STATE_FASTPATH
@ STATE_RUNNING
#define pgstat_read_activity_complete(before_changecount, after_changecount)
#define PGSTAT_END_WRITE_ACTIVITY(beentry)
#define PGSTAT_BEGIN_WRITE_ACTIVITY(beentry)
#define pgstat_end_read_activity(beentry, after_changecount)
#define pgstat_begin_read_activity(beentry, before_changecount)
int BackendId
Definition: backendid.h:21
#define InvalidBackendId
Definition: backendid.h:23
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 Min(x, y)
Definition: c.h:993
#define unvolatize(underlying_type, expr)
Definition: c.h:1236
#define MemSet(start, val, len)
Definition: c.h:1009
size_t Size
Definition: c.h:594
int64 TimestampTz
Definition: timestamp.h:39
int MyProcPid
Definition: globals.c:45
BackendId MyBackendId
Definition: globals.c:86
int MaxBackends
Definition: globals.c:143
TimestampTz MyStartTimestamp
Definition: globals.c:47
struct Port * MyProcPort
Definition: globals.c:48
Oid MyDatabaseId
Definition: globals.c:90
char * application_name
Definition: guc_tables.c:543
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition: mbutils.c:1084
static int cliplen(const char *str, int len, int limit)
Definition: mbutils.c:1151
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1630
MemoryContext TopMemoryContext
Definition: mcxt.c:141
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1034
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition: mcxt.c:1561
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
#define AllocSetContextCreate
Definition: memutils.h:128
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:162
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
@ B_WAL_SENDER
Definition: miscadmin.h:340
@ B_BG_WORKER
Definition: miscadmin.h:332
@ B_BACKEND
Definition: miscadmin.h:331
@ NotAnAuxProcess
Definition: miscadmin.h:441
Oid GetUserId(void)
Definition: miscinit.c:515
Oid GetSessionUserId(void)
Definition: miscinit.c:549
BackendType MyBackendType
Definition: miscinit.c:64
void * arg
#define NAMEDATALEN
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
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
uintptr_t Datum
Definition: postgres.h:64
#define InvalidOid
Definition: postgres_ext.h:36
Size add_size(Size s1, Size s2)
Definition: shmem.c:494
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:388
Size mul_size(Size s1, Size s2)
Definition: shmem.c:511
void BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmin, int *nsubxid, bool *overflowed)
Definition: sinvaladt.c:412
PGPROC * MyProc
Definition: proc.c:68
TransactionId backend_xid
PgBackendStatus backendStatus
TransactionId backend_xmin
Definition: proc.h:162
uint32 wait_event_info
Definition: proc.h:265
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
PgBackendGSSStatus * st_gssstatus
BackendState st_state
TimestampTz st_activity_start_timestamp
ProgressCommandType st_progress_command
SockAddr st_clientaddr
PgBackendSSLStatus * st_sslstatus
TimestampTz st_xact_start_timestamp
char * st_clienthostname
Oid st_progress_command_target
bool ssl_in_use
Definition: libpq-be.h:217
char * remote_hostname
Definition: libpq-be.h:154
void * gss
Definition: libpq-be.h:211
SockAddr raddr
Definition: libpq-be.h:152
Definition: regguts.h:323
bool superuser(void)
Definition: superuser.c:46
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:864