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 "storage/spin.h"
30#include "utils/wait_event.h"
31
32
36static const char *pgstat_get_wait_ipc(WaitEventIPC w);
38static const char *pgstat_get_wait_io(WaitEventIO w);
39
40
43
44#define WAIT_EVENT_CLASS_MASK 0xFF000000
45#define WAIT_EVENT_ID_MASK 0x0000FFFF
46
47/*
48 * Hash tables for storing custom wait event ids and their names in
49 * shared memory.
50 *
51 * WaitEventCustomHashByInfo is used to find the name from wait event
52 * information. Any backend can search it to find custom wait events.
53 *
54 * WaitEventCustomHashByName is used to find the wait event information from a
55 * name. It is used to ensure that no duplicated entries are registered.
56 *
57 * For simplicity, we use the same ID counter across types of custom events.
58 * We could end that anytime the need arises.
59 *
60 * The size of the hash table is based on the assumption that usually only a
61 * handful of entries are needed, but since it's small in absolute terms
62 * anyway, we leave a generous amount of headroom.
63 */
64static HTAB *WaitEventCustomHashByInfo; /* find names from infos */
65static HTAB *WaitEventCustomHashByName; /* find infos from names */
66
67#define WAIT_EVENT_CUSTOM_HASH_SIZE 128
68
69/* hash table entries */
71{
72 uint32 wait_event_info; /* hash key */
73 char wait_event_name[NAMEDATALEN]; /* custom wait event name */
75
81
82
83/* dynamic allocation counter for custom wait events */
85{
86 int nextId; /* next ID to assign */
87 slock_t mutex; /* protects the counter */
89
90/* pointer to the shared memory */
92
93/* first event ID of custom wait events */
94#define WAIT_EVENT_CUSTOM_INITIAL_ID 1
95
96static uint32 WaitEventCustomNew(uint32 classId, const char *wait_event_name);
97static const char *GetWaitEventCustomIdentifier(uint32 wait_event_info);
98
99static void WaitEventCustomShmemRequest(void *arg);
100static void WaitEventCustomShmemInit(void *arg);
101
106
107/*
108 * Register shmem space for dynamic shared hash and dynamic allocation counter.
109 */
110static void
112{
113 ShmemRequestStruct(.name = "WaitEventCustomCounterData",
114 .size = sizeof(WaitEventCustomCounterData),
115 .ptr = (void **) &WaitEventCustomCounter,
116 );
117 ShmemRequestHash(.name = "WaitEventCustom hash by wait event information",
120 .hash_info.keysize = sizeof(uint32),
121 .hash_info.entrysize = sizeof(WaitEventCustomEntryByInfo),
122 .hash_flags = HASH_ELEM | HASH_BLOBS,
123 );
124 ShmemRequestHash(.name = "WaitEventCustom hash by name",
127 /* key is a NULL-terminated string */
128 .hash_info.keysize = sizeof(char[NAMEDATALEN]),
129 .hash_info.entrysize = sizeof(WaitEventCustomEntryByName),
130 .hash_flags = HASH_ELEM | HASH_STRINGS,
131 );
132}
133
134static void
136{
137 /* initialize the allocation counter and its spinlock. */
140}
141
142/*
143 * Allocate a new event ID and return the wait event info.
144 *
145 * If the wait event name is already defined, this does not allocate a new
146 * entry; it returns the wait event information associated to the name.
147 */
148uint32
149WaitEventExtensionNew(const char *wait_event_name)
150{
151 return WaitEventCustomNew(PG_WAIT_EXTENSION, wait_event_name);
152}
153
154uint32
155WaitEventInjectionPointNew(const char *wait_event_name)
156{
157 return WaitEventCustomNew(PG_WAIT_INJECTIONPOINT, wait_event_name);
158}
159
160static uint32
161WaitEventCustomNew(uint32 classId, const char *wait_event_name)
162{
164 bool found;
167 uint32 wait_event_info;
168
169 /* Check the limit of the length of the event name */
170 if (strlen(wait_event_name) >= NAMEDATALEN)
171 elog(ERROR,
172 "cannot use custom wait event string longer than %u characters",
173 NAMEDATALEN - 1);
174
175 /*
176 * Check if the wait event info associated to the name is already defined,
177 * and return it if so.
178 */
181 hash_search(WaitEventCustomHashByName, wait_event_name,
182 HASH_FIND, &found);
184 if (found)
185 {
187
189 if (oldClassId != classId)
192 errmsg("wait event \"%s\" already exists in type \"%s\"",
193 wait_event_name,
194 pgstat_get_wait_event_type(entry_by_name->wait_event_info))));
195 return entry_by_name->wait_event_info;
196 }
197
198 /*
199 * Allocate and register a new wait event. Recheck if the event name
200 * exists, as it could be possible that a concurrent process has inserted
201 * one with the same name since the LWLock acquired again here was
202 * previously released.
203 */
206 hash_search(WaitEventCustomHashByName, wait_event_name,
207 HASH_FIND, &found);
208 if (found)
209 {
211
214 if (oldClassId != classId)
217 errmsg("wait event \"%s\" already exists in type \"%s\"",
218 wait_event_name,
219 pgstat_get_wait_event_type(entry_by_name->wait_event_info))));
220 return entry_by_name->wait_event_info;
221 }
222
223 /* Allocate a new event Id */
225
227 {
231 errmsg("too many custom wait events"));
232 }
233
235
237
238 /* Register the new wait event */
239 wait_event_info = classId | eventId;
241 hash_search(WaitEventCustomHashByInfo, &wait_event_info,
242 HASH_ENTER, &found);
243 Assert(!found);
244 strlcpy(entry_by_info->wait_event_name, wait_event_name,
245 sizeof(entry_by_info->wait_event_name));
246
248 hash_search(WaitEventCustomHashByName, wait_event_name,
249 HASH_ENTER, &found);
250 Assert(!found);
251 entry_by_name->wait_event_info = wait_event_info;
252
254
255 return wait_event_info;
256}
257
258/*
259 * Return the name of a custom wait event information.
260 */
261static const char *
263{
264 bool found;
266
267 /* Built-in event? */
268 if (wait_event_info == PG_WAIT_EXTENSION)
269 return "Extension";
270
271 /* It is a user-defined wait event, so lookup hash table. */
274 hash_search(WaitEventCustomHashByInfo, &wait_event_info,
275 HASH_FIND, &found);
277
278 if (!entry)
279 elog(ERROR,
280 "could not find custom name for wait event information %u",
281 wait_event_info);
282
283 return entry->wait_event_name;
284}
285
286
287/*
288 * Returns a list of currently defined custom wait event names. The result is
289 * a palloc'd array, with the number of elements saved in *nwaitevents.
290 */
291char **
293{
294 char **waiteventnames;
297 int index;
298 int els;
299
301
302 /* Now we can safely count the number of entries */
304
305 /* Allocate enough space for all entries */
307
308 /* Now scan the hash table to copy the data */
310
311 index = 0;
313 {
314 if ((hentry->wait_event_info & WAIT_EVENT_CLASS_MASK) != classId)
315 continue;
316 waiteventnames[index] = pstrdup(hentry->wait_event_name);
317 index++;
318 }
319
321
323 return waiteventnames;
324}
325
326/*
327 * Configure wait event reporting to report wait events to *wait_event_info.
328 * *wait_event_info needs to be valid until pgstat_reset_wait_event_storage()
329 * is called.
330 *
331 * Expected to be called during backend startup, to point my_wait_event_info
332 * into shared memory.
333 */
334void
336{
337 my_wait_event_info = wait_event_info;
338}
339
340/*
341 * Reset wait event storage location.
342 *
343 * Expected to be called during backend shutdown, before the location set up
344 * pgstat_set_wait_event_storage() becomes invalid.
345 */
346void
351
352/* ----------
353 * pgstat_get_wait_event_type() -
354 *
355 * Return a string representing the current wait event type, backend is
356 * waiting on.
357 */
358const char *
360{
361 uint32 classId;
362 const char *event_type;
363
364 /* report process as not waiting. */
365 if (wait_event_info == 0)
366 return NULL;
367
368 classId = wait_event_info & WAIT_EVENT_CLASS_MASK;
369
370 switch (classId)
371 {
372 case PG_WAIT_LWLOCK:
373 event_type = "LWLock";
374 break;
375 case PG_WAIT_LOCK:
376 event_type = "Lock";
377 break;
378 case PG_WAIT_BUFFER:
379 event_type = "Buffer";
380 break;
381 case PG_WAIT_ACTIVITY:
382 event_type = "Activity";
383 break;
384 case PG_WAIT_CLIENT:
385 event_type = "Client";
386 break;
388 event_type = "Extension";
389 break;
390 case PG_WAIT_IPC:
391 event_type = "IPC";
392 break;
393 case PG_WAIT_TIMEOUT:
394 event_type = "Timeout";
395 break;
396 case PG_WAIT_IO:
397 event_type = "IO";
398 break;
400 event_type = "InjectionPoint";
401 break;
402 default:
403 event_type = "???";
404 break;
405 }
406
407 return event_type;
408}
409
410/* ----------
411 * pgstat_get_wait_event() -
412 *
413 * Return a string representing the current wait event, backend is
414 * waiting on.
415 */
416const char *
418{
419 uint32 classId;
421 const char *event_name;
422
423 /* report process as not waiting. */
424 if (wait_event_info == 0)
425 return NULL;
426
427 classId = wait_event_info & WAIT_EVENT_CLASS_MASK;
428 eventId = wait_event_info & WAIT_EVENT_ID_MASK;
429
430 switch (classId)
431 {
432 case PG_WAIT_LWLOCK:
434 break;
435 case PG_WAIT_LOCK:
437 break;
440 event_name = GetWaitEventCustomIdentifier(wait_event_info);
441 break;
442 case PG_WAIT_BUFFER:
443 {
444 WaitEventBuffer w = (WaitEventBuffer) wait_event_info;
445
447 break;
448 }
449 case PG_WAIT_ACTIVITY:
450 {
451 WaitEventActivity w = (WaitEventActivity) wait_event_info;
452
454 break;
455 }
456 case PG_WAIT_CLIENT:
457 {
458 WaitEventClient w = (WaitEventClient) wait_event_info;
459
461 break;
462 }
463 case PG_WAIT_IPC:
464 {
465 WaitEventIPC w = (WaitEventIPC) wait_event_info;
466
468 break;
469 }
470 case PG_WAIT_TIMEOUT:
471 {
472 WaitEventTimeout w = (WaitEventTimeout) wait_event_info;
473
475 break;
476 }
477 case PG_WAIT_IO:
478 {
479 WaitEventIO w = (WaitEventIO) wait_event_info;
480
482 break;
483 }
484 default:
485 event_name = "unknown wait event";
486 break;
487 }
488
489 return event_name;
490}
491
492#include "utils/pgstat_wait_event.c"
#define Assert(condition)
Definition c.h:943
uint16_t uint16
Definition c.h:623
uint32_t uint32
Definition c.h:624
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:1322
int errcode(int sqlerrcode)
Definition elog.c:874
#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:76
#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:1781
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
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
static void SpinLockInit(volatile slock_t *lock)
Definition spin.h:50
#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:73
char wait_event_name[NAMEDATALEN]
Definition wait_event.c:78
Definition type.h:96
#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:292
static WaitEventCustomCounterData * WaitEventCustomCounter
Definition wait_event.c:91
static const char * pgstat_get_wait_activity(WaitEventActivity w)
const char * pgstat_get_wait_event_type(uint32 wait_event_info)
Definition wait_event.c:359
static const char * pgstat_get_wait_io(WaitEventIO w)
void pgstat_set_wait_event_storage(uint32 *wait_event_info)
Definition wait_event.c:335
const char * pgstat_get_wait_event(uint32 wait_event_info)
Definition wait_event.c:417
static void WaitEventCustomShmemRequest(void *arg)
Definition wait_event.c:111
static const char * GetWaitEventCustomIdentifier(uint32 wait_event_info)
Definition wait_event.c:262
static uint32 local_my_wait_event_info
Definition wait_event.c:41
uint32 WaitEventInjectionPointNew(const char *wait_event_name)
Definition wait_event.c:155
static HTAB * WaitEventCustomHashByName
Definition wait_event.c:65
static const char * pgstat_get_wait_client(WaitEventClient w)
const ShmemCallbacks WaitEventCustomShmemCallbacks
Definition wait_event.c:102
static const char * pgstat_get_wait_ipc(WaitEventIPC w)
#define WAIT_EVENT_CUSTOM_HASH_SIZE
Definition wait_event.c:67
void pgstat_reset_wait_event_storage(void)
Definition wait_event.c:347
#define WAIT_EVENT_ID_MASK
Definition wait_event.c:45
static HTAB * WaitEventCustomHashByInfo
Definition wait_event.c:64
static void WaitEventCustomShmemInit(void *arg)
Definition wait_event.c:135
#define WAIT_EVENT_CLASS_MASK
Definition wait_event.c:44
uint32 WaitEventExtensionNew(const char *wait_event_name)
Definition wait_event.c:149
static uint32 WaitEventCustomNew(uint32 classId, const char *wait_event_name)
Definition wait_event.c:161
uint32 * my_wait_event_info
Definition wait_event.c:42
#define WAIT_EVENT_CUSTOM_INITIAL_ID
Definition wait_event.c:94
static const char * pgstat_get_wait_buffer(WaitEventBuffer w)
const char * name