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-2025, 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-be.h"
16#include "miscadmin.h"
17#include "pg_trace.h"
18#include "pgstat.h"
19#include "storage/ipc.h"
20#include "storage/proc.h" /* for MyProc */
21#include "storage/procarray.h"
22#include "utils/ascii.h"
23#include "utils/guc.h" /* for application_name */
24#include "utils/memutils.h"
25
26
27/* ----------
28 * Total number of backends including auxiliary
29 *
30 * We reserve a slot for each possible PGPROC entry, including aux processes.
31 * (But not including PGPROC entries reserved for prepared xacts; they are not
32 * real processes.)
33 * ----------
34 */
35#define NumBackendStatSlots (MaxBackends + NUM_AUXILIARY_PROCS)
36
37
38/* ----------
39 * GUC parameters
40 * ----------
41 */
44
45
46/* exposed so that backend_progress.c can access it */
48
49
51static char *BackendAppnameBuffer = NULL;
52static char *BackendClientHostnameBuffer = NULL;
53static char *BackendActivityBuffer = NULL;
55#ifdef USE_SSL
56static PgBackendSSLStatus *BackendSslStatusBuffer = NULL;
57#endif
58#ifdef ENABLE_GSS
59static PgBackendGSSStatus *BackendGssStatusBuffer = NULL;
60#endif
61
62
63/* Status for backends including auxiliary */
65
66/* Total number of backends including auxiliary */
67static int localNumBackends = 0;
68
70
71
72static void pgstat_beshutdown_hook(int code, Datum arg);
73static void pgstat_read_current_status(void);
75
76
77/*
78 * Report shared-memory space needed by BackendStatusShmemInit.
79 */
80Size
82{
83 Size size;
84
85 /* BackendStatusArray: */
87 /* BackendAppnameBuffer: */
90 /* BackendClientHostnameBuffer: */
93 /* BackendActivityBuffer: */
96#ifdef USE_SSL
97 /* BackendSslStatusBuffer: */
100#endif
101#ifdef ENABLE_GSS
102 /* BackendGssStatusBuffer: */
105#endif
106 return size;
107}
108
109/*
110 * Initialize the shared status array and several string buffers
111 * during postmaster startup.
112 */
113void
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 {
148 buffer += NAMEDATALEN;
149 }
150 }
151
152 /* Create or attach to the shared client hostname buffer */
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 {
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 {
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}
235
236/*
237 * Initialize pgstats backend activity state, and set up our on-proc-exit
238 * hook. Called from InitPostgres and AuxiliaryProcessMain. MyProcNumber must
239 * be set, but we must not have started any transaction yet (since the exit
240 * hook must run after the last transaction exit).
241 *
242 * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
243 */
244void
246{
247 /* Initialize MyBEEntry */
251
252 /* Set up a process-exit hook to clean up */
254}
255
256
257/* ----------
258 * pgstat_bestart() -
259 *
260 * Initialize this backend's entry in the PgBackendStatus array.
261 * Called from InitPostgres.
262 *
263 * Apart from auxiliary processes, MyDatabaseId, session userid, and
264 * application_name must already be set (hence, this cannot be combined
265 * with pgstat_beinit). Note also that we must be inside a transaction
266 * if this isn't an aux process, as we may need to do encoding conversion
267 * on some strings.
268 *----------
269 */
270void
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;
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 */
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';
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
428
429 /* Create the backend statistics entry */
432
433 /* Update app name to current GUC setting */
436}
437
438/*
439 * Clear out our entry in the PgBackendStatus array.
440 */
441static void
443{
444 volatile PgBackendStatus *beentry = MyBEEntry;
445
446 /*
447 * Clear my status entry, following the protocol of bumping st_changecount
448 * before and after. We use a volatile pointer here to ensure the
449 * compiler doesn't try to get cute.
450 */
452
453 beentry->st_procpid = 0; /* mark invalid */
454
456
457 /* so that functions can check if backend_status.c is up via MyBEEntry */
458 MyBEEntry = NULL;
459}
460
461/*
462 * Discard any data collected in the current transaction. Any subsequent
463 * request will cause new snapshots to be read.
464 *
465 * This is also invoked during transaction commit or abort to discard the
466 * no-longer-wanted snapshot.
467 */
468void
470{
471 /* Release memory, if any was allocated */
473 {
476 }
477
478 /* Reset variables */
481}
482
483static void
485{
488 "Backend Status Snapshot",
490}
491
492
493/* ----------
494 * pgstat_report_activity() -
495 *
496 * Called from tcop/postgres.c to report what the backend is actually doing
497 * (but note cmd_str can be NULL for certain cases).
498 *
499 * All updates of the status entry follow the protocol of bumping
500 * st_changecount before and after. We use a volatile pointer here to
501 * ensure the compiler doesn't try to get cute.
502 * ----------
503 */
504void
506{
507 volatile PgBackendStatus *beentry = MyBEEntry;
508 TimestampTz start_timestamp;
509 TimestampTz current_timestamp;
510 int len = 0;
511
512 TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
513
514 if (!beentry)
515 return;
516
518 {
519 if (beentry->st_state != STATE_DISABLED)
520 {
521 volatile PGPROC *proc = MyProc;
522
523 /*
524 * track_activities is disabled, but we last reported a
525 * non-disabled state. As our final update, change the state and
526 * clear fields we will not be updating anymore.
527 */
529 beentry->st_state = STATE_DISABLED;
530 beentry->st_state_start_timestamp = 0;
531 beentry->st_activity_raw[0] = '\0';
532 beentry->st_activity_start_timestamp = 0;
533 /* st_xact_start_timestamp and wait_event_info are also disabled */
534 beentry->st_xact_start_timestamp = 0;
535 beentry->st_query_id = UINT64CONST(0);
536 proc->wait_event_info = 0;
538 }
539 return;
540 }
541
542 /*
543 * To minimize the time spent modifying the entry, and avoid risk of
544 * errors inside the critical section, fetch all the needed data first.
545 */
546 start_timestamp = GetCurrentStatementStartTimestamp();
547 if (cmd_str != NULL)
548 {
549 /*
550 * Compute length of to-be-stored string unaware of multi-byte
551 * characters. For speed reasons that'll get corrected on read, rather
552 * than computed every write.
553 */
554 len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
555 }
556 current_timestamp = GetCurrentTimestamp();
557
558 /*
559 * If the state has changed from "active" or "idle in transaction",
560 * calculate the duration.
561 */
562 if ((beentry->st_state == STATE_RUNNING ||
563 beentry->st_state == STATE_FASTPATH ||
564 beentry->st_state == STATE_IDLEINTRANSACTION ||
566 state != beentry->st_state)
567 {
568 long secs;
569 int usecs;
570
572 current_timestamp,
573 &secs, &usecs);
574
575 if (beentry->st_state == STATE_RUNNING ||
576 beentry->st_state == STATE_FASTPATH)
577 pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
578 else
579 pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
580 }
581
582 /*
583 * Now update the status entry
584 */
586
587 beentry->st_state = state;
588 beentry->st_state_start_timestamp = current_timestamp;
589
590 /*
591 * If a new query is started, we reset the query identifier as it'll only
592 * be known after parse analysis, to avoid reporting last query's
593 * identifier.
594 */
595 if (state == STATE_RUNNING)
596 beentry->st_query_id = UINT64CONST(0);
597
598 if (cmd_str != NULL)
599 {
600 memcpy((char *) beentry->st_activity_raw, cmd_str, len);
601 beentry->st_activity_raw[len] = '\0';
602 beentry->st_activity_start_timestamp = start_timestamp;
603 }
604
606}
607
608/* --------
609 * pgstat_report_query_id() -
610 *
611 * Called to update top-level query identifier.
612 * --------
613 */
614void
615pgstat_report_query_id(uint64 query_id, bool force)
616{
617 volatile PgBackendStatus *beentry = MyBEEntry;
618
619 /*
620 * if track_activities is disabled, st_query_id should already have been
621 * reset
622 */
623 if (!beentry || !pgstat_track_activities)
624 return;
625
626 /*
627 * We only report the top-level query identifiers. The stored query_id is
628 * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
629 * with an explicit call to this function using the force flag. If the
630 * saved query identifier is not zero it means that it's not a top-level
631 * command, so ignore the one provided unless it's an explicit call to
632 * reset the identifier.
633 */
634 if (beentry->st_query_id != 0 && !force)
635 return;
636
637 /*
638 * Update my status entry, following the protocol of bumping
639 * st_changecount before and after. We use a volatile pointer here to
640 * ensure the compiler doesn't try to get cute.
641 */
643 beentry->st_query_id = query_id;
645}
646
647
648/* ----------
649 * pgstat_report_appname() -
650 *
651 * Called to update our application name.
652 * ----------
653 */
654void
655pgstat_report_appname(const char *appname)
656{
657 volatile PgBackendStatus *beentry = MyBEEntry;
658 int len;
659
660 if (!beentry)
661 return;
662
663 /* This should be unnecessary if GUC did its job, but be safe */
664 len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
665
666 /*
667 * Update my status entry, following the protocol of bumping
668 * st_changecount before and after. We use a volatile pointer here to
669 * ensure the compiler doesn't try to get cute.
670 */
672
673 memcpy((char *) beentry->st_appname, appname, len);
674 beentry->st_appname[len] = '\0';
675
677}
678
679/*
680 * Report current transaction start timestamp as the specified value.
681 * Zero means there is no active transaction.
682 */
683void
685{
686 volatile PgBackendStatus *beentry = MyBEEntry;
687
688 if (!pgstat_track_activities || !beentry)
689 return;
690
691 /*
692 * Update my status entry, following the protocol of bumping
693 * st_changecount before and after. We use a volatile pointer here to
694 * ensure the compiler doesn't try to get cute.
695 */
697
698 beentry->st_xact_start_timestamp = tstamp;
699
701}
702
703/* ----------
704 * pgstat_read_current_status() -
705 *
706 * Copy the current contents of the PgBackendStatus array to local memory,
707 * if not already done in this transaction.
708 * ----------
709 */
710static void
712{
713 volatile PgBackendStatus *beentry;
714 LocalPgBackendStatus *localtable;
715 LocalPgBackendStatus *localentry;
716 char *localappname,
717 *localclienthostname,
718 *localactivity;
719#ifdef USE_SSL
720 PgBackendSSLStatus *localsslstatus;
721#endif
722#ifdef ENABLE_GSS
723 PgBackendGSSStatus *localgssstatus;
724#endif
725 ProcNumber procNumber;
726
728 return; /* already done */
729
731
732 /*
733 * Allocate storage for local copy of state data. We can presume that
734 * none of these requests overflow size_t, because we already calculated
735 * the same values using mul_size during shmem setup. However, with
736 * probably-silly values of pgstat_track_activity_query_size and
737 * max_connections, the localactivity buffer could exceed 1GB, so use
738 * "huge" allocation for that one.
739 */
740 localtable = (LocalPgBackendStatus *)
743 localappname = (char *)
746 localclienthostname = (char *)
749 localactivity = (char *)
753#ifdef USE_SSL
754 localsslstatus = (PgBackendSSLStatus *)
757#endif
758#ifdef ENABLE_GSS
759 localgssstatus = (PgBackendGSSStatus *)
762#endif
763
765
766 beentry = BackendStatusArray;
767 localentry = localtable;
768 for (procNumber = 0; procNumber < NumBackendStatSlots; procNumber++)
769 {
770 /*
771 * Follow the protocol of retrying if st_changecount changes while we
772 * copy the entry, or if it's odd. (The check for odd is needed to
773 * cover the case where we are able to completely copy the entry while
774 * the source backend is between increment steps.) We use a volatile
775 * pointer here to ensure the compiler doesn't try to get cute.
776 */
777 for (;;)
778 {
779 int before_changecount;
780 int after_changecount;
781
782 pgstat_begin_read_activity(beentry, before_changecount);
783
784 localentry->backendStatus.st_procpid = beentry->st_procpid;
785 /* Skip all the data-copying work if entry is not in use */
786 if (localentry->backendStatus.st_procpid > 0)
787 {
788 memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
789
790 /*
791 * For each PgBackendStatus field that is a pointer, copy the
792 * pointed-to data, then adjust the local copy of the pointer
793 * field to point at the local copy of the data.
794 *
795 * strcpy is safe even if the string is modified concurrently,
796 * because there's always a \0 at the end of the buffer.
797 */
798 strcpy(localappname, (char *) beentry->st_appname);
799 localentry->backendStatus.st_appname = localappname;
800 strcpy(localclienthostname, (char *) beentry->st_clienthostname);
801 localentry->backendStatus.st_clienthostname = localclienthostname;
802 strcpy(localactivity, (char *) beentry->st_activity_raw);
803 localentry->backendStatus.st_activity_raw = localactivity;
804#ifdef USE_SSL
805 if (beentry->st_ssl)
806 {
807 memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
808 localentry->backendStatus.st_sslstatus = localsslstatus;
809 }
810#endif
811#ifdef ENABLE_GSS
812 if (beentry->st_gss)
813 {
814 memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
815 localentry->backendStatus.st_gssstatus = localgssstatus;
816 }
817#endif
818 }
819
820 pgstat_end_read_activity(beentry, after_changecount);
821
822 if (pgstat_read_activity_complete(before_changecount,
823 after_changecount))
824 break;
825
826 /* Make sure we can break out of loop if stuck... */
828 }
829
830 /* Only valid entries get included into the local array */
831 if (localentry->backendStatus.st_procpid > 0)
832 {
833 /*
834 * The BackendStatusArray index is exactly the ProcNumber of the
835 * source backend. Note that this means localBackendStatusTable
836 * is in order by proc_number. pgstat_get_beentry_by_proc_number()
837 * depends on that.
838 */
839 localentry->proc_number = procNumber;
841 &localentry->backend_xid,
842 &localentry->backend_xmin,
843 &localentry->backend_subxact_count,
844 &localentry->backend_subxact_overflowed);
845
846 localentry++;
847 localappname += NAMEDATALEN;
848 localclienthostname += NAMEDATALEN;
849 localactivity += pgstat_track_activity_query_size;
850#ifdef USE_SSL
851 localsslstatus++;
852#endif
853#ifdef ENABLE_GSS
854 localgssstatus++;
855#endif
857 }
858
859 beentry++;
860 }
861
862 /* Set the pointer only after completion of a valid table */
863 localBackendStatusTable = localtable;
864}
865
866
867/* ----------
868 * pgstat_get_backend_current_activity() -
869 *
870 * Return a string representing the current activity of the backend with
871 * the specified PID. This looks directly at the BackendStatusArray,
872 * and so will provide current information regardless of the age of our
873 * transaction's snapshot of the status array.
874 *
875 * It is the caller's responsibility to invoke this only for backends whose
876 * state is expected to remain stable while the result is in use. The
877 * only current use is in deadlock reporting, where we can expect that
878 * the target backend is blocked on a lock. (There are corner cases
879 * where the target's wait could get aborted while we are looking at it,
880 * but the very worst consequence is to return a pointer to a string
881 * that's been changed, so we won't worry too much.)
882 *
883 * Note: return strings for special cases match pg_stat_get_backend_activity.
884 * ----------
885 */
886const char *
888{
889 PgBackendStatus *beentry;
890 int i;
891
892 beentry = BackendStatusArray;
893 for (i = 1; i <= MaxBackends; i++)
894 {
895 /*
896 * Although we expect the target backend's entry to be stable, that
897 * doesn't imply that anyone else's is. To avoid identifying the
898 * wrong backend, while we check for a match to the desired PID we
899 * must follow the protocol of retrying if st_changecount changes
900 * while we examine the entry, or if it's odd. (This might be
901 * unnecessary, since fetching or storing an int is almost certainly
902 * atomic, but let's play it safe.) We use a volatile pointer here to
903 * ensure the compiler doesn't try to get cute.
904 */
905 volatile PgBackendStatus *vbeentry = beentry;
906 bool found;
907
908 for (;;)
909 {
910 int before_changecount;
911 int after_changecount;
912
913 pgstat_begin_read_activity(vbeentry, before_changecount);
914
915 found = (vbeentry->st_procpid == pid);
916
917 pgstat_end_read_activity(vbeentry, after_changecount);
918
919 if (pgstat_read_activity_complete(before_changecount,
920 after_changecount))
921 break;
922
923 /* Make sure we can break out of loop if stuck... */
925 }
926
927 if (found)
928 {
929 /* Now it is safe to use the non-volatile pointer */
930 if (checkUser && !superuser() && beentry->st_userid != GetUserId())
931 return "<insufficient privilege>";
932 else if (*(beentry->st_activity_raw) == '\0')
933 return "<command string not enabled>";
934 else
935 {
936 /* this'll leak a bit of memory, but that seems acceptable */
937 return pgstat_clip_activity(beentry->st_activity_raw);
938 }
939 }
940
941 beentry++;
942 }
943
944 /* If we get here, caller is in error ... */
945 return "<backend information not available>";
946}
947
948/* ----------
949 * pgstat_get_crashed_backend_activity() -
950 *
951 * Return a string representing the current activity of the backend with
952 * the specified PID. Like the function above, but reads shared memory with
953 * the expectation that it may be corrupt. On success, copy the string
954 * into the "buffer" argument and return that pointer. On failure,
955 * return NULL.
956 *
957 * This function is only intended to be used by the postmaster to report the
958 * query that crashed a backend. In particular, no attempt is made to
959 * follow the correct concurrency protocol when accessing the
960 * BackendStatusArray. But that's OK, in the worst case we'll return a
961 * corrupted message. We also must take care not to trip on ereport(ERROR).
962 * ----------
963 */
964const char *
965pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
966{
967 volatile PgBackendStatus *beentry;
968 int i;
969
970 beentry = BackendStatusArray;
971
972 /*
973 * We probably shouldn't get here before shared memory has been set up,
974 * but be safe.
975 */
976 if (beentry == NULL || BackendActivityBuffer == NULL)
977 return NULL;
978
979 for (i = 1; i <= MaxBackends; i++)
980 {
981 if (beentry->st_procpid == pid)
982 {
983 /* Read pointer just once, so it can't change after validation */
984 const char *activity = beentry->st_activity_raw;
985 const char *activity_last;
986
987 /*
988 * We mustn't access activity string before we verify that it
989 * falls within the BackendActivityBuffer. To make sure that the
990 * entire string including its ending is contained within the
991 * buffer, subtract one activity length from the buffer size.
992 */
995
996 if (activity < BackendActivityBuffer ||
997 activity > activity_last)
998 return NULL;
999
1000 /* If no string available, no point in a report */
1001 if (activity[0] == '\0')
1002 return NULL;
1003
1004 /*
1005 * Copy only ASCII-safe characters so we don't run into encoding
1006 * problems when reporting the message; and be sure not to run off
1007 * the end of memory. As only ASCII characters are reported, it
1008 * doesn't seem necessary to perform multibyte aware clipping.
1009 */
1010 ascii_safe_strlcpy(buffer, activity,
1012
1013 return buffer;
1014 }
1015
1016 beentry++;
1017 }
1018
1019 /* PID not found */
1020 return NULL;
1021}
1022
1023/* ----------
1024 * pgstat_get_my_query_id() -
1025 *
1026 * Return current backend's query identifier.
1027 */
1028uint64
1030{
1031 if (!MyBEEntry)
1032 return 0;
1033
1034 /*
1035 * There's no need for a lock around pgstat_begin_read_activity /
1036 * pgstat_end_read_activity here as it's only called from
1037 * pg_stat_get_activity which is already protected, or from the same
1038 * backend which means that there won't be concurrent writes.
1039 */
1040 return MyBEEntry->st_query_id;
1041}
1042
1043/* ----------
1044 * pgstat_get_backend_type_by_proc_number() -
1045 *
1046 * Return the type of the backend with the specified ProcNumber. This looks
1047 * directly at the BackendStatusArray, so the return value may be out of date.
1048 * The only current use of this function is in pg_signal_backend(), which is
1049 * inherently racy, so we don't worry too much about this.
1050 *
1051 * It is the caller's responsibility to use this wisely; at minimum, callers
1052 * should ensure that procNumber is valid and perform the required permissions
1053 * checks.
1054 * ----------
1055 */
1058{
1059 volatile PgBackendStatus *status = &BackendStatusArray[procNumber];
1060
1061 /*
1062 * We bypass the changecount mechanism since fetching and storing an int
1063 * is almost certainly atomic.
1064 */
1065 return status->st_backendType;
1066}
1067
1068/* ----------
1069 * cmp_lbestatus
1070 *
1071 * Comparison function for bsearch() on an array of LocalPgBackendStatus.
1072 * The proc_number field is used to compare the arguments.
1073 * ----------
1074 */
1075static int
1076cmp_lbestatus(const void *a, const void *b)
1077{
1078 const LocalPgBackendStatus *lbestatus1 = (const LocalPgBackendStatus *) a;
1079 const LocalPgBackendStatus *lbestatus2 = (const LocalPgBackendStatus *) b;
1080
1081 return lbestatus1->proc_number - lbestatus2->proc_number;
1082}
1083
1084/* ----------
1085 * pgstat_get_beentry_by_proc_number() -
1086 *
1087 * Support function for the SQL-callable pgstat* functions. Returns
1088 * our local copy of the current-activity entry for one backend,
1089 * or NULL if the given beid doesn't identify any known session.
1090 *
1091 * The argument is the ProcNumber of the desired session
1092 * (note that this is unlike pgstat_get_local_beentry_by_index()).
1093 *
1094 * NB: caller is responsible for a check if the user is permitted to see
1095 * this info (especially the querystring).
1096 * ----------
1097 */
1100{
1102
1103 if (ret)
1104 return &ret->backendStatus;
1105
1106 return NULL;
1107}
1108
1109
1110/* ----------
1111 * pgstat_get_local_beentry_by_proc_number() -
1112 *
1113 * Like pgstat_get_beentry_by_proc_number() but with locally computed additions
1114 * (like xid and xmin values of the backend)
1115 *
1116 * The argument is the ProcNumber of the desired session
1117 * (note that this is unlike pgstat_get_local_beentry_by_index()).
1118 *
1119 * NB: caller is responsible for checking if the user is permitted to see this
1120 * info (especially the querystring).
1121 * ----------
1122 */
1125{
1127
1129
1130 /*
1131 * Since the localBackendStatusTable is in order by proc_number, we can
1132 * use bsearch() to search it efficiently.
1133 */
1134 key.proc_number = procNumber;
1137}
1138
1139
1140/* ----------
1141 * pgstat_get_local_beentry_by_index() -
1142 *
1143 * Like pgstat_get_beentry_by_proc_number() but with locally computed
1144 * additions (like xid and xmin values of the backend)
1145 *
1146 * The idx argument is a 1-based index in the localBackendStatusTable
1147 * (note that this is unlike pgstat_get_beentry_by_proc_number()).
1148 * Returns NULL if the argument is out of range (no current caller does that).
1149 *
1150 * NB: caller is responsible for a check if the user is permitted to see
1151 * this info (especially the querystring).
1152 * ----------
1153 */
1156{
1158
1159 if (idx < 1 || idx > localNumBackends)
1160 return NULL;
1161
1162 return &localBackendStatusTable[idx - 1];
1163}
1164
1165
1166/* ----------
1167 * pgstat_fetch_stat_numbackends() -
1168 *
1169 * Support function for the SQL-callable pgstat* functions. Returns
1170 * the number of sessions known in the localBackendStatusTable, i.e.
1171 * the maximum 1-based index to pass to pgstat_get_local_beentry_by_index().
1172 * ----------
1173 */
1174int
1176{
1178
1179 return localNumBackends;
1180}
1181
1182/*
1183 * Convert a potentially unsafely truncated activity string (see
1184 * PgBackendStatus.st_activity_raw's documentation) into a correctly truncated
1185 * one.
1186 *
1187 * The returned string is allocated in the caller's memory context and may be
1188 * freed.
1189 */
1190char *
1191pgstat_clip_activity(const char *raw_activity)
1192{
1193 char *activity;
1194 int rawlen;
1195 int cliplen;
1196
1197 /*
1198 * Some callers, like pgstat_get_backend_current_activity(), do not
1199 * guarantee that the buffer isn't concurrently modified. We try to take
1200 * care that the buffer is always terminated by a NUL byte regardless, but
1201 * let's still be paranoid about the string's length. In those cases the
1202 * underlying buffer is guaranteed to be pgstat_track_activity_query_size
1203 * large.
1204 */
1205 activity = pnstrdup(raw_activity, pgstat_track_activity_query_size - 1);
1206
1207 /* now double-guaranteed to be NUL terminated */
1208 rawlen = strlen(activity);
1209
1210 /*
1211 * All supported server-encodings make it possible to determine the length
1212 * of a multi-byte character from its first byte (this is not the case for
1213 * client encodings, see GB18030). As st_activity is always stored using
1214 * server encoding, this allows us to perform multi-byte aware truncation,
1215 * even if the string earlier was truncated in the middle of a multi-byte
1216 * character.
1217 */
1218 cliplen = pg_mbcliplen(activity, rawlen,
1220
1221 activity[cliplen] = '\0';
1222
1223 return activity;
1224}
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
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1720
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1644
@ PROGRESS_COMMAND_INVALID
#define NumBackendStatSlots
int pgstat_fetch_stat_numbackends(void)
PgBackendStatus * MyBEEntry
uint64 pgstat_get_my_query_id(void)
LocalPgBackendStatus * pgstat_get_local_beentry_by_proc_number(ProcNumber procNumber)
void pgstat_clear_backend_activity_snapshot(void)
static LocalPgBackendStatus * localBackendStatusTable
static int localNumBackends
static void pgstat_beshutdown_hook(int code, Datum arg)
static char * BackendClientHostnameBuffer
static int cmp_lbestatus(const void *a, const void *b)
bool pgstat_track_activities
char * pgstat_clip_activity(const char *raw_activity)
static MemoryContext backendStatusSnapContext
const char * pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
static char * BackendActivityBuffer
void BackendStatusShmemInit(void)
static void pgstat_setup_backend_status_context(void)
LocalPgBackendStatus * pgstat_get_local_beentry_by_index(int idx)
void pgstat_report_query_id(uint64 query_id, bool force)
static char * BackendAppnameBuffer
void pgstat_report_activity(BackendState state, const char *cmd_str)
BackendType pgstat_get_backend_type_by_proc_number(ProcNumber procNumber)
void pgstat_report_xact_timestamp(TimestampTz tstamp)
PgBackendStatus * pgstat_get_beentry_by_proc_number(ProcNumber procNumber)
static PgBackendStatus * BackendStatusArray
void pgstat_beinit(void)
Size BackendStatusShmemSize(void)
void pgstat_report_appname(const char *appname)
static Size BackendActivityBufferSize
const char * pgstat_get_backend_current_activity(int pid, bool checkUser)
static void pgstat_read_current_status(void)
int pgstat_track_activity_query_size
void pgstat_bestart(void)
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)
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)
const char * be_tls_get_cipher(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)
void be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len)
#define Min(x, y)
Definition: c.h:961
#define unvolatize(underlying_type, expr)
Definition: c.h:1204
#define Assert(condition)
Definition: c.h:815
uint64_t uint64
Definition: c.h:489
#define MemSet(start, val, len)
Definition: c.h:977
#define UINT64CONST(x)
Definition: c.h:503
size_t Size
Definition: c.h:562
int64 TimestampTz
Definition: timestamp.h:39
int MyProcPid
Definition: globals.c:46
ProcNumber MyProcNumber
Definition: globals.c:89
int MaxBackends
Definition: globals.c:145
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
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
int b
Definition: isn.c:69
int a
Definition: isn.c:68
int i
Definition: isn.c:72
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
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1181
MemoryContext TopMemoryContext
Definition: mcxt.c:149
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1707
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition: mcxt.c:1640
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:170
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
BackendType
Definition: miscadmin.h:337
@ B_WAL_SENDER
Definition: miscadmin.h:346
@ B_BG_WORKER
Definition: miscadmin.h:345
@ B_BACKEND
Definition: miscadmin.h:341
Oid GetUserId(void)
Definition: miscinit.c:517
Oid GetSessionUserId(void)
Definition: miscinit.c:556
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:616
#define pgstat_count_conn_active_time(n)
Definition: pgstat.h:614
int64 PgStat_Counter
Definition: pgstat.h:66
void pgstat_create_backend(ProcNumber procnum)
bool pgstat_tracks_backend_bktype(BackendType bktype)
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
uintptr_t Datum
Definition: postgres.h:69
#define InvalidOid
Definition: postgres_ext.h:37
void ProcNumberGetTransactionIds(ProcNumber procNumber, TransactionId *xid, TransactionId *xmin, int *nsubxid, bool *overflowed)
Definition: procarray.c:3160
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
int ProcNumber
Definition: procnumber.h:24
Size add_size(Size s1, Size s2)
Definition: shmem.c:488
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
static pg_noinline void Size size
Definition: slab.c:607
PGPROC * MyProc
Definition: proc.c:66
TransactionId backend_xid
PgBackendStatus backendStatus
TransactionId backend_xmin
Definition: proc.h:162
uint32 wait_event_info
Definition: proc.h:279
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:211
char * remote_hostname
Definition: libpq-be.h:142
void * gss
Definition: libpq-be.h:205
SockAddr raddr
Definition: libpq-be.h:140
Definition: regguts.h:323
bool superuser(void)
Definition: superuser.c:46
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:878