1 /* ----------
2 * backend_status.c
3 * Backend status reporting infrastructure.
4 *
5 * Copyright (c) 2001-2021, PostgreSQL Global Development Group
6 *
7 *
8 * IDENTIFICATION
9 * src/backend/postmaster/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 */
45 bool pgstat_track_activities = false;
46 int pgstat_track_activity_query_size = 1024;
47
48
49 /* exposed so that backend_progress.c can access it */
50 PgBackendStatus *MyBEEntry = NULL;
51
52
53 static PgBackendStatus *BackendStatusArray = NULL;
54 static char *BackendAppnameBuffer = NULL;
55 static char *BackendClientHostnameBuffer = NULL;
56 static char *BackendActivityBuffer = NULL;
57 static Size BackendActivityBufferSize = 0;
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 */
67 static LocalPgBackendStatus *localBackendStatusTable = NULL;
68
69 /* Total number of backends including auxiliary */
70 static int localNumBackends = 0;
71
72 static MemoryContext backendStatusSnapContext;
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
BackendStatusShmemSize(void)84 BackendStatusShmemSize(void)
85 {
86 Size size;
87
88 /* BackendStatusArray: */
89 size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
90 /* BackendAppnameBuffer: */
91 size = add_size(size,
92 mul_size(NAMEDATALEN, NumBackendStatSlots));
93 /* BackendClientHostnameBuffer: */
94 size = add_size(size,
95 mul_size(NAMEDATALEN, NumBackendStatSlots));
96 /* BackendActivityBuffer: */
97 size = add_size(size,
98 mul_size(pgstat_track_activity_query_size, NumBackendStatSlots));
99 #ifdef USE_SSL
100 /* BackendSslStatusBuffer: */
101 size = add_size(size,
102 mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots));
103 #endif
104 #ifdef ENABLE_GSS
105 /* BackendGssStatusBuffer: */
106 size = add_size(size,
107 mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots));
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
CreateSharedBackendStatus(void)117 CreateSharedBackendStatus(void)
118 {
119 Size size;
120 bool found;
121 int i;
122 char *buffer;
123
124 /* Create or attach to the shared array */
125 size = mul_size(sizeof(PgBackendStatus), NumBackendStatSlots);
126 BackendStatusArray = (PgBackendStatus *)
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 */
138 size = mul_size(NAMEDATALEN, NumBackendStatSlots);
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 */
156 size = mul_size(NAMEDATALEN, NumBackendStatSlots);
157 BackendClientHostnameBuffer = (char *)
158 ShmemInitStruct("Backend Client Host Name Buffer", size, &found);
159
160 if (!found)
161 {
162 MemSet(BackendClientHostnameBuffer, 0, size);
163
164 /* Initialize st_clienthostname pointers. */
165 buffer = BackendClientHostnameBuffer;
166 for (i = 0; i < NumBackendStatSlots; i++)
167 {
168 BackendStatusArray[i].st_clienthostname = buffer;
169 buffer += NAMEDATALEN;
170 }
171 }
172
173 /* Create or attach to the shared activity buffer */
174 BackendActivityBufferSize = mul_size(pgstat_track_activity_query_size,
175 NumBackendStatSlots);
176 BackendActivityBuffer = (char *)
177 ShmemInitStruct("Backend Activity Buffer",
178 BackendActivityBufferSize,
179 &found);
180
181 if (!found)
182 {
183 MemSet(BackendActivityBuffer, 0, BackendActivityBufferSize);
184
185 /* Initialize st_activity pointers. */
186 buffer = BackendActivityBuffer;
187 for (i = 0; i < NumBackendStatSlots; i++)
188 {
189 BackendStatusArray[i].st_activity_raw = buffer;
190 buffer += pgstat_track_activity_query_size;
191 }
192 }
193
194 #ifdef USE_SSL
195 /* Create or attach to the shared SSL status buffer */
196 size = mul_size(sizeof(PgBackendSSLStatus), NumBackendStatSlots);
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 {
210 BackendStatusArray[i].st_sslstatus = ptr;
211 ptr++;
212 }
213 }
214 #endif
215
216 #ifdef ENABLE_GSS
217 /* Create or attach to the shared GSSAPI status buffer */
218 size = mul_size(sizeof(PgBackendGSSStatus), NumBackendStatSlots);
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 {
232 BackendStatusArray[i].st_gssstatus = ptr;
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
pgstat_beinit(void)249 pgstat_beinit(void)
250 {
251 /* Initialize MyBEEntry */
252 if (MyBackendId != InvalidBackendId)
253 {
254 Assert(MyBackendId >= 1 && MyBackendId <= MaxBackends);
255 MyBEEntry = &BackendStatusArray[MyBackendId - 1];
256 }
257 else
258 {
259 /* Must be an auxiliary process */
260 Assert(MyAuxProcType != NotAnAuxProcess);
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 1 to MaxBackends (inclusive), so we use
267 * MaxBackends + AuxBackendType + 1 as the index of the slot for an
268 * auxiliary process.
269 */
270 MyBEEntry = &BackendStatusArray[MaxBackends + MyAuxProcType];
271 }
272
273 /* Set up a process-exit hook to clean up */
274 on_shmem_exit(pgstat_beshutdown_hook, 0);
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 pgbestat_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
pgstat_bestart(void)292 pgstat_bestart(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;
335 lbeentry.st_proc_start_timestamp = MyStartTimestamp;
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
361 if (MyProcPort && MyProcPort->ssl_in_use)
362 {
363 lbeentry.st_ssl = true;
364 lsslstatus.ssl_bits = be_tls_get_cipher_bits(MyProcPort);
365 strlcpy(lsslstatus.ssl_version, be_tls_get_version(MyProcPort), NAMEDATALEN);
366 strlcpy(lsslstatus.ssl_cipher, be_tls_get_cipher(MyProcPort), NAMEDATALEN);
367 be_tls_get_peer_subject_name(MyProcPort, lsslstatus.ssl_client_dn, NAMEDATALEN);
368 be_tls_get_peer_serial(MyProcPort, lsslstatus.ssl_client_serial, NAMEDATALEN);
369 be_tls_get_peer_issuer_name(MyProcPort, lsslstatus.ssl_issuer_dn, NAMEDATALEN);
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);
387 if (princ)
388 strlcpy(lgssstatus.gss_princ, princ, NAMEDATALEN);
389 }
390 else
391 {
392 lbeentry.st_gss = false;
393 }
394 #else
395 lbeentry.st_gss = false;
396 #endif
397
398 lbeentry.st_state = STATE_UNDEFINED;
399 lbeentry.st_progress_command = PROGRESS_COMMAND_INVALID;
400 lbeentry.st_progress_command_target = InvalidOid;
401 lbeentry.st_query_id = UINT64CONST(0);
402
403 /*
404 * we don't zero st_progress_param here to save cycles; nobody should
405 * examine it until st_progress_command has been set to something other
406 * than PROGRESS_COMMAND_INVALID
407 */
408
409 /*
410 * We're ready to enter the critical section that fills the shared-memory
411 * status entry. We follow the protocol of bumping st_changecount before
412 * and after; and make sure it's even afterwards. We use a volatile
413 * pointer here to ensure the compiler doesn't try to get cute.
414 */
415 PGSTAT_BEGIN_WRITE_ACTIVITY(vbeentry);
416
417 /* make sure we'll memcpy the same st_changecount back */
418 lbeentry.st_changecount = vbeentry->st_changecount;
419
420 memcpy(unvolatize(PgBackendStatus *, vbeentry),
421 &lbeentry,
422 sizeof(PgBackendStatus));
423
424 /*
425 * We can write the out-of-line strings and structs using the pointers
426 * that are in lbeentry; this saves some de-volatilizing messiness.
427 */
428 lbeentry.st_appname[0] = '\0';
429 if (MyProcPort && MyProcPort->remote_hostname)
430 strlcpy(lbeentry.st_clienthostname, MyProcPort->remote_hostname,
431 NAMEDATALEN);
432 else
433 lbeentry.st_clienthostname[0] = '\0';
434 lbeentry.st_activity_raw[0] = '\0';
435 /* Also make sure the last byte in each string area is always 0 */
436 lbeentry.st_appname[NAMEDATALEN - 1] = '\0';
437 lbeentry.st_clienthostname[NAMEDATALEN - 1] = '\0';
438 lbeentry.st_activity_raw[pgstat_track_activity_query_size - 1] = '\0';
439
440 #ifdef USE_SSL
441 memcpy(lbeentry.st_sslstatus, &lsslstatus, sizeof(PgBackendSSLStatus));
442 #endif
443 #ifdef ENABLE_GSS
444 memcpy(lbeentry.st_gssstatus, &lgssstatus, sizeof(PgBackendGSSStatus));
445 #endif
446
447 PGSTAT_END_WRITE_ACTIVITY(vbeentry);
448
449 /* Update app name to current GUC setting */
450 if (application_name)
451 pgstat_report_appname(application_name);
452 }
453
454 /*
455 * Clear out our entry in the PgBackendStatus array.
456 */
457 static void
pgstat_beshutdown_hook(int code,Datum arg)458 pgstat_beshutdown_hook(int code, Datum arg)
459 {
460 volatile PgBackendStatus *beentry = MyBEEntry;
461
462 /*
463 * Clear my status entry, following the protocol of bumping st_changecount
464 * before and after. We use a volatile pointer here to ensure the
465 * compiler doesn't try to get cute.
466 */
467 PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
468
469 beentry->st_procpid = 0; /* mark invalid */
470
471 PGSTAT_END_WRITE_ACTIVITY(beentry);
472
473 /* so that functions can check if backend_status.c is up via MyBEEntry */
474 MyBEEntry = NULL;
475 }
476
477 /*
478 * Discard any data collected in the current transaction. Any subsequent
479 * request will cause new snapshots to be read.
480 *
481 * This is also invoked during transaction commit or abort to discard the
482 * no-longer-wanted snapshot.
483 */
484 void
pgstat_clear_backend_activity_snapshot(void)485 pgstat_clear_backend_activity_snapshot(void)
486 {
487 /* Release memory, if any was allocated */
488 if (backendStatusSnapContext)
489 {
490 MemoryContextDelete(backendStatusSnapContext);
491 backendStatusSnapContext = NULL;
492 }
493
494 /* Reset variables */
495 localBackendStatusTable = NULL;
496 localNumBackends = 0;
497 }
498
499 static void
pgstat_setup_backend_status_context(void)500 pgstat_setup_backend_status_context(void)
501 {
502 if (!backendStatusSnapContext)
503 backendStatusSnapContext = AllocSetContextCreate(TopMemoryContext,
504 "Backend Status Snapshot",
505 ALLOCSET_SMALL_SIZES);
506 }
507
508
509 /* ----------
510 * pgstat_report_activity() -
511 *
512 * Called from tcop/postgres.c to report what the backend is actually doing
513 * (but note cmd_str can be NULL for certain cases).
514 *
515 * All updates of the status entry follow the protocol of bumping
516 * st_changecount before and after. We use a volatile pointer here to
517 * ensure the compiler doesn't try to get cute.
518 * ----------
519 */
520 void
pgstat_report_activity(BackendState state,const char * cmd_str)521 pgstat_report_activity(BackendState state, const char *cmd_str)
522 {
523 volatile PgBackendStatus *beentry = MyBEEntry;
524 TimestampTz start_timestamp;
525 TimestampTz current_timestamp;
526 int len = 0;
527
528 TRACE_POSTGRESQL_STATEMENT_STATUS(cmd_str);
529
530 if (!beentry)
531 return;
532
533 if (!pgstat_track_activities)
534 {
535 if (beentry->st_state != STATE_DISABLED)
536 {
537 volatile PGPROC *proc = MyProc;
538
539 /*
540 * track_activities is disabled, but we last reported a
541 * non-disabled state. As our final update, change the state and
542 * clear fields we will not be updating anymore.
543 */
544 PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
545 beentry->st_state = STATE_DISABLED;
546 beentry->st_state_start_timestamp = 0;
547 beentry->st_activity_raw[0] = '\0';
548 beentry->st_activity_start_timestamp = 0;
549 /* st_xact_start_timestamp and wait_event_info are also disabled */
550 beentry->st_xact_start_timestamp = 0;
551 beentry->st_query_id = UINT64CONST(0);
552 proc->wait_event_info = 0;
553 PGSTAT_END_WRITE_ACTIVITY(beentry);
554 }
555 return;
556 }
557
558 /*
559 * To minimize the time spent modifying the entry, and avoid risk of
560 * errors inside the critical section, fetch all the needed data first.
561 */
562 start_timestamp = GetCurrentStatementStartTimestamp();
563 if (cmd_str != NULL)
564 {
565 /*
566 * Compute length of to-be-stored string unaware of multi-byte
567 * characters. For speed reasons that'll get corrected on read, rather
568 * than computed every write.
569 */
570 len = Min(strlen(cmd_str), pgstat_track_activity_query_size - 1);
571 }
572 current_timestamp = GetCurrentTimestamp();
573
574 /*
575 * If the state has changed from "active" or "idle in transaction",
576 * calculate the duration.
577 */
578 if ((beentry->st_state == STATE_RUNNING ||
579 beentry->st_state == STATE_FASTPATH ||
580 beentry->st_state == STATE_IDLEINTRANSACTION ||
581 beentry->st_state == STATE_IDLEINTRANSACTION_ABORTED) &&
582 state != beentry->st_state)
583 {
584 long secs;
585 int usecs;
586
587 TimestampDifference(beentry->st_state_start_timestamp,
588 current_timestamp,
589 &secs, &usecs);
590
591 if (beentry->st_state == STATE_RUNNING ||
592 beentry->st_state == STATE_FASTPATH)
593 pgstat_count_conn_active_time((PgStat_Counter) secs * 1000000 + usecs);
594 else
595 pgstat_count_conn_txn_idle_time((PgStat_Counter) secs * 1000000 + usecs);
596 }
597
598 /*
599 * Now update the status entry
600 */
601 PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
602
603 beentry->st_state = state;
604 beentry->st_state_start_timestamp = current_timestamp;
605
606 /*
607 * If a new query is started, we reset the query identifier as it'll only
608 * be known after parse analysis, to avoid reporting last query's
609 * identifier.
610 */
611 if (state == STATE_RUNNING)
612 beentry->st_query_id = UINT64CONST(0);
613
614 if (cmd_str != NULL)
615 {
616 memcpy((char *) beentry->st_activity_raw, cmd_str, len);
617 beentry->st_activity_raw[len] = '\0';
618 beentry->st_activity_start_timestamp = start_timestamp;
619 }
620
621 PGSTAT_END_WRITE_ACTIVITY(beentry);
622 }
623
624 /* --------
625 * pgstat_report_query_id() -
626 *
627 * Called to update top-level query identifier.
628 * --------
629 */
630 void
pgstat_report_query_id(uint64 query_id,bool force)631 pgstat_report_query_id(uint64 query_id, bool force)
632 {
633 volatile PgBackendStatus *beentry = MyBEEntry;
634
635 /*
636 * if track_activities is disabled, st_query_id should already have been
637 * reset
638 */
639 if (!beentry || !pgstat_track_activities)
640 return;
641
642 /*
643 * We only report the top-level query identifiers. The stored query_id is
644 * reset when a backend calls pgstat_report_activity(STATE_RUNNING), or
645 * with an explicit call to this function using the force flag. If the
646 * saved query identifier is not zero it means that it's not a top-level
647 * command, so ignore the one provided unless it's an explicit call to
648 * reset the identifier.
649 */
650 if (beentry->st_query_id != 0 && !force)
651 return;
652
653 /*
654 * Update my status entry, following the protocol of bumping
655 * st_changecount before and after. We use a volatile pointer here to
656 * ensure the compiler doesn't try to get cute.
657 */
658 PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
659 beentry->st_query_id = query_id;
660 PGSTAT_END_WRITE_ACTIVITY(beentry);
661 }
662
663
664 /* ----------
665 * pgstat_report_appname() -
666 *
667 * Called to update our application name.
668 * ----------
669 */
670 void
pgstat_report_appname(const char * appname)671 pgstat_report_appname(const char *appname)
672 {
673 volatile PgBackendStatus *beentry = MyBEEntry;
674 int len;
675
676 if (!beentry)
677 return;
678
679 /* This should be unnecessary if GUC did its job, but be safe */
680 len = pg_mbcliplen(appname, strlen(appname), NAMEDATALEN - 1);
681
682 /*
683 * Update my status entry, following the protocol of bumping
684 * st_changecount before and after. We use a volatile pointer here to
685 * ensure the compiler doesn't try to get cute.
686 */
687 PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
688
689 memcpy((char *) beentry->st_appname, appname, len);
690 beentry->st_appname[len] = '\0';
691
692 PGSTAT_END_WRITE_ACTIVITY(beentry);
693 }
694
695 /*
696 * Report current transaction start timestamp as the specified value.
697 * Zero means there is no active transaction.
698 */
699 void
pgstat_report_xact_timestamp(TimestampTz tstamp)700 pgstat_report_xact_timestamp(TimestampTz tstamp)
701 {
702 volatile PgBackendStatus *beentry = MyBEEntry;
703
704 if (!pgstat_track_activities || !beentry)
705 return;
706
707 /*
708 * Update my status entry, following the protocol of bumping
709 * st_changecount before and after. We use a volatile pointer here to
710 * ensure the compiler doesn't try to get cute.
711 */
712 PGSTAT_BEGIN_WRITE_ACTIVITY(beentry);
713
714 beentry->st_xact_start_timestamp = tstamp;
715
716 PGSTAT_END_WRITE_ACTIVITY(beentry);
717 }
718
719 /* ----------
720 * pgstat_read_current_status() -
721 *
722 * Copy the current contents of the PgBackendStatus array to local memory,
723 * if not already done in this transaction.
724 * ----------
725 */
726 static void
pgstat_read_current_status(void)727 pgstat_read_current_status(void)
728 {
729 volatile PgBackendStatus *beentry;
730 LocalPgBackendStatus *localtable;
731 LocalPgBackendStatus *localentry;
732 char *localappname,
733 *localclienthostname,
734 *localactivity;
735 #ifdef USE_SSL
736 PgBackendSSLStatus *localsslstatus;
737 #endif
738 #ifdef ENABLE_GSS
739 PgBackendGSSStatus *localgssstatus;
740 #endif
741 int i;
742
743 if (localBackendStatusTable)
744 return; /* already done */
745
746 pgstat_setup_backend_status_context();
747
748 /*
749 * Allocate storage for local copy of state data. We can presume that
750 * none of these requests overflow size_t, because we already calculated
751 * the same values using mul_size during shmem setup. However, with
752 * probably-silly values of pgstat_track_activity_query_size and
753 * max_connections, the localactivity buffer could exceed 1GB, so use
754 * "huge" allocation for that one.
755 */
756 localtable = (LocalPgBackendStatus *)
757 MemoryContextAlloc(backendStatusSnapContext,
758 sizeof(LocalPgBackendStatus) * NumBackendStatSlots);
759 localappname = (char *)
760 MemoryContextAlloc(backendStatusSnapContext,
761 NAMEDATALEN * NumBackendStatSlots);
762 localclienthostname = (char *)
763 MemoryContextAlloc(backendStatusSnapContext,
764 NAMEDATALEN * NumBackendStatSlots);
765 localactivity = (char *)
766 MemoryContextAllocHuge(backendStatusSnapContext,
767 pgstat_track_activity_query_size * NumBackendStatSlots);
768 #ifdef USE_SSL
769 localsslstatus = (PgBackendSSLStatus *)
770 MemoryContextAlloc(backendStatusSnapContext,
771 sizeof(PgBackendSSLStatus) * NumBackendStatSlots);
772 #endif
773 #ifdef ENABLE_GSS
774 localgssstatus = (PgBackendGSSStatus *)
775 MemoryContextAlloc(backendStatusSnapContext,
776 sizeof(PgBackendGSSStatus) * NumBackendStatSlots);
777 #endif
778
779 localNumBackends = 0;
780
781 beentry = BackendStatusArray;
782 localentry = localtable;
783 for (i = 1; i <= NumBackendStatSlots; i++)
784 {
785 /*
786 * Follow the protocol of retrying if st_changecount changes while we
787 * copy the entry, or if it's odd. (The check for odd is needed to
788 * cover the case where we are able to completely copy the entry while
789 * the source backend is between increment steps.) We use a volatile
790 * pointer here to ensure the compiler doesn't try to get cute.
791 */
792 for (;;)
793 {
794 int before_changecount;
795 int after_changecount;
796
797 pgstat_begin_read_activity(beentry, before_changecount);
798
799 localentry->backendStatus.st_procpid = beentry->st_procpid;
800 /* Skip all the data-copying work if entry is not in use */
801 if (localentry->backendStatus.st_procpid > 0)
802 {
803 memcpy(&localentry->backendStatus, unvolatize(PgBackendStatus *, beentry), sizeof(PgBackendStatus));
804
805 /*
806 * For each PgBackendStatus field that is a pointer, copy the
807 * pointed-to data, then adjust the local copy of the pointer
808 * field to point at the local copy of the data.
809 *
810 * strcpy is safe even if the string is modified concurrently,
811 * because there's always a \0 at the end of the buffer.
812 */
813 strcpy(localappname, (char *) beentry->st_appname);
814 localentry->backendStatus.st_appname = localappname;
815 strcpy(localclienthostname, (char *) beentry->st_clienthostname);
816 localentry->backendStatus.st_clienthostname = localclienthostname;
817 strcpy(localactivity, (char *) beentry->st_activity_raw);
818 localentry->backendStatus.st_activity_raw = localactivity;
819 #ifdef USE_SSL
820 if (beentry->st_ssl)
821 {
822 memcpy(localsslstatus, beentry->st_sslstatus, sizeof(PgBackendSSLStatus));
823 localentry->backendStatus.st_sslstatus = localsslstatus;
824 }
825 #endif
826 #ifdef ENABLE_GSS
827 if (beentry->st_gss)
828 {
829 memcpy(localgssstatus, beentry->st_gssstatus, sizeof(PgBackendGSSStatus));
830 localentry->backendStatus.st_gssstatus = localgssstatus;
831 }
832 #endif
833 }
834
835 pgstat_end_read_activity(beentry, after_changecount);
836
837 if (pgstat_read_activity_complete(before_changecount,
838 after_changecount))
839 break;
840
841 /* Make sure we can break out of loop if stuck... */
842 CHECK_FOR_INTERRUPTS();
843 }
844
845 beentry++;
846 /* Only valid entries get included into the local array */
847 if (localentry->backendStatus.st_procpid > 0)
848 {
849 BackendIdGetTransactionIds(i,
850 &localentry->backend_xid,
851 &localentry->backend_xmin);
852
853 localentry++;
854 localappname += NAMEDATALEN;
855 localclienthostname += NAMEDATALEN;
856 localactivity += pgstat_track_activity_query_size;
857 #ifdef USE_SSL
858 localsslstatus++;
859 #endif
860 #ifdef ENABLE_GSS
861 localgssstatus++;
862 #endif
863 localNumBackends++;
864 }
865 }
866
867 /* Set the pointer only after completion of a valid table */
868 localBackendStatusTable = localtable;
869 }
870
871
872 /* ----------
873 * pgstat_get_backend_current_activity() -
874 *
875 * Return a string representing the current activity of the backend with
876 * the specified PID. This looks directly at the BackendStatusArray,
877 * and so will provide current information regardless of the age of our
878 * transaction's snapshot of the status array.
879 *
880 * It is the caller's responsibility to invoke this only for backends whose
881 * state is expected to remain stable while the result is in use. The
882 * only current use is in deadlock reporting, where we can expect that
883 * the target backend is blocked on a lock. (There are corner cases
884 * where the target's wait could get aborted while we are looking at it,
885 * but the very worst consequence is to return a pointer to a string
886 * that's been changed, so we won't worry too much.)
887 *
888 * Note: return strings for special cases match pg_stat_get_backend_activity.
889 * ----------
890 */
891 const char *
pgstat_get_backend_current_activity(int pid,bool checkUser)892 pgstat_get_backend_current_activity(int pid, bool checkUser)
893 {
894 PgBackendStatus *beentry;
895 int i;
896
897 beentry = BackendStatusArray;
898 for (i = 1; i <= MaxBackends; i++)
899 {
900 /*
901 * Although we expect the target backend's entry to be stable, that
902 * doesn't imply that anyone else's is. To avoid identifying the
903 * wrong backend, while we check for a match to the desired PID we
904 * must follow the protocol of retrying if st_changecount changes
905 * while we examine the entry, or if it's odd. (This might be
906 * unnecessary, since fetching or storing an int is almost certainly
907 * atomic, but let's play it safe.) We use a volatile pointer here to
908 * ensure the compiler doesn't try to get cute.
909 */
910 volatile PgBackendStatus *vbeentry = beentry;
911 bool found;
912
913 for (;;)
914 {
915 int before_changecount;
916 int after_changecount;
917
918 pgstat_begin_read_activity(vbeentry, before_changecount);
919
920 found = (vbeentry->st_procpid == pid);
921
922 pgstat_end_read_activity(vbeentry, after_changecount);
923
924 if (pgstat_read_activity_complete(before_changecount,
925 after_changecount))
926 break;
927
928 /* Make sure we can break out of loop if stuck... */
929 CHECK_FOR_INTERRUPTS();
930 }
931
932 if (found)
933 {
934 /* Now it is safe to use the non-volatile pointer */
935 if (checkUser && !superuser() && beentry->st_userid != GetUserId())
936 return "<insufficient privilege>";
937 else if (*(beentry->st_activity_raw) == '\0')
938 return "<command string not enabled>";
939 else
940 {
941 /* this'll leak a bit of memory, but that seems acceptable */
942 return pgstat_clip_activity(beentry->st_activity_raw);
943 }
944 }
945
946 beentry++;
947 }
948
949 /* If we get here, caller is in error ... */
950 return "<backend information not available>";
951 }
952
953 /* ----------
954 * pgstat_get_crashed_backend_activity() -
955 *
956 * Return a string representing the current activity of the backend with
957 * the specified PID. Like the function above, but reads shared memory with
958 * the expectation that it may be corrupt. On success, copy the string
959 * into the "buffer" argument and return that pointer. On failure,
960 * return NULL.
961 *
962 * This function is only intended to be used by the postmaster to report the
963 * query that crashed a backend. In particular, no attempt is made to
964 * follow the correct concurrency protocol when accessing the
965 * BackendStatusArray. But that's OK, in the worst case we'll return a
966 * corrupted message. We also must take care not to trip on ereport(ERROR).
967 * ----------
968 */
969 const char *
pgstat_get_crashed_backend_activity(int pid,char * buffer,int buflen)970 pgstat_get_crashed_backend_activity(int pid, char *buffer, int buflen)
971 {
972 volatile PgBackendStatus *beentry;
973 int i;
974
975 beentry = BackendStatusArray;
976
977 /*
978 * We probably shouldn't get here before shared memory has been set up,
979 * but be safe.
980 */
981 if (beentry == NULL || BackendActivityBuffer == NULL)
982 return NULL;
983
984 for (i = 1; i <= MaxBackends; i++)
985 {
986 if (beentry->st_procpid == pid)
987 {
988 /* Read pointer just once, so it can't change after validation */
989 const char *activity = beentry->st_activity_raw;
990 const char *activity_last;
991
992 /*
993 * We mustn't access activity string before we verify that it
994 * falls within the BackendActivityBuffer. To make sure that the
995 * entire string including its ending is contained within the
996 * buffer, subtract one activity length from the buffer size.
997 */
998 activity_last = BackendActivityBuffer + BackendActivityBufferSize
999 - pgstat_track_activity_query_size;
1000
1001 if (activity < BackendActivityBuffer ||
1002 activity > activity_last)
1003 return NULL;
1004
1005 /* If no string available, no point in a report */
1006 if (activity[0] == '\0')
1007 return NULL;
1008
1009 /*
1010 * Copy only ASCII-safe characters so we don't run into encoding
1011 * problems when reporting the message; and be sure not to run off
1012 * the end of memory. As only ASCII characters are reported, it
1013 * doesn't seem necessary to perform multibyte aware clipping.
1014 */
1015 ascii_safe_strlcpy(buffer, activity,
1016 Min(buflen, pgstat_track_activity_query_size));
1017
1018 return buffer;
1019 }
1020
1021 beentry++;
1022 }
1023
1024 /* PID not found */
1025 return NULL;
1026 }
1027
1028 /* ----------
1029 * pgstat_get_my_query_id() -
1030 *
1031 * Return current backend's query identifier.
1032 */
1033 uint64
pgstat_get_my_query_id(void)1034 pgstat_get_my_query_id(void)
1035 {
1036 if (!MyBEEntry)
1037 return 0;
1038
1039 /*
1040 * There's no need for a lock around pgstat_begin_read_activity /
1041 * pgstat_end_read_activity here as it's only called from
1042 * pg_stat_get_activity which is already protected, or from the same
1043 * backend which means that there won't be concurrent writes.
1044 */
1045 return MyBEEntry->st_query_id;
1046 }
1047
1048
1049 /* ----------
1050 * pgstat_fetch_stat_beentry() -
1051 *
1052 * Support function for the SQL-callable pgstat* functions. Returns
1053 * our local copy of the current-activity entry for one backend.
1054 *
1055 * NB: caller is responsible for a check if the user is permitted to see
1056 * this info (especially the querystring).
1057 * ----------
1058 */
1059 PgBackendStatus *
pgstat_fetch_stat_beentry(int beid)1060 pgstat_fetch_stat_beentry(int beid)
1061 {
1062 pgstat_read_current_status();
1063
1064 if (beid < 1 || beid > localNumBackends)
1065 return NULL;
1066
1067 return &localBackendStatusTable[beid - 1].backendStatus;
1068 }
1069
1070
1071 /* ----------
1072 * pgstat_fetch_stat_local_beentry() -
1073 *
1074 * Like pgstat_fetch_stat_beentry() but with locally computed additions (like
1075 * xid and xmin values of the backend)
1076 *
1077 * NB: caller is responsible for a check if the user is permitted to see
1078 * this info (especially the querystring).
1079 * ----------
1080 */
1081 LocalPgBackendStatus *
pgstat_fetch_stat_local_beentry(int beid)1082 pgstat_fetch_stat_local_beentry(int beid)
1083 {
1084 pgstat_read_current_status();
1085
1086 if (beid < 1 || beid > localNumBackends)
1087 return NULL;
1088
1089 return &localBackendStatusTable[beid - 1];
1090 }
1091
1092
1093 /* ----------
1094 * pgstat_fetch_stat_numbackends() -
1095 *
1096 * Support function for the SQL-callable pgstat* functions. Returns
1097 * the maximum current backend id.
1098 * ----------
1099 */
1100 int
pgstat_fetch_stat_numbackends(void)1101 pgstat_fetch_stat_numbackends(void)
1102 {
1103 pgstat_read_current_status();
1104
1105 return localNumBackends;
1106 }
1107
1108 /*
1109 * Convert a potentially unsafely truncated activity string (see
1110 * PgBackendStatus.st_activity_raw's documentation) into a correctly truncated
1111 * one.
1112 *
1113 * The returned string is allocated in the caller's memory context and may be
1114 * freed.
1115 */
1116 char *
pgstat_clip_activity(const char * raw_activity)1117 pgstat_clip_activity(const char *raw_activity)
1118 {
1119 char *activity;
1120 int rawlen;
1121 int cliplen;
1122
1123 /*
1124 * Some callers, like pgstat_get_backend_current_activity(), do not
1125 * guarantee that the buffer isn't concurrently modified. We try to take
1126 * care that the buffer is always terminated by a NUL byte regardless, but
1127 * let's still be paranoid about the string's length. In those cases the
1128 * underlying buffer is guaranteed to be pgstat_track_activity_query_size
1129 * large.
1130 */
1131 activity = pnstrdup(raw_activity, pgstat_track_activity_query_size - 1);
1132
1133 /* now double-guaranteed to be NUL terminated */
1134 rawlen = strlen(activity);
1135
1136 /*
1137 * All supported server-encodings make it possible to determine the length
1138 * of a multi-byte character from its first byte (this is not the case for
1139 * client encodings, see GB18030). As st_activity is always stored using
1140 * server encoding, this allows us to perform multi-byte aware truncation,
1141 * even if the string earlier was truncated in the middle of a multi-byte
1142 * character.
1143 */
1144 cliplen = pg_mbcliplen(activity, rawlen,
1145 pgstat_track_activity_query_size - 1);
1146
1147 activity[cliplen] = '\0';
1148
1149 return activity;
1150 }
1151