1010#include "postgres.h"
1111
1212#include <signal.h>
13+ #include <time.h>
1314
1415#include "compat.h"
1516#include "miscadmin.h"
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))
3341static volatile sig_atomic_t shutdown_requested = false;
3442
3543static 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 ,
0 commit comments