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