PostgreSQL Source Code git master
Loading...
Searching...
No Matches
wait_event.c
Go to the documentation of this file.
1/* ----------
2 * wait_event.c
3 * Wait event reporting infrastructure.
4 *
5 * Copyright (c) 2001-2026, PostgreSQL Global Development Group
6 *
7 *
8 * IDENTIFICATION
9 * src/backend/utils/activity/wait_event.c
10 *
11 * NOTES
12 *
13 * To make pgstat_report_wait_start() and pgstat_report_wait_end() as
14 * lightweight as possible, they do not check if shared memory (MyProc
15 * specifically, where the wait event is stored) is already available. Instead
16 * we initially set my_wait_event_info to a process local variable, which then
17 * is redirected to shared memory using pgstat_set_wait_event_storage(). For
18 * the same reason pgstat_track_activities is not checked - the check adds
19 * more work than it saves.
20 *
21 * ----------
22 */
23#include "postgres.h"
24
25#include "storage/lmgr.h"
26#include "storage/lwlock.h"
27#include "storage/shmem.h"
28#include "storage/subsystems.h"
29#include "utils/wait_event.h"
30
31
35static const char *pgstat_get_wait_ipc(WaitEventIPC w);
37static const char *pgstat_get_wait_io(WaitEventIO w);
38
39
42
43#define WAIT_EVENT_CLASS_MASK 0xFF000000
44#define WAIT_EVENT_ID_MASK 0x0000FFFF
45
46/*
47 * Hash tables for storing custom wait event ids and their names in
48 * shared memory.
49 *
50 * WaitEventCustomHashByInfo is used to find the name from wait event
51 * information. Any backend can search it to find custom wait events.
52 *
53 * WaitEventCustomHashByName is used to find the wait event information from a
54 * name. It is used to ensure that no duplicated entries are registered.
55 *
56 * For simplicity, we use the same ID counter across types of custom events.
57 * We could end that anytime the need arises.
58 *
59 * The size of the hash table is based on the assumption that usually only a
60 * handful of entries are needed, but since it's small in absolute terms
61 * anyway, we leave a generous amount of headroom.
62 */
63static HTAB *WaitEventCustomHashByInfo; /* find names from infos */
64static HTAB *WaitEventCustomHashByName; /* find infos from names */
65
66#define WAIT_EVENT_CUSTOM_HASH_SIZE 128
67
68/* hash table entries */
70{
71 uint32 wait_event_info; /* hash key */
72 char wait_event_name[NAMEDATALEN]; /* custom wait event name */
74
80
81
82/* dynamic allocation counter for custom wait events */
84
85/* first event ID of custom wait events */
86#define WAIT_EVENT_CUSTOM_INITIAL_ID 1
87
88static uint32 WaitEventCustomNew(uint32 classId, const char *wait_event_name);
89static const char *GetWaitEventCustomIdentifier(uint32 wait_event_info);
90
91static void WaitEventCustomShmemRequest(void *arg);
92static void WaitEventCustomShmemInit(void *arg);
93
98
99/*
100 * Register shmem space for dynamic shared hash and dynamic allocation counter.
101 */
102static void
104{
105 ShmemRequestStruct(.name = "WaitEventCustomCounter",
106 .size = sizeof(int),
107 .ptr = (void **) &WaitEventCustomCounter,
108 );
109 ShmemRequestHash(.name = "WaitEventCustom hash by wait event information",
112 .hash_info.keysize = sizeof(uint32),
113 .hash_info.entrysize = sizeof(WaitEventCustomEntryByInfo),
114 .hash_flags = HASH_ELEM | HASH_BLOBS,
115 );
116 ShmemRequestHash(.name = "WaitEventCustom hash by name",
119 /* key is a NULL-terminated string */
120 .hash_info.keysize = sizeof(char[NAMEDATALEN]),
121 .hash_info.entrysize = sizeof(WaitEventCustomEntryByName),
122 .hash_flags = HASH_ELEM | HASH_STRINGS,
123 );
124}
125
126static void
128{
129 /* initialize the allocation counter */
131}
132
133/*
134 * Allocate a new event ID and return the wait event info.
135 *
136 * If the wait event name is already defined, this does not allocate a new
137 * entry; it returns the wait event information associated to the name.
138 */
139uint32
140WaitEventExtensionNew(const char *wait_event_name)
141{
142 return WaitEventCustomNew(PG_WAIT_EXTENSION, wait_event_name);
143}
144
145uint32
146WaitEventInjectionPointNew(const char *wait_event_name)
147{
148 return WaitEventCustomNew(PG_WAIT_INJECTIONPOINT, wait_event_name);
149}
150
151static uint32
152WaitEventCustomNew(uint32 classId, const char *wait_event_name)
153{
155 bool found;
158 uint32 wait_event_info;
159
160 /* Check the limit of the length of the event name */
161 if (strlen(wait_event_name) >= NAMEDATALEN)
162 elog(ERROR,
163 "cannot use custom wait event string longer than %u characters",
164 NAMEDATALEN - 1);
165
166 /*
167 * Check if the wait event info associated to the name is already defined,
168 * and return it if so.
169 */
172 hash_search(WaitEventCustomHashByName, wait_event_name,
173 HASH_FIND, &found);
175 if (found)
176 {
178
180 if (oldClassId != classId)
183 errmsg("wait event \"%s\" already exists in type \"%s\"",
184 wait_event_name,
185 pgstat_get_wait_event_type(entry_by_name->wait_event_info))));
186 return entry_by_name->wait_event_info;
187 }
188
189 /*
190 * Allocate and register a new wait event. Recheck if the event name
191 * exists, as it could be possible that a concurrent process has inserted
192 * one with the same name since the LWLock acquired again here was
193 * previously released.
194 */
197 hash_search(WaitEventCustomHashByName, wait_event_name,
198 HASH_FIND, &found);
199 if (found)
200 {
202
205 if (oldClassId != classId)
208 errmsg("wait event \"%s\" already exists in type \"%s\"",
209 wait_event_name,
210 pgstat_get_wait_event_type(entry_by_name->wait_event_info))));
211 return entry_by_name->wait_event_info;
212 }
213
214 /* Allocate a new event Id */
218 errmsg("too many custom wait events"));
219
220 eventId = (*WaitEventCustomCounter)++;
221
222 /* Register the new wait event */
223 wait_event_info = classId | eventId;
225 hash_search(WaitEventCustomHashByInfo, &wait_event_info,
226 HASH_ENTER, &found);
227 Assert(!found);
228 strlcpy(entry_by_info->wait_event_name, wait_event_name,
229 sizeof(entry_by_info->wait_event_name));
230
232 hash_search(WaitEventCustomHashByName, wait_event_name,
233 HASH_ENTER, &found);
234 Assert(!found);
235 entry_by_name->wait_event_info = wait_event_info;
236
238
239 return wait_event_info;
240}
241
242/*
243 * Return the name of a custom wait event information.
244 */
245static const char *
247{
248 bool found;
250
251 /* Built-in event? */
252 if (wait_event_info == PG_WAIT_EXTENSION)
253 return "Extension";
254
255 /* It is a user-defined wait event, so lookup hash table. */
258 hash_search(WaitEventCustomHashByInfo, &wait_event_info,
259 HASH_FIND, &found);
261
262 if (!entry)
263 elog(ERROR,
264 "could not find custom name for wait event information %u",
265 wait_event_info);
266
267 return entry->wait_event_name;
268}
269
270
271/*
272 * Returns a list of currently defined custom wait event names. The result is
273 * a palloc'd array, with the number of elements saved in *nwaitevents.
274 */
275char **
277{
278 char **waiteventnames;
281 int index;
282 int els;
283
285
286 /* Now we can safely count the number of entries */
288
289 /* Allocate enough space for all entries */
291
292 /* Now scan the hash table to copy the data */
294
295 index = 0;
297 {
298 if ((hentry->wait_event_info & WAIT_EVENT_CLASS_MASK) != classId)
299 continue;
300 waiteventnames[index] = pstrdup(hentry->wait_event_name);
301 index++;
302 }
303
305
307 return waiteventnames;
308}
309
310/*
311 * Configure wait event reporting to report wait events to *wait_event_info.
312 * *wait_event_info needs to be valid until pgstat_reset_wait_event_storage()
313 * is called.
314 *
315 * Expected to be called during backend startup, to point my_wait_event_info
316 * into shared memory.
317 */
318void
320{
321 my_wait_event_info = wait_event_info;
322}
323
324/*
325 * Reset wait event storage location.
326 *
327 * Expected to be called during backend shutdown, before the location set up
328 * pgstat_set_wait_event_storage() becomes invalid.
329 */
330void
335
336/* ----------
337 * pgstat_get_wait_event_type() -
338 *
339 * Return a string representing the current wait event type, backend is
340 * waiting on.
341 */
342const char *
344{
345 uint32 classId;
346 const char *event_type;
347
348 /* report process as not waiting. */
349 if (wait_event_info == 0)
350 return NULL;
351
352 classId = wait_event_info & WAIT_EVENT_CLASS_MASK;
353
354 switch (classId)
355 {
356 case PG_WAIT_LWLOCK:
357 event_type = "LWLock";
358 break;
359 case PG_WAIT_LOCK:
360 event_type = "Lock";
361 break;
362 case PG_WAIT_BUFFER:
363 event_type = "Buffer";
364 break;
365 case PG_WAIT_ACTIVITY:
366 event_type = "Activity";
367 break;
368 case PG_WAIT_CLIENT:
369 event_type = "Client";
370 break;
372 event_type = "Extension";
373 break;
374 case PG_WAIT_IPC:
375 event_type = "IPC";
376 break;
377 case PG_WAIT_TIMEOUT:
378 event_type = "Timeout";
379 break;
380 case PG_WAIT_IO:
381 event_type = "IO";
382 break;
384 event_type = "InjectionPoint";
385 break;
386 default:
387 event_type = "???";
388 break;
389 }
390
391 return event_type;
392}
393
394/* ----------
395 * pgstat_get_wait_event() -
396 *
397 * Return a string representing the current wait event, backend is
398 * waiting on.
399 */
400const char *
402{
403 uint32 classId;
405 const char *event_name;
406
407 /* report process as not waiting. */
408 if (wait_event_info == 0)
409 return NULL;
410
411 classId = wait_event_info & WAIT_EVENT_CLASS_MASK;
412 eventId = wait_event_info & WAIT_EVENT_ID_MASK;
413
414 switch (classId)
415 {
416 case PG_WAIT_LWLOCK:
418 break;
419 case PG_WAIT_LOCK:
421 break;
424 event_name = GetWaitEventCustomIdentifier(wait_event_info);
425 break;
426 case PG_WAIT_BUFFER:
427 {
428 WaitEventBuffer w = (WaitEventBuffer) wait_event_info;
429
431 break;
432 }
433 case PG_WAIT_ACTIVITY:
434 {
435 WaitEventActivity w = (WaitEventActivity) wait_event_info;
436
438 break;
439 }
440 case PG_WAIT_CLIENT:
441 {
442 WaitEventClient w = (WaitEventClient) wait_event_info;
443
445 break;
446 }
447 case PG_WAIT_IPC:
448 {
449 WaitEventIPC w = (WaitEventIPC) wait_event_info;
450
452 break;
453 }
454 case PG_WAIT_TIMEOUT:
455 {
456 WaitEventTimeout w = (WaitEventTimeout) wait_event_info;
457
459 break;
460 }
461 case PG_WAIT_IO:
462 {
463 WaitEventIO w = (WaitEventIO) wait_event_info;
464
466 break;
467 }
468 default:
469 event_name = "unknown wait event";
470 break;
471 }
472
473 return event_name;
474}
475
476#include "utils/pgstat_wait_event.c"
#define Assert(condition)
Definition c.h:1002
uint16_t uint16
Definition c.h:682
uint32_t uint32
Definition c.h:683
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
int64 hash_get_num_entries(HTAB *hashp)
Definition dynahash.c:1273
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
Datum arg
Definition elog.c:1323
int errcode(int sqlerrcode)
Definition elog.c:875
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_array(type, count)
Definition fe_memutils.h:91
#define HASH_STRINGS
Definition hsearch.h:91
@ HASH_FIND
Definition hsearch.h:108
@ HASH_ENTER
Definition hsearch.h:109
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
const char * GetLockNameFromTagType(uint16 locktag_type)
Definition lmgr.c:1346
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
const char * GetLWLockIdentifier(uint32 classId, uint16 eventId)
Definition lwlock.c:747
@ LW_SHARED
Definition lwlock.h:105
@ LW_EXCLUSIVE
Definition lwlock.h:104
char * pstrdup(const char *in)
Definition mcxt.c:1910
static char * errmsg
#define NAMEDATALEN
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
static int fb(int x)
#define ShmemRequestHash(...)
Definition shmem.h:179
#define ShmemRequestStruct(...)
Definition shmem.h:176
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30
Size keysize
Definition dynahash.c:241
ShmemRequestCallback request_fn
Definition shmem.h:133
char wait_event_name[NAMEDATALEN]
Definition wait_event.c:72
char wait_event_name[NAMEDATALEN]
Definition wait_event.c:77
Definition type.h:97
#define PG_WAIT_TIMEOUT
#define PG_WAIT_INJECTIONPOINT
#define PG_WAIT_LWLOCK
#define PG_WAIT_BUFFER
#define PG_WAIT_IPC
#define PG_WAIT_CLIENT
#define PG_WAIT_EXTENSION
#define PG_WAIT_ACTIVITY
#define PG_WAIT_LOCK
#define PG_WAIT_IO
static const char * pgstat_get_wait_timeout(WaitEventTimeout w)
char ** GetWaitEventCustomNames(uint32 classId, int *nwaitevents)
Definition wait_event.c:276
static const char * pgstat_get_wait_activity(WaitEventActivity w)
const char * pgstat_get_wait_event_type(uint32 wait_event_info)
Definition wait_event.c:343
static const char * pgstat_get_wait_io(WaitEventIO w)
void pgstat_set_wait_event_storage(uint32 *wait_event_info)
Definition wait_event.c:319
const char * pgstat_get_wait_event(uint32 wait_event_info)
Definition wait_event.c:401
static void WaitEventCustomShmemRequest(void *arg)
Definition wait_event.c:103
static const char * GetWaitEventCustomIdentifier(uint32 wait_event_info)
Definition wait_event.c:246
static uint32 local_my_wait_event_info
Definition wait_event.c:40
uint32 WaitEventInjectionPointNew(const char *wait_event_name)
Definition wait_event.c:146
static int * WaitEventCustomCounter
Definition wait_event.c:83
static HTAB * WaitEventCustomHashByName
Definition wait_event.c:64
static const char * pgstat_get_wait_client(WaitEventClient w)
const ShmemCallbacks WaitEventCustomShmemCallbacks
Definition wait_event.c:94
static const char * pgstat_get_wait_ipc(WaitEventIPC w)
#define WAIT_EVENT_CUSTOM_HASH_SIZE
Definition wait_event.c:66
void pgstat_reset_wait_event_storage(void)
Definition wait_event.c:331
#define WAIT_EVENT_ID_MASK
Definition wait_event.c:44
static HTAB * WaitEventCustomHashByInfo
Definition wait_event.c:63
static void WaitEventCustomShmemInit(void *arg)
Definition wait_event.c:127
#define WAIT_EVENT_CLASS_MASK
Definition wait_event.c:43
uint32 WaitEventExtensionNew(const char *wait_event_name)
Definition wait_event.c:140
static uint32 WaitEventCustomNew(uint32 classId, const char *wait_event_name)
Definition wait_event.c:152
uint32 * my_wait_event_info
Definition wait_event.c:41
#define WAIT_EVENT_CUSTOM_INITIAL_ID
Definition wait_event.c:86
static const char * pgstat_get_wait_buffer(WaitEventBuffer w)
const char * name