PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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-2026, 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 "storage/shmem.h"
23#include "storage/subsystems.h"
24#include "utils/ascii.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 PGPROC entry, including aux processes.
33 * (But not including PGPROC entries reserved for prepared xacts; they are not
34 * real processes.)
35 * ----------
36 */
37#define NumBackendStatSlots (MaxBackends + NUM_AUXILIARY_PROCS)
38
39
40/* ----------
41 * GUC parameters
42 * ----------
43 */
46
47
48/* exposed so that backend_progress.c can access it */
50
51
57#ifdef USE_SSL
59#endif
60#ifdef ENABLE_GSS
62#endif
63
64
65/* Status for backends including auxiliary */
67
68/* Total number of backends including auxiliary */
69static int localNumBackends = 0;
70
72
73
74static void pgstat_beshutdown_hook(int code, Datum arg);
75static void pgstat_read_current_status(void);
77
78static void BackendStatusShmemRequest(void *arg);
79static void BackendStatusShmemInit(void *arg);
80static void BackendStatusShmemAttach(void *arg);
81
87
88/*
89 * Register shared memory needs for backend status reporting.
90 */
91static void
93{
94 ShmemRequestStruct(.name = "Backend Status Array",
96 .ptr = (void **) &BackendStatusArray,
97 );
98
99 ShmemRequestStruct(.name = "Backend Application Name Buffer",
101 .ptr = (void **) &BackendAppnameBuffer,
102 );
103
104 ShmemRequestStruct(.name = "Backend Client Host Name Buffer",
106 .ptr = (void **) &BackendClientHostnameBuffer,
107 );
108
111 ShmemRequestStruct(.name = "Backend Activity Buffer",
113 .ptr = (void **) &BackendActivityBuffer
114 );
115
116#ifdef USE_SSL
117 ShmemRequestStruct(.name = "Backend SSL Status Buffer",
119 .ptr = (void **) &BackendSslStatusBuffer,
120 );
121#endif
122
123#ifdef ENABLE_GSS
124 ShmemRequestStruct(.name = "Backend GSS Status Buffer",
126 .ptr = (void **) &BackendGssStatusBuffer,
127 );
128#endif
129}
130
131/*
132 * Initialize the shared status array and several string buffers
133 * during postmaster startup.
134 */
135static void
137{
138 int i;
139 char *buffer;
140
141 /* Initialize st_appname pointers. */
142 buffer = BackendAppnameBuffer;
143 for (i = 0; i < NumBackendStatSlots; i++)
144 {
146 buffer += NAMEDATALEN;
147 }
148
149 /* Initialize st_clienthostname pointers. */
151 for (i = 0; i < NumBackendStatSlots; i++)
152 {
154 buffer += NAMEDATALEN;
155 }
156
157 /* Initialize st_activity pointers. */
158 buffer = BackendActivityBuffer;
159 for (i = 0; i < NumBackendStatSlots; i++)
160 {
163 }
164
165#ifdef USE_SSL
166 {
168
169 /* Initialize st_sslstatus pointers. */
171 for (i = 0; i < NumBackendStatSlots; i++)
172 {
174 ptr++;
175 }
176 }
177#endif
178
179#ifdef ENABLE_GSS
180 {
182
183 /* Initialize st_gssstatus pointers. */
185 for (i = 0; i < NumBackendStatSlots; i++)
186 {
188 ptr++;
189 }
190 }
191#endif
192}
193
194static void
200
201/*
202 * Initialize pgstats backend activity state, and set up our on-proc-exit
203 * hook. Called from InitPostgres and AuxiliaryProcessMain. MyProcNumber must
204 * be set, but we must not have started any transaction yet (since the exit
205 * hook must run after the last transaction exit).
206 *
207 * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
208 */
209void
211{
212 /* Initialize MyBEEntry */
216
217 /* Set up a process-exit hook to clean up */
219}
220
221
222/* ----------
223 * pgstat_bestart_initial() -
224 *
225 * Initialize this backend's entry in the PgBackendStatus array. Called
226 * from InitPostgres and AuxiliaryProcessMain.
227 *
228 * Clears out a new pgstat entry, initializing it to suitable defaults and
229 * reporting STATE_STARTING. Backends should continue filling in any
230 * transport security details as needed with pgstat_bestart_security(), and
231 * must finally exit STATE_STARTING by calling pgstat_bestart_final().
232 * ----------
233 */
234void
236{
239
240 /* pgstats state must be initialized from pgstat_beinit() */
241 Assert(vbeentry != NULL);
242
243 /*
244 * To minimize the time spent modifying the PgBackendStatus entry, and
245 * avoid risk of errors inside the critical section, we first copy the
246 * shared-memory struct to a local variable, then modify the data in the
247 * local variable, then copy the local variable back to shared memory.
248 * Only the last step has to be inside the critical section.
249 *
250 * Most of the data we copy from shared memory is just going to be
251 * overwritten, but the struct's not so large that it's worth the
252 * maintenance hassle to copy only the needful fields.
253 */
256 sizeof(PgBackendStatus));
257
258 /*
259 * Now fill in all the fields of lbeentry, except for strings that are
260 * out-of-line data. Those have to be handled separately, below.
261 */
262 lbeentry.st_procpid = MyProcPid;
263 lbeentry.st_backendType = MyBackendType;
264 lbeentry.st_proc_start_timestamp = MyStartTimestamp;
265 lbeentry.st_activity_start_timestamp = 0;
266 lbeentry.st_state_start_timestamp = 0;
267 lbeentry.st_xact_start_timestamp = 0;
268 lbeentry.st_databaseid = InvalidOid;
269 lbeentry.st_userid = InvalidOid;
270
271 /*
272 * We may not have a MyProcPort (eg, if this is the autovacuum process).
273 * If so, use all-zeroes client address, which is dealt with specially in
274 * pg_stat_get_backend_client_addr and pg_stat_get_backend_client_port.
275 */
276 if (MyProcPort)
277 memcpy(&lbeentry.st_clientaddr, &MyProcPort->raddr,
278 sizeof(lbeentry.st_clientaddr));
279 else
280 MemSet(&lbeentry.st_clientaddr, 0, sizeof(lbeentry.st_clientaddr));
281
282 lbeentry.st_ssl = false;
283 lbeentry.st_gss = false;
284
285 lbeentry.st_state = STATE_STARTING;
286 lbeentry.st_progress_command = PROGRESS_COMMAND_INVALID;
287 lbeentry.st_progress_command_target = InvalidOid;
288 lbeentry.st_query_id = INT64CONST(0);
289 lbeentry.st_plan_id = INT64CONST(0);
290
291 /*
292 * we don't zero st_progress_param here to save cycles; nobody should
293 * examine it until st_progress_command has been set to something other
294 * than PROGRESS_COMMAND_INVALID
295 */
296
297 /*
298 * We're ready to enter the critical section that fills the shared-memory
299 * status entry. We follow the protocol of bumping st_changecount before
300 * and after; and make sure it's even afterwards. We use a volatile
301 * pointer here to ensure the compiler doesn't try to get cute.
302 */
304
305 /* make sure we'll memcpy the same st_changecount back */
306 lbeentry.st_changecount = vbeentry->st_changecount;
307
309 &lbeentry,
310 sizeof(PgBackendStatus));
311
312 /*
313 * We can write the out-of-line strings and structs using the pointers
314 * that are in lbeentry; this saves some de-volatilizing messiness.
315 */
316 lbeentry.st_appname[0] = '\0';
318 strlcpy(lbeentry.st_clienthostname, MyProcPort->remote_hostname,
320 else
321 lbeentry.st_clienthostname[0] = '\0';
322 lbeentry.st_activity_raw[0] = '\0';
323 /* Also make sure the last byte in each string area is always 0 */
324 lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
325 lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
326 lbeentry.st_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
327
328 /* These structs can just start from zeroes each time */
329#ifdef USE_SSL
330 memset(lbeentry.st_sslstatus, 0, sizeof(PgBackendSSLStatus));
331#endif
332#ifdef ENABLE_GSS
333 memset(lbeentry.st_gssstatus, 0, sizeof(PgBackendGSSStatus));
334#endif
335
337}
338
339/* ----------
340 * pgstat_bestart_security() -
341 *
342 * Fill in SSL and GSS information for the pgstat entry. This is the second
343 * optional step taken when filling a backend's entry, not required for
344 * auxiliary processes.
345 *
346 * This should only be called from backends with a MyProcPort.
347 * ----------
348 */
349void
351{
353 bool ssl = false;
354 bool gss = false;
355#ifdef USE_SSL
357 PgBackendSSLStatus *st_sslstatus;
358#endif
359#ifdef ENABLE_GSS
361 PgBackendGSSStatus *st_gssstatus;
362#endif
363
364 /* pgstats state must be initialized from pgstat_beinit() */
365 Assert(beentry != NULL);
366 Assert(MyProcPort); /* otherwise there's no point */
367
368#ifdef USE_SSL
369 st_sslstatus = beentry->st_sslstatus;
370 memset(&lsslstatus, 0, sizeof(lsslstatus));
371
373 {
374 ssl = true;
381 }
382#endif
383
384#ifdef ENABLE_GSS
385 st_gssstatus = beentry->st_gssstatus;
386 memset(&lgssstatus, 0, sizeof(lgssstatus));
387
388 if (MyProcPort->gss != NULL)
389 {
390 const char *princ = be_gssapi_get_princ(MyProcPort);
391
392 gss = true;
396 if (princ)
397 strlcpy(lgssstatus.gss_princ, princ, NAMEDATALEN);
398 }
399#endif
400
401 /*
402 * Update my status entry, following the protocol of bumping
403 * st_changecount before and after. We use a volatile pointer here to
404 * ensure the compiler doesn't try to get cute.
405 */
407
408 beentry->st_ssl = ssl;
409 beentry->st_gss = gss;
410
411#ifdef USE_SSL
412 memcpy(st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
413#endif
414#ifdef ENABLE_GSS
415 memcpy(st_gssstatus, &lgssstatus, sizeof(PgBackendGSSStatus));
416#endif
417
419}
420
421/* ----------
422 * pgstat_bestart_final() -
423 *
424 * Finalizes the state of this backend's entry by filling in the user and
425 * database IDs, clearing STATE_STARTING, and reporting the application_name.
426 *
427 * We must be inside a transaction if this is not an auxiliary process, as
428 * we may need to do encoding conversion.
429 * ----------
430 */
431void
433{
435 Oid userid;
436
437 /* pgstats state must be initialized from pgstat_beinit() */
438 Assert(beentry != NULL);
439
440 /* We have userid for client-backends, wal-sender and bgworker processes */
444 userid = GetSessionUserId();
445 else
446 userid = InvalidOid;
447
448 /*
449 * Update my status entry, following the protocol of bumping
450 * st_changecount before and after. We use a volatile pointer here to
451 * ensure the compiler doesn't try to get cute.
452 */
454
455 beentry->st_databaseid = MyDatabaseId;
456 beentry->st_userid = userid;
457 beentry->st_state = STATE_UNDEFINED;
458
460
461 /* Create the backend statistics entry */
464
465 /* Update app name to current GUC setting */
468}
469
470/*
471 * Clear out our entry in the PgBackendStatus array.
472 */
473static void
475{
477
478 /*
479 * Clear my status entry, following the protocol of bumping st_changecount
480 * before and after. We use a volatile pointer here to ensure the
481 * compiler doesn't try to get cute.
482 */
484
485 beentry->st_procpid = 0; /* mark invalid */
486
488
489 /* so that functions can check if backend_status.c is up via MyBEEntry */
490 MyBEEntry = NULL;
491}
492
493/*
494 * Discard any data collected in the current transaction. Any subsequent
495 * request will cause new snapshots to be read.
496 *
497 * This is also invoked during transaction commit or abort to discard the
498 * no-longer-wanted snapshot.
499 */
500void
502{
503 /* Release memory, if any was allocated */
505 {
508 }
509
510 /* Reset variables */
513}
514
515static void
523
524
525/* ----------
526 * pgstat_report_activity() -
527 *
528 * Called from tcop/postgres.c to report what the backend is actually doing
529 * (but note cmd_str can be NULL for certain cases).
530 *
531 * All updates of the status entry follow the protocol of bumping
532 * st_changecount before and after. We use a volatile pointer here to
533 * ensure the compiler doesn't try to get cute.
534 * ----------
535 */
536void
538{
542 int len = 0;
543
545
546 if (!beentry)
547 return;
548
550 {
551 if (beentry->st_state != STATE_DISABLED)
552 {
553 volatile PGPROC *proc = MyProc;
554
555 /*
556 * track_activities is disabled, but we last reported a
557 * non-disabled state. As our final update, change the state and
558 * clear fields we will not be updating anymore.
559 */
561 beentry->st_state = STATE_DISABLED;
562 beentry->st_state_start_timestamp = 0;
563 beentry->st_activity_raw[0] = '\0';
564 beentry->st_activity_start_timestamp = 0;
565 /* st_xact_start_timestamp and wait_event_info are also disabled */
566 beentry->st_xact_start_timestamp = 0;
567 beentry->st_query_id = INT64CONST(0);
568 beentry->st_plan_id = INT64CONST(0);
569 proc->wait_event_info = 0;
571 }
572 return;
573 }
574
575 /*
576 * To minimize the time spent modifying the entry, and avoid risk of
577 * errors inside the critical section, fetch all the needed data first.
578 */
580 if (cmd_str != NULL)
581 {
582 /*
583 * Compute length of to-be-stored string unaware of multi-byte
584 * characters. For speed reasons that'll get corrected on read, rather
585 * than computed every write.
586 */
588 }
590
591 /*
592 * If the state has changed from "active" or "idle in transaction",
593 * calculate the duration.
594 */
595 if ((beentry->st_state == STATE_RUNNING ||
596 beentry->st_state == STATE_FASTPATH ||
597 beentry->st_state == STATE_IDLEINTRANSACTION ||
599 state != beentry->st_state)
600 {
601 long secs;
602 int usecs;
603
604 TimestampDifference(beentry->st_state_start_timestamp,
606 &secs, &usecs);
607
608 if (beentry->st_state == STATE_RUNNING ||
609 beentry->st_state == STATE_FASTPATH)
611 else
613 }
614
615 /*
616 * Now update the status entry
617 */
619
620 beentry->st_state = state;
621 beentry->st_state_start_timestamp = current_timestamp;
622
623 /*
624 * If a new query is started, we reset the query identifier as it'll only
625 * be known after parse analysis, to avoid reporting last query's
626 * identifier.
627 */
628 if (state == STATE_RUNNING)
629 {
630 beentry->st_query_id = INT64CONST(0);
631 beentry->st_plan_id = INT64CONST(0);
632 }
633
634 if (cmd_str != NULL)
635 {
636 memcpy(beentry->st_activity_raw, cmd_str, len);
637 beentry->st_activity_raw[len] = '\0';
638 beentry->st_activity_start_timestamp = start_timestamp;
639 }
640
642}
643
644/* --------
645 * pgstat_report_query_id() -
646 *
647 * Called to update top-level query identifier.
648 * --------
649 */
650void
652{
654
655 /*
656 * if track_activities is disabled, st_query_id should already have been
657 * reset
658 */
660 return;
661
662 /*
663 * We only report the top-level query identifiers. The stored query_id is
664 * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
665 * with an explicit call to this function using the force flag. If the
666 * saved query identifier is not zero it means that it's not a top-level
667 * command, so ignore the one provided unless it's an explicit call to
668 * reset the identifier.
669 */
670 if (beentry->st_query_id != INT64CONST(0) && !force)
671 return;
672
673 /*
674 * Update my status entry, following the protocol of bumping
675 * st_changecount before and after. We use a volatile pointer here to
676 * ensure the compiler doesn't try to get cute.
677 */
679 beentry->st_query_id = query_id;
681}
682
683/* --------
684 * pgstat_report_plan_id() -
685 *
686 * Called to update top-level plan identifier.
687 * --------
688 */
689void
690pgstat_report_plan_id(int64 plan_id, bool force)
691{
693
694 /*
695 * if track_activities is disabled, st_plan_id should already have been
696 * reset
697 */
699 return;
700
701 /*
702 * We only report the top-level plan identifiers. The stored plan_id is
703 * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
704 * with an explicit call to this function using the force flag. If the
705 * saved plan identifier is not zero it means that it's not a top-level
706 * command, so ignore the one provided unless it's an explicit call to
707 * reset the identifier.
708 */
709 if (beentry->st_plan_id != 0 && !force)
710 return;
711
712 /*
713 * Update my status entry, following the protocol of bumping
714 * st_changecount before and after. We use a volatile pointer here to
715 * ensure the compiler doesn't try to get cute.
716 */
718 beentry->st_plan_id = plan_id;
720}
721
722/* ----------
723 * pgstat_report_appname() -
724 *
725 * Called to update our application name.
726 * ----------
727 */
728void
729pgstat_report_appname(const char *appname)
730{
732 int len;
733
734 if (!beentry)
735 return;
736
737 /* This should be unnecessary if GUC did its job, but be safe */
738 len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
739
740 /*
741 * Update my status entry, following the protocol of bumping
742 * st_changecount before and after. We use a volatile pointer here to
743 * ensure the compiler doesn't try to get cute.
744 */
746
747 memcpy(beentry->st_appname, appname, len);
748 beentry->st_appname[len] = '\0';
749
751}
752
753/*
754 * Report current transaction start timestamp as the specified value.
755 * Zero means there is no active transaction.
756 */
757void
759{
761
763 return;
764
765 /*
766 * Update my status entry, following the protocol of bumping
767 * st_changecount before and after. We use a volatile pointer here to
768 * ensure the compiler doesn't try to get cute.
769 */
771
772 beentry->st_xact_start_timestamp = tstamp;
773
775}
776
777/* ----------
778 * pgstat_read_current_status() -
779 *
780 * Copy the current contents of the PgBackendStatus array to local memory,
781 * if not already done in this transaction.
782 * ----------
783 */
784static void
786{
787 volatile PgBackendStatus *beentry;
790 char *localappname,
793#ifdef USE_SSL
795#endif
796#ifdef ENABLE_GSS
798#endif
799 ProcNumber procNumber;
800
802 return; /* already done */
803
805
806 /*
807 * Allocate storage for local copy of state data. We can presume that
808 * none of these requests overflow size_t, because we already calculated
809 * the same values using mul_size during shmem setup. However, with
810 * probably-silly values of pgstat_track_activity_query_size and
811 * max_connections, the localactivity buffer could exceed 1GB, so use
812 * "huge" allocation for that one.
813 */
817 localappname = (char *)
820 localclienthostname = (char *)
823 localactivity = (char *)
827#ifdef USE_SSL
831#endif
832#ifdef ENABLE_GSS
836#endif
837
839
842 for (procNumber = 0; procNumber < NumBackendStatSlots; procNumber++)
843 {
844 /*
845 * Follow the protocol of retrying if st_changecount changes while we
846 * copy the entry, or if it's odd. (The check for odd is needed to
847 * cover the case where we are able to completely copy the entry while
848 * the source backend is between increment steps.) We use a volatile
849 * pointer here to ensure the compiler doesn't try to get cute.
850 */
851 for (;;)
852 {
855
857
858 localentry->backendStatus.st_procpid = beentry->st_procpid;
859 /* Skip all the data-copying work if entry is not in use */
860 if (localentry->backendStatus.st_procpid > 0)
861 {
862 memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
863
864 /*
865 * For each PgBackendStatus field that is a pointer, copy the
866 * pointed-to data, then adjust the local copy of the pointer
867 * field to point at the local copy of the data.
868 *
869 * strcpy is safe even if the string is modified concurrently,
870 * because there's always a \0 at the end of the buffer.
871 */
872 strcpy(localappname, beentry->st_appname);
873 localentry->backendStatus.st_appname = localappname;
874 strcpy(localclienthostname, beentry->st_clienthostname);
875 localentry->backendStatus.st_clienthostname = localclienthostname;
876 strcpy(localactivity, beentry->st_activity_raw);
877 localentry->backendStatus.st_activity_raw = localactivity;
878#ifdef USE_SSL
879 if (beentry->st_ssl)
880 {
881 memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
882 localentry->backendStatus.st_sslstatus = localsslstatus;
883 }
884#endif
885#ifdef ENABLE_GSS
886 if (beentry->st_gss)
887 {
888 memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
889 localentry->backendStatus.st_gssstatus = localgssstatus;
890 }
891#endif
892 }
893
895
898 break;
899
900 /* Make sure we can break out of loop if stuck... */
902 }
903
904 /* Only valid entries get included into the local array */
905 if (localentry->backendStatus.st_procpid > 0)
906 {
907 /*
908 * The BackendStatusArray index is exactly the ProcNumber of the
909 * source backend. Note that this means localBackendStatusTable
910 * is in order by proc_number. pgstat_get_beentry_by_proc_number()
911 * depends on that.
912 */
913 localentry->proc_number = procNumber;
915 &localentry->backend_xid,
916 &localentry->backend_xmin,
917 &localentry->backend_subxact_count,
918 &localentry->backend_subxact_overflowed);
919
920 localentry++;
924#ifdef USE_SSL
926#endif
927#ifdef ENABLE_GSS
929#endif
931 }
932
933 beentry++;
934 }
935
936 /* Set the pointer only after completion of a valid table */
938}
939
940
941/* ----------
942 * pgstat_get_backend_current_activity() -
943 *
944 * Return a string representing the current activity of the backend with
945 * the specified PID. This looks directly at the BackendStatusArray,
946 * and so will provide current information regardless of the age of our
947 * transaction's snapshot of the status array.
948 *
949 * It is the caller's responsibility to invoke this only for backends whose
950 * state is expected to remain stable while the result is in use. The
951 * only current use is in deadlock reporting, where we can expect that
952 * the target backend is blocked on a lock. (There are corner cases
953 * where the target's wait could get aborted while we are looking at it,
954 * but the very worst consequence is to return a pointer to a string
955 * that's been changed, so we won't worry too much.)
956 *
957 * Note: return strings for special cases match pg_stat_get_backend_activity.
958 * ----------
959 */
960const char *
962{
964 int i;
965
967 for (i = 1; i <= MaxBackends; i++)
968 {
969 /*
970 * Although we expect the target backend's entry to be stable, that
971 * doesn't imply that anyone else's is. To avoid identifying the
972 * wrong backend, while we check for a match to the desired PID we
973 * must follow the protocol of retrying if st_changecount changes
974 * while we examine the entry, or if it's odd. (This might be
975 * unnecessary, since fetching or storing an int is almost certainly
976 * atomic, but let's play it safe.) We use a volatile pointer here to
977 * ensure the compiler doesn't try to get cute.
978 */
979 volatile PgBackendStatus *vbeentry = beentry;
980 bool found;
981
982 for (;;)
983 {
986
988
989 found = (vbeentry->st_procpid == pid);
990
992
995 break;
996
997 /* Make sure we can break out of loop if stuck... */
999 }
1000
1001 if (found)
1002 {
1003 /* Now it is safe to use the non-volatile pointer */
1004 if (checkUser && !superuser() && beentry->st_userid != GetUserId())
1005 return "<insufficient privilege>";
1006 else if (*(beentry->st_activity_raw) == '\0')
1007 return "<command string not enabled>";
1008 else
1009 {
1010 /* this'll leak a bit of memory, but that seems acceptable */
1011 return pgstat_clip_activity(beentry->st_activity_raw);
1012 }
1013 }
1014
1015 beentry++;
1016 }
1017
1018 /* If we get here, caller is in error ... */
1019 return "<backend information not available>";
1020}
1021
1022/* ----------
1023 * pgstat_get_crashed_backend_activity() -
1024 *
1025 * Return a string representing the current activity of the backend with
1026 * the specified PID. Like the function above, but reads shared memory with
1027 * the expectation that it may be corrupt. On success, copy the string
1028 * into the "buffer" argument and return that pointer. On failure,
1029 * return NULL.
1030 *
1031 * This function is only intended to be used by the postmaster to report the
1032 * query that crashed a backend. In particular, no attempt is made to
1033 * follow the correct concurrency protocol when accessing the
1034 * BackendStatusArray. But that's OK, in the worst case we'll return a
1035 * corrupted message. We also must take care not to trip on ereport(ERROR).
1036 * ----------
1037 */
1038const char *
1039pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
1040{
1041 volatile PgBackendStatus *beentry;
1042 int i;
1043
1045
1046 /*
1047 * We probably shouldn't get here before shared memory has been set up,
1048 * but be safe.
1049 */
1051 return NULL;
1052
1053 for (i = 1; i <= MaxBackends; i++)
1054 {
1055 if (beentry->st_procpid == pid)
1056 {
1057 /* Read pointer just once, so it can't change after validation */
1058 const char *activity = beentry->st_activity_raw;
1059 const char *activity_last;
1060
1061 /*
1062 * We mustn't access activity string before we verify that it
1063 * falls within the BackendActivityBuffer. To make sure that the
1064 * entire string including its ending is contained within the
1065 * buffer, subtract one activity length from the buffer size.
1066 */
1069
1072 return NULL;
1073
1074 /* If no string available, no point in a report */
1075 if (activity[0] == '\0')
1076 return NULL;
1077
1078 /*
1079 * Copy only ASCII-safe characters so we don't run into encoding
1080 * problems when reporting the message; and be sure not to run off
1081 * the end of memory. As only ASCII characters are reported, it
1082 * doesn't seem necessary to perform multibyte aware clipping.
1083 */
1086
1087 return buffer;
1088 }
1089
1090 beentry++;
1091 }
1092
1093 /* PID not found */
1094 return NULL;
1095}
1096
1097/* ----------
1098 * pgstat_get_my_query_id() -
1099 *
1100 * Return current backend's query identifier.
1101 */
1102int64
1104{
1105 if (!MyBEEntry)
1106 return 0;
1107
1108 /*
1109 * There's no need for a lock around pgstat_begin_read_activity /
1110 * pgstat_end_read_activity here as it's only called from
1111 * pg_stat_get_activity which is already protected, or from the same
1112 * backend which means that there won't be concurrent writes.
1113 */
1114 return MyBEEntry->st_query_id;
1115}
1116
1117/* ----------
1118 * pgstat_get_my_plan_id() -
1119 *
1120 * Return current backend's plan identifier.
1121 */
1122int64
1124{
1125 if (!MyBEEntry)
1126 return 0;
1127
1128 /* No need for a lock, for roughly the same reasons as above. */
1129 return MyBEEntry->st_plan_id;
1130}
1131
1132/* ----------
1133 * cmp_lbestatus
1134 *
1135 * Comparison function for bsearch() on an array of LocalPgBackendStatus.
1136 * The proc_number field is used to compare the arguments.
1137 * ----------
1138 */
1139static int
1140cmp_lbestatus(const void *a, const void *b)
1141{
1144
1145 return lbestatus1->proc_number - lbestatus2->proc_number;
1146}
1147
1148/* ----------
1149 * pgstat_get_beentry_by_proc_number() -
1150 *
1151 * Support function for the SQL-callable pgstat* functions. Returns
1152 * our local copy of the current-activity entry for one backend,
1153 * or NULL if the given beid doesn't identify any known session.
1154 *
1155 * The argument is the ProcNumber of the desired session
1156 * (note that this is unlike pgstat_get_local_beentry_by_index()).
1157 *
1158 * NB: caller is responsible for a check if the user is permitted to see
1159 * this info (especially the querystring).
1160 * ----------
1161 */
1164{
1166
1167 if (ret)
1168 return &ret->backendStatus;
1169
1170 return NULL;
1171}
1172
1173
1174/* ----------
1175 * pgstat_get_local_beentry_by_proc_number() -
1176 *
1177 * Like pgstat_get_beentry_by_proc_number() but with locally computed additions
1178 * (like xid and xmin values of the backend)
1179 *
1180 * The argument is the ProcNumber of the desired session
1181 * (note that this is unlike pgstat_get_local_beentry_by_index()).
1182 *
1183 * NB: caller is responsible for checking if the user is permitted to see this
1184 * info (especially the querystring).
1185 * ----------
1186 */
1189{
1191
1193
1194 /*
1195 * Since the localBackendStatusTable is in order by proc_number, we can
1196 * use bsearch() to search it efficiently.
1197 */
1198 key.proc_number = procNumber;
1201}
1202
1203
1204/* ----------
1205 * pgstat_get_local_beentry_by_index() -
1206 *
1207 * Like pgstat_get_beentry_by_proc_number() but with locally computed
1208 * additions (like xid and xmin values of the backend)
1209 *
1210 * The idx argument is a 1-based index in the localBackendStatusTable
1211 * (note that this is unlike pgstat_get_beentry_by_proc_number()).
1212 * Returns NULL if the argument is out of range (no current caller does that).
1213 *
1214 * NB: caller is responsible for a check if the user is permitted to see
1215 * this info (especially the querystring).
1216 * ----------
1217 */
1228
1229
1230/* ----------
1231 * pgstat_fetch_stat_numbackends() -
1232 *
1233 * Support function for the SQL-callable pgstat* functions. Returns
1234 * the number of sessions known in the localBackendStatusTable, i.e.
1235 * the maximum 1-based index to pass to pgstat_get_local_beentry_by_index().
1236 * ----------
1237 */
1238int
1245
1246/*
1247 * Convert a potentially unsafely truncated activity string (see
1248 * PgBackendStatus.st_activity_raw's documentation) into a correctly truncated
1249 * one.
1250 *
1251 * The returned string is allocated in the caller's memory context and may be
1252 * freed.
1253 */
1254char *
1256{
1257 char *activity;
1258 int rawlen;
1259 int cliplen;
1260
1261 /*
1262 * Some callers, like pgstat_get_backend_current_activity(), do not
1263 * guarantee that the buffer isn't concurrently modified. We try to take
1264 * care that the buffer is always terminated by a NUL byte regardless, but
1265 * let's still be paranoid about the string's length. In those cases the
1266 * underlying buffer is guaranteed to be pgstat_track_activity_query_size
1267 * large.
1268 */
1270
1271 /* now double-guaranteed to be NUL terminated */
1273
1274 /*
1275 * All supported server-encodings make it possible to determine the length
1276 * of a multi-byte character from its first byte (this is not the case for
1277 * client encodings, see GB18030). As st_activity is always stored using
1278 * server encoding, this allows us to perform multi-byte aware truncation,
1279 * even if the string earlier was truncated in the middle of a multi-byte
1280 * character.
1281 */
1284
1285 activity[cliplen] = '\0';
1286
1287 return activity;
1288}
Datum idx(PG_FUNCTION_ARGS)
Definition _int_op.c:262
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:1715
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1639
@ PROGRESS_COMMAND_INVALID
#define NumBackendStatSlots
int pgstat_fetch_stat_numbackends(void)
PgBackendStatus * MyBEEntry
const ShmemCallbacks BackendStatusShmemCallbacks
LocalPgBackendStatus * pgstat_get_local_beentry_by_proc_number(ProcNumber procNumber)
void pgstat_clear_backend_activity_snapshot(void)
static LocalPgBackendStatus * localBackendStatusTable
void pgstat_bestart_security(void)
static int localNumBackends
void pgstat_bestart_initial(void)
static void pgstat_beshutdown_hook(int code, Datum arg)
void pgstat_report_query_id(int64 query_id, bool force)
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
static void BackendStatusShmemRequest(void *arg)
int64 pgstat_get_my_query_id(void)
const char * pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
static char * BackendActivityBuffer
static void pgstat_setup_backend_status_context(void)
LocalPgBackendStatus * pgstat_get_local_beentry_by_index(int idx)
static char * BackendAppnameBuffer
static void BackendStatusShmemInit(void *arg)
static void BackendStatusShmemAttach(void *arg)
void pgstat_report_activity(BackendState state, const char *cmd_str)
void pgstat_report_xact_timestamp(TimestampTz tstamp)
void pgstat_report_plan_id(int64 plan_id, bool force)
PgBackendStatus * pgstat_get_beentry_by_proc_number(ProcNumber procNumber)
static PgBackendStatus * BackendStatusArray
int64 pgstat_get_my_plan_id(void)
void pgstat_beinit(void)
void pgstat_bestart_final(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
BackendState
@ STATE_UNDEFINED
@ STATE_IDLEINTRANSACTION_ABORTED
@ STATE_STARTING
@ 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 INT64CONST(x)
Definition c.h:630
#define Min(x, y)
Definition c.h:1091
#define unvolatize(underlying_type, expr)
Definition c.h:1328
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
#define MemSet(start, val, len)
Definition c.h:1107
size_t Size
Definition c.h:689
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int64 TimestampTz
Definition timestamp.h:39
Datum arg
Definition elog.c:1322
int MyProcPid
Definition globals.c:49
ProcNumber MyProcNumber
Definition globals.c:92
int MaxBackends
Definition globals.c:149
TimestampTz MyStartTimestamp
Definition globals.c:51
struct Port * MyProcPort
Definition globals.c:53
Oid MyDatabaseId
Definition globals.c:96
char * application_name
Definition guc_tables.c:589
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition ipc.c:372
int b
Definition isn.c:74
int a
Definition isn.c:73
int i
Definition isn.c:77
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1211
static int cliplen(const char *str, int len, int limit)
Definition mbutils.c:1278
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
MemoryContext TopMemoryContext
Definition mcxt.c:166
char * pnstrdup(const char *in, Size len)
Definition mcxt.c:1792
void * MemoryContextAllocHuge(MemoryContext context, Size size)
Definition mcxt.c:1725
void MemoryContextDelete(MemoryContext context)
Definition mcxt.c:472
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
@ B_WAL_SENDER
Definition miscadmin.h:359
@ B_BG_WORKER
Definition miscadmin.h:358
@ B_BACKEND
Definition miscadmin.h:354
Oid GetUserId(void)
Definition miscinit.c:470
Oid GetSessionUserId(void)
Definition miscinit.c:509
BackendType MyBackendType
Definition miscinit.c:65
#define NAMEDATALEN
const void size_t len
#define pgstat_count_conn_txn_idle_time(n)
Definition pgstat.h:664
#define pgstat_count_conn_active_time(n)
Definition pgstat.h:662
int64 PgStat_Counter
Definition pgstat.h:71
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
uint64_t Datum
Definition postgres.h:70
#define InvalidOid
unsigned int Oid
static int fb(int x)
void ProcNumberGetTransactionIds(ProcNumber procNumber, TransactionId *xid, TransactionId *xmin, int *nsubxid, bool *overflowed)
Definition procarray.c:3133
#define INVALID_PROC_NUMBER
Definition procnumber.h:26
int ProcNumber
Definition procnumber.h:24
Size mul_size(Size s1, Size s2)
Definition shmem.c:1063
#define ShmemRequestStruct(...)
Definition shmem.h:176
PGPROC * MyProc
Definition proc.c:71
PgBackendStatus backendStatus
Definition proc.h:179
uint32 wait_event_info
Definition proc.h:378
PgBackendGSSStatus * st_gssstatus
PgBackendSSLStatus * st_sslstatus
bool ssl_in_use
Definition libpq-be.h:208
char * remote_hostname
Definition libpq-be.h:136
void * gss
Definition libpq-be.h:202
SockAddr raddr
Definition libpq-be.h:134
ShmemRequestCallback request_fn
Definition shmem.h:133
bool superuser(void)
Definition superuser.c:47
const char * name
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition xact.c:881