Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd7e39d7

Browse files
committed
Use actual backend IDs in pg_stat_get_backend_idset() and friends.
Up to now, the ID values returned by pg_stat_get_backend_idset() andused by pg_stat_get_backend_activity() and allied functions were justindexes into a local array of sessions seen by the last stats refresh.This is problematic for a few reasons. The "ID" of a session can varyover its existence, which is surprising. Also, while these numbersoften match the "backend ID" used for purposes like temp schemaassignment, that isn't reliably true. We can fairly cheaply switchthings around to make these numbers actually be the sessions' backendIDs. The added test case illustrates that with this definition, thetemp schema used by a given session can be obtained given its PID.While here, delete some dead code that guarded against gettinga NULL return from pgstat_fetch_stat_local_beentry(). That can'thappen as long as the caller is careful to pass an in-range arrayindex, as all the callers are. (This code may not have been deadwhen written, but it surely is now.)Nathan BossartDiscussion:https://postgr.es/m/20220815205811.GA250990@nathanxps13
1 parentd5e3fe6 commitd7e39d7

File tree

6 files changed

+107
-51
lines changed

6 files changed

+107
-51
lines changed

‎doc/src/sgml/monitoring.sgml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5485,20 +5485,23 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
54855485
the <structname>pg_stat_activity</structname> view, returns a set of records
54865486
containing all the available information about each backend process.
54875487
Sometimes it may be more convenient to obtain just a subset of this
5488-
information. In such cases,an older set of per-backend statistics
5488+
information. In such cases,another set of per-backend statistics
54895489
access functions can be used; these are shown in <xref
54905490
linkend="monitoring-stats-backend-funcs-table"/>.
5491-
These access functions use a backend ID number, which ranges from one
5492-
to the number of currently active backends.
5491+
These access functions use the session's backend ID number, which is a
5492+
small positive integer that is distinct from the backend ID of any
5493+
concurrent session, although a session's ID can be recycled as soon as
5494+
it exits. The backend ID is used, among other things, to identify the
5495+
session's temporary schema if it has one.
54935496
The function <function>pg_stat_get_backend_idset</function> provides a
5494-
convenient way togenerate one row for each active backend for
5497+
convenient way tolist all the active backends' ID numbers for
54955498
invoking these functions. For example, to show the <acronym>PID</acronym>s and
54965499
current queries of all backends:
54975500

54985501
<programlisting>
5499-
SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
5500-
pg_stat_get_backend_activity(s.backendid) AS query
5501-
FROM(SELECTpg_stat_get_backend_idset() AS backendid) AS s;
5502+
SELECT pg_stat_get_backend_pid(backendid) AS pid,
5503+
pg_stat_get_backend_activity(backendid) AS query
5504+
FROM pg_stat_get_backend_idset() AS backendid;
55025505
</programlisting>
55035506
</para>
55045507

@@ -5526,8 +5529,7 @@ SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
55265529
<returnvalue>setof integer</returnvalue>
55275530
</para>
55285531
<para>
5529-
Returns the set of currently active backend ID numbers (from 1 to the
5530-
number of active backends).
5532+
Returns the set of currently active backend ID numbers.
55315533
</para></entry>
55325534
</row>
55335535

‎src/backend/utils/activity/backend_status.c

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,13 @@ pgstat_read_current_status(void)
846846
/* Only valid entries get included into the local array */
847847
if (localentry->backendStatus.st_procpid>0)
848848
{
849+
/*
850+
* The BackendStatusArray index is exactly the BackendId of the
851+
* source backend. Note that this means localBackendStatusTable
852+
* is in order by backend_id. pgstat_fetch_stat_beentry() depends
853+
* on that.
854+
*/
855+
localentry->backend_id=i;
849856
BackendIdGetTransactionIds(i,
850857
&localentry->backend_xid,
851858
&localentry->backend_xmin);
@@ -1045,26 +1052,57 @@ pgstat_get_my_query_id(void)
10451052
returnMyBEEntry->st_query_id;
10461053
}
10471054

1055+
/* ----------
1056+
* cmp_lbestatus
1057+
*
1058+
*Comparison function for bsearch() on an array of LocalPgBackendStatus.
1059+
*The backend_id field is used to compare the arguments.
1060+
* ----------
1061+
*/
1062+
staticint
1063+
cmp_lbestatus(constvoid*a,constvoid*b)
1064+
{
1065+
constLocalPgBackendStatus*lbestatus1= (constLocalPgBackendStatus*)a;
1066+
constLocalPgBackendStatus*lbestatus2= (constLocalPgBackendStatus*)b;
1067+
1068+
returnlbestatus1->backend_id-lbestatus2->backend_id;
1069+
}
10481070

10491071
/* ----------
10501072
* pgstat_fetch_stat_beentry() -
10511073
*
10521074
*Support function for the SQL-callable pgstat* functions. Returns
1053-
*our local copy of the current-activity entry for one backend.
1075+
*our local copy of the current-activity entry for one backend,
1076+
*or NULL if the given beid doesn't identify any known session.
1077+
*
1078+
*The beid argument is the BackendId of the desired session
1079+
*(note that this is unlike pgstat_fetch_stat_local_beentry()).
10541080
*
10551081
*NB: caller is responsible for a check if the user is permitted to see
10561082
*this info (especially the querystring).
10571083
* ----------
10581084
*/
10591085
PgBackendStatus*
1060-
pgstat_fetch_stat_beentry(intbeid)
1086+
pgstat_fetch_stat_beentry(BackendIdbeid)
10611087
{
1088+
LocalPgBackendStatuskey;
1089+
LocalPgBackendStatus*ret;
1090+
10621091
pgstat_read_current_status();
10631092

1064-
if (beid<1||beid>localNumBackends)
1065-
returnNULL;
1093+
/*
1094+
* Since the localBackendStatusTable is in order by backend_id, we can use
1095+
* bsearch() to search it efficiently.
1096+
*/
1097+
key.backend_id=beid;
1098+
ret= (LocalPgBackendStatus*)bsearch(&key,localBackendStatusTable,
1099+
localNumBackends,
1100+
sizeof(LocalPgBackendStatus),
1101+
cmp_lbestatus);
1102+
if (ret)
1103+
return&ret->backendStatus;
10661104

1067-
return&localBackendStatusTable[beid-1].backendStatus;
1105+
returnNULL;
10681106
}
10691107

10701108

@@ -1074,6 +1112,10 @@ pgstat_fetch_stat_beentry(int beid)
10741112
*Like pgstat_fetch_stat_beentry() but with locally computed additions (like
10751113
*xid and xmin values of the backend)
10761114
*
1115+
*The beid argument is a 1-based index in the localBackendStatusTable
1116+
*(note that this is unlike pgstat_fetch_stat_beentry()).
1117+
*Returns NULL if the argument is out of range (no current caller does that).
1118+
*
10771119
*NB: caller is responsible for a check if the user is permitted to see
10781120
*this info (especially the querystring).
10791121
* ----------
@@ -1094,7 +1136,8 @@ pgstat_fetch_stat_local_beentry(int beid)
10941136
* pgstat_fetch_stat_numbackends() -
10951137
*
10961138
*Support function for the SQL-callable pgstat* functions. Returns
1097-
*the maximum current backend id.
1139+
*the number of sessions known in the localBackendStatusTable, i.e.
1140+
*the maximum 1-based index to pass to pgstat_fetch_stat_local_beentry().
10981141
* ----------
10991142
*/
11001143
int

‎src/backend/utils/adt/pgstatfuncs.c

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,6 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
415415
{
416416
FuncCallContext*funcctx;
417417
int*fctx;
418-
int32result;
419418

420419
/* stuff done only on the first call of the function */
421420
if (SRF_IS_FIRSTCALL())
@@ -424,24 +423,33 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
424423
funcctx=SRF_FIRSTCALL_INIT();
425424

426425
fctx=MemoryContextAlloc(funcctx->multi_call_memory_ctx,
427-
2*sizeof(int));
426+
sizeof(int));
428427
funcctx->user_fctx=fctx;
429428

430429
fctx[0]=0;
431-
fctx[1]=pgstat_fetch_stat_numbackends();
432430
}
433431

434432
/* stuff done on every call of the function */
435433
funcctx=SRF_PERCALL_SETUP();
436434
fctx=funcctx->user_fctx;
437435

438436
fctx[0]+=1;
439-
result=fctx[0];
440437

441-
if (result <=fctx[1])
438+
/*
439+
* We recheck pgstat_fetch_stat_numbackends() each time through, just in
440+
* case the local status data has been refreshed since we started. It's
441+
* plenty cheap enough if not. If a refresh does happen, we'll likely
442+
* miss or duplicate some backend IDs, but we're content not to crash.
443+
* (Refreshing midway through such a query would be problematic usage
444+
* anyway, since the backend IDs we've already returned might no longer
445+
* refer to extant sessions.)
446+
*/
447+
if (fctx[0] <=pgstat_fetch_stat_numbackends())
442448
{
443449
/* do when there is more left to send */
444-
SRF_RETURN_NEXT(funcctx,Int32GetDatum(result));
450+
LocalPgBackendStatus*local_beentry=pgstat_fetch_stat_local_beentry(fctx[0]);
451+
452+
SRF_RETURN_NEXT(funcctx,Int32GetDatum(local_beentry->backend_id));
445453
}
446454
else
447455
{
@@ -493,17 +501,13 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS)
493501
inti;
494502

495503
local_beentry=pgstat_fetch_stat_local_beentry(curr_backend);
496-
497-
if (!local_beentry)
498-
continue;
499-
500504
beentry=&local_beentry->backendStatus;
501505

502506
/*
503507
* Report values for only those backends which are running the given
504508
* command.
505509
*/
506-
if (!beentry||beentry->st_progress_command!=cmdtype)
510+
if (beentry->st_progress_command!=cmdtype)
507511
continue;
508512

509513
/* Value available to all callers */
@@ -558,24 +562,6 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
558562

559563
/* Get the next one in the list */
560564
local_beentry=pgstat_fetch_stat_local_beentry(curr_backend);
561-
if (!local_beentry)
562-
{
563-
inti;
564-
565-
/* Ignore missing entries if looking for specific PID */
566-
if (pid!=-1)
567-
continue;
568-
569-
for (i=0;i<lengthof(nulls);i++)
570-
nulls[i]= true;
571-
572-
nulls[5]= false;
573-
values[5]=CStringGetTextDatum("<backend information not available>");
574-
575-
tuplestore_putvalues(rsinfo->setResult,rsinfo->setDesc,values,nulls);
576-
continue;
577-
}
578-
579565
beentry=&local_beentry->backendStatus;
580566

581567
/* If looking for specific PID, ignore all the others */
@@ -1180,9 +1166,9 @@ pg_stat_get_db_numbackends(PG_FUNCTION_ARGS)
11801166
result=0;
11811167
for (beid=1;beid <=tot_backends;beid++)
11821168
{
1183-
PgBackendStatus*beentry=pgstat_fetch_stat_beentry(beid);
1169+
LocalPgBackendStatus*local_beentry=pgstat_fetch_stat_local_beentry(beid);
11841170

1185-
if (beentry&&beentry->st_databaseid==dbid)
1171+
if (local_beentry->backendStatus.st_databaseid==dbid)
11861172
result++;
11871173
}
11881174

‎src/include/utils/backend_status.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include"datatype/timestamp.h"
1414
#include"libpq/pqcomm.h"
1515
#include"miscadmin.h"/* for BackendType */
16+
#include"storage/backendid.h"
1617
#include"utils/backend_progress.h"
1718

1819

@@ -247,6 +248,13 @@ typedef struct LocalPgBackendStatus
247248
*/
248249
PgBackendStatusbackendStatus;
249250

251+
/*
252+
* The backend ID. For auxiliary processes, this will be set to a value
253+
* greater than MaxBackends (since auxiliary processes do not have proper
254+
* backend IDs).
255+
*/
256+
BackendIdbackend_id;
257+
250258
/*
251259
* The xid of the current transaction if available, InvalidTransactionId
252260
* if not.
@@ -313,7 +321,7 @@ extern uint64 pgstat_get_my_query_id(void);
313321
* ----------
314322
*/
315323
externintpgstat_fetch_stat_numbackends(void);
316-
externPgBackendStatus*pgstat_fetch_stat_beentry(intbeid);
324+
externPgBackendStatus*pgstat_fetch_stat_beentry(BackendIdbeid);
317325
externLocalPgBackendStatus*pgstat_fetch_stat_local_beentry(intbeid);
318326
externchar*pgstat_clip_activity(constchar*raw_activity);
319327

‎src/test/regress/expected/stats.out

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,9 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
576576

577577
-- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
578578
SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
579-
-- Test pg_stat_wal
579+
-- Test pg_stat_wal (and make a temp table so our temp schema exists)
580580
SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
581-
CREATE TABLE test_stats_temp AS SELECT 17;
581+
CREATETEMPTABLE test_stats_temp AS SELECT 17;
582582
DROP TABLE test_stats_temp;
583583
-- Checkpoint twice: The checkpointer reports stats after reporting completion
584584
-- of the checkpoint. But after a second checkpoint we'll see at least the
@@ -597,6 +597,17 @@ SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
597597
t
598598
(1 row)
599599

600+
-- Test pg_stat_get_backend_idset() and some allied functions.
601+
-- In particular, verify that their notion of backend ID matches
602+
-- our temp schema index.
603+
SELECT (current_schemas(true))[1] = ('pg_temp_' || beid::text) AS match
604+
FROM pg_stat_get_backend_idset() beid
605+
WHERE pg_stat_get_backend_pid(beid) = pg_backend_pid();
606+
match
607+
-------
608+
t
609+
(1 row)
610+
600611
-----
601612
-- Test that resetting stats works for reset timestamp
602613
-----

‎src/test/regress/sql/stats.sql

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,10 +303,10 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
303303
-- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
304304
SELECT checkpoints_reqAS rqst_ckpts_beforeFROM pg_stat_bgwriter \gset
305305

306-
-- Test pg_stat_wal
306+
-- Test pg_stat_wal (and make a temp table so our temp schema exists)
307307
SELECT wal_bytesAS wal_bytes_beforeFROM pg_stat_wal \gset
308308

309-
CREATETABLEtest_stats_tempASSELECT17;
309+
CREATETEMPTABLE test_stats_tempASSELECT17;
310310
DROPTABLE test_stats_temp;
311311

312312
-- Checkpoint twice: The checkpointer reports stats after reporting completion
@@ -318,6 +318,12 @@ CHECKPOINT;
318318
SELECT checkpoints_req> :rqst_ckpts_beforeFROM pg_stat_bgwriter;
319319
SELECT wal_bytes> :wal_bytes_beforeFROM pg_stat_wal;
320320

321+
-- Test pg_stat_get_backend_idset() and some allied functions.
322+
-- In particular, verify that their notion of backend ID matches
323+
-- our temp schema index.
324+
SELECT (current_schemas(true))[1]= ('pg_temp_'|| beid::text)AS match
325+
FROM pg_stat_get_backend_idset() beid
326+
WHERE pg_stat_get_backend_pid(beid)= pg_backend_pid();
321327

322328
-----
323329
-- Test that resetting stats works for reset timestamp

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp