Skip to content

Commit 6cd4efa

Browse files
Oleg TselebrovskiyMedvecrab
authored andcommitted
Add profile_extended and history_extended views with additional dimensions
Sometimes it can be useful to have additional info collected with wait_events, so we add two new views/functions that include more information. The structure of those views could be changed in new versions of pg_wait_sampling extension
1 parent 8427f4a commit 6cd4efa

File tree

9 files changed

+1067
-23
lines changed

9 files changed

+1067
-23
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ MODULE_big = pg_wait_sampling
44
OBJS = pg_wait_sampling.o collector.o
55

66
EXTENSION = pg_wait_sampling
7-
DATA = pg_wait_sampling--1.1.sql pg_wait_sampling--1.0--1.1.sql
7+
DATA = pg_wait_sampling--1.1.sql pg_wait_sampling--1.0--1.1.sql pg_wait_sampling--1.1--1.2.sql
88

99
REGRESS = load queries
1010

collector.c

Lines changed: 106 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "postgres.h"
1111

1212
#include <signal.h>
13+
#include <time.h>
1314

1415
#include "compat.h"
1516
#include "miscadmin.h"
@@ -30,6 +31,13 @@
3031
#include "utils/resowner.h"
3132
#include "utils/timestamp.h"
3233

34+
#define check_bestatus_dimensions(dimensions) \
35+
(dimensions & (PGWS_DIMENSIONS_BE_TYPE |\
36+
PGWS_DIMENSIONS_BE_STATE |\
37+
PGWS_DIMENSIONS_BE_START_TIME |\
38+
PGWS_DIMENSIONS_CLIENT_ADDR |\
39+
PGWS_DIMENSIONS_CLIENT_HOSTNAME |\
40+
PGWS_DIMENSIONS_APPNAME))
3341
static volatile sig_atomic_t shutdown_requested = false;
3442

3543
static void handle_sigterm(SIGNAL_ARGS);
@@ -162,25 +170,103 @@ probe_waits(History *observations, HTAB *profile_hash,
162170
LWLockAcquire(ProcArrayLock, LW_SHARED);
163171
for (i = 0; i < ProcGlobal->allProcCount; i++)
164172
{
165-
HistoryItem item,
173+
HistoryItem item_history,
166174
*observation;
175+
ProfileItem item_profile;
167176
PGPROC *proc = &ProcGlobal->allProcs[i];
177+
int pid;
178+
uint32 wait_event_info;
168179

169-
if (!pgws_should_sample_proc(proc, &item.pid, &item.wait_event_info))
180+
/* Check if we need to sample this process */
181+
if (!pgws_should_sample_proc(proc, &pid, &wait_event_info))
170182
continue;
171183

184+
/* We zero whole HistoryItem to avoid doing it field-by-field */
185+
memset(&item_history, 0, sizeof(HistoryItem));
186+
memset(&item_profile, 0, sizeof(ProfileItem));
187+
188+
item_history.pid = pid;
189+
item_profile.pid = pid;
190+
191+
item_history.wait_event_info = wait_event_info;
192+
item_profile.wait_event_info = wait_event_info;
193+
172194
if (pgws_profileQueries)
173-
item.queryId = pgws_proc_queryids[i];
174-
else
175-
item.queryId = 0;
195+
{
196+
item_history.queryId = pgws_proc_queryids[i];
197+
item_profile.queryId = pgws_proc_queryids[i];
198+
}
176199

177-
item.ts = ts;
200+
item_history.ts = ts;
201+
202+
/* Copy everything we need from PGPROC */
203+
if (pgws_history_dimensions & PGWS_DIMENSIONS_ROLE_ID)
204+
item_history.role_id = proc->roleId;
205+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_ROLE_ID)
206+
item_profile.role_id = proc->roleId;
207+
208+
if (pgws_history_dimensions & PGWS_DIMENSIONS_DB_ID)
209+
item_history.database_id = proc->databaseId;
210+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_DB_ID)
211+
item_profile.database_id = proc->databaseId;
212+
213+
if (pgws_history_dimensions & PGWS_DIMENSIONS_PARALLEL_LEADER_PID)
214+
item_history.parallel_leader_pid = (proc->lockGroupLeader ?
215+
proc->lockGroupLeader->pid :
216+
0);
217+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_PARALLEL_LEADER_PID)
218+
item_profile.parallel_leader_pid = (proc->lockGroupLeader ?
219+
proc->lockGroupLeader->pid :
220+
0);
221+
/* Look into BackendStatus only if necessary */
222+
if (check_bestatus_dimensions(pgws_history_dimensions) ||
223+
check_bestatus_dimensions(pgws_profile_dimensions))
224+
{
225+
#if PG_VERSION_NUM >= 170000
226+
PgBackendStatus *bestatus = pgstat_get_beentry_by_proc_number(GetNumberFromPGProc(proc));
227+
#else
228+
PgBackendStatus *bestatus = get_beentry_by_procpid(proc->pid);
229+
#endif
230+
/* Copy everything we need from BackendStatus */
231+
if (bestatus)
232+
{
233+
if (pgws_history_dimensions & PGWS_DIMENSIONS_BE_TYPE)
234+
item_history.backend_type = bestatus->st_backendType;
235+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_BE_TYPE)
236+
item_profile.backend_type = bestatus->st_backendType;
237+
238+
if (pgws_history_dimensions & PGWS_DIMENSIONS_BE_STATE)
239+
item_history.backend_state = bestatus->st_state;
240+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_BE_STATE)
241+
item_profile.backend_state = bestatus->st_state;
242+
243+
if (pgws_history_dimensions & PGWS_DIMENSIONS_BE_START_TIME)
244+
item_history.proc_start = bestatus->st_proc_start_timestamp;
245+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_BE_START_TIME)
246+
item_profile.proc_start = bestatus->st_proc_start_timestamp;
247+
248+
if (pgws_history_dimensions & PGWS_DIMENSIONS_CLIENT_ADDR)
249+
item_history.client_addr = bestatus->st_clientaddr;
250+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_CLIENT_ADDR)
251+
item_profile.client_addr = bestatus->st_clientaddr;
252+
253+
if (pgws_history_dimensions & PGWS_DIMENSIONS_CLIENT_HOSTNAME)
254+
strcpy(item_history.client_hostname, bestatus->st_clienthostname);
255+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_CLIENT_HOSTNAME)
256+
strcpy(item_profile.client_hostname, bestatus->st_clienthostname);
257+
258+
if (pgws_history_dimensions & PGWS_DIMENSIONS_APPNAME)
259+
strcpy(item_history.appname, bestatus->st_appname);
260+
if (pgws_profile_dimensions & PGWS_DIMENSIONS_APPNAME)
261+
strcpy(item_profile.appname, bestatus->st_appname);
262+
}
263+
}
178264

179265
/* Write to the history if needed */
180266
if (write_history)
181267
{
182268
observation = get_next_observation(observations);
183-
*observation = item;
269+
*observation = item_history;
184270
}
185271

186272
/* Write to the profile if needed */
@@ -190,16 +276,21 @@ probe_waits(History *observations, HTAB *profile_hash,
190276
bool found;
191277

192278
if (!profile_pid)
193-
item.pid = 0;
279+
item_profile.pid = 0;
194280

195-
profileItem = (ProfileItem *) hash_search(profile_hash, &item, HASH_ENTER, &found);
281+
profileItem = (ProfileItem *) hash_search(profile_hash, &item_profile, HASH_ENTER, &found);
196282
if (found)
197283
profileItem->count++;
198284
else
199285
profileItem->count = 1;
200286
}
201287
}
202288
LWLockRelease(ProcArrayLock);
289+
#if PG_VERSION_NUM >= 140000
290+
pgstat_clear_backend_activity_snapshot();
291+
#else
292+
pgstat_clear_snapshot();
293+
#endif
203294
}
204295

205296
/*
@@ -287,10 +378,12 @@ make_profile_hash()
287378
{
288379
HASHCTL hash_ctl;
289380

290-
if (pgws_profileQueries)
291-
hash_ctl.keysize = offsetof(ProfileItem, count);
292-
else
293-
hash_ctl.keysize = offsetof(ProfileItem, queryId);
381+
/*
382+
* Since adding additional dimensions we include everyting except count
383+
* into hashtable key. This is fine for cases when some fields are 0 since
384+
* it doesn't impede our ability to search the hash table for entries
385+
*/
386+
hash_ctl.keysize = offsetof(ProfileItem, count);
294387

295388
hash_ctl.entrysize = sizeof(ProfileItem);
296389
return hash_create("Waits profile hash", 1024, &hash_ctl,

expected/queries.out

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ WITH t as (SELECT sum(0) FROM pg_wait_sampling_profile)
2020
0
2121
(1 row)
2222

23+
WITH t as (SELECT sum(0) FROM pg_wait_sampling_current_extended)
24+
SELECT sum(0) FROM generate_series(1, 2), t;
25+
sum
26+
-----
27+
0
28+
(1 row)
29+
30+
WITH t as (SELECT sum(0) FROM pg_wait_sampling_history_extended)
31+
SELECT sum(0) FROM generate_series(1, 2), t;
32+
sum
33+
-----
34+
0
35+
(1 row)
36+
37+
WITH t as (SELECT sum(0) FROM pg_wait_sampling_profile_extended)
38+
SELECT sum(0) FROM generate_series(1, 2), t;
39+
sum
40+
-----
41+
0
42+
(1 row)
43+
2344
-- Some dummy checks just to be sure that all our functions work and return something.
2445
SELECT count(*) = 1 as test FROM pg_wait_sampling_get_current(pg_backend_pid());
2546
test
@@ -45,4 +66,28 @@ SELECT pg_wait_sampling_reset_profile();
4566

4667
(1 row)
4768

69+
SELECT count(*) = 1 as test FROM pg_wait_sampling_get_current_extended(pg_backend_pid());
70+
test
71+
------
72+
t
73+
(1 row)
74+
75+
SELECT count(*) >= 0 as test FROM pg_wait_sampling_get_profile_extended();
76+
test
77+
------
78+
t
79+
(1 row)
80+
81+
SELECT count(*) >= 0 as test FROM pg_wait_sampling_get_history_extended();
82+
test
83+
------
84+
t
85+
(1 row)
86+
87+
SELECT pg_wait_sampling_reset_profile();
88+
pg_wait_sampling_reset_profile
89+
--------------------------------
90+
91+
(1 row)
92+
4893
DROP EXTENSION pg_wait_sampling;

meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ install_data(
2424
'pg_wait_sampling.control',
2525
'pg_wait_sampling--1.0--1.1.sql',
2626
'pg_wait_sampling--1.1.sql',
27+
'pg_wait_sampling--1.1--1.2.sql',
2728
kwargs: contrib_data_args,
2829
)
2930

pg_wait_sampling--1.1--1.2.sql

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/* contrib/pg_wait_sampling/pg_wait_sampling--1.1--1.2.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION pg_wait_sampling UPDATE TO 1.2" to load this file. \quit
5+
6+
CREATE FUNCTION pg_wait_sampling_get_current_extended (
7+
pid int4,
8+
OUT pid int4,
9+
OUT event_type text,
10+
OUT event text,
11+
OUT queryid int8,
12+
OUT role_id int8,
13+
OUT database_id int8,
14+
OUT parallel_leader_pid int4,
15+
OUT backend_type text,
16+
OUT backend_state text,
17+
OUT proc_start timestamptz,
18+
OUT client_addr text,
19+
OUT client_hostname text,
20+
OUT appname text
21+
)
22+
RETURNS SETOF record
23+
AS 'MODULE_PATHNAME'
24+
LANGUAGE C VOLATILE CALLED ON NULL INPUT;
25+
26+
CREATE VIEW pg_wait_sampling_current_extended AS
27+
SELECT * FROM pg_wait_sampling_get_current_extended(NULL::integer);
28+
29+
GRANT SELECT ON pg_wait_sampling_current TO PUBLIC;
30+
31+
CREATE FUNCTION pg_wait_sampling_get_history_extended (
32+
OUT pid int4,
33+
OUT ts timestamptz,
34+
OUT event_type text,
35+
OUT event text,
36+
OUT queryid int8,
37+
OUT role_id int8,
38+
OUT database_id int8,
39+
OUT parallel_leader_pid int4,
40+
OUT backend_type text,
41+
OUT backend_state text,
42+
OUT proc_start timestamptz,
43+
OUT client_addr text,
44+
OUT client_hostname text,
45+
OUT appname text
46+
)
47+
RETURNS SETOF record
48+
AS 'MODULE_PATHNAME'
49+
LANGUAGE C VOLATILE STRICT;
50+
51+
CREATE VIEW pg_wait_sampling_history_extended AS
52+
SELECT * FROM pg_wait_sampling_get_history_extended();
53+
54+
GRANT SELECT ON pg_wait_sampling_history_extended TO PUBLIC;
55+
56+
CREATE FUNCTION pg_wait_sampling_get_profile_extended (
57+
OUT pid int4,
58+
OUT event_type text,
59+
OUT event text,
60+
OUT queryid int8,
61+
OUT role_id int8,
62+
OUT database_id int8,
63+
OUT parallel_leader_pid int4,
64+
OUT backend_type text,
65+
OUT backend_state text,
66+
OUT proc_start timestamptz,
67+
OUT client_addr text,
68+
OUT client_hostname text,
69+
OUT appname text,
70+
OUT count int8
71+
)
72+
RETURNS SETOF record
73+
AS 'MODULE_PATHNAME'
74+
LANGUAGE C VOLATILE STRICT;
75+
76+
CREATE VIEW pg_wait_sampling_profile_extended AS
77+
SELECT * FROM pg_wait_sampling_get_profile_extended();
78+
79+
GRANT SELECT ON pg_wait_sampling_profile_extended TO PUBLIC;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy