22
22
*/
23
23
#include "postgres.h"
24
24
25
+ #include "miscadmin.h"
26
+ #include "port/pg_bitutils.h"
25
27
#include "storage/lmgr.h" /* for GetLockNameFromTagType */
26
28
#include "storage/lwlock.h" /* for GetLWLockIdentifier */
29
+ #include "storage/spin.h"
30
+ #include "utils/memutils.h"
27
31
#include "utils/wait_event.h"
28
32
29
33
30
34
static const char * pgstat_get_wait_activity (WaitEventActivity w );
31
35
static const char * pgstat_get_wait_bufferpin (WaitEventBufferPin w );
32
36
static const char * pgstat_get_wait_client (WaitEventClient w );
33
- static const char * pgstat_get_wait_extension (WaitEventExtension w );
34
37
static const char * pgstat_get_wait_ipc (WaitEventIPC w );
35
38
static const char * pgstat_get_wait_timeout (WaitEventTimeout w );
36
39
static const char * pgstat_get_wait_io (WaitEventIO w );
@@ -42,6 +45,169 @@ uint32 *my_wait_event_info = &local_my_wait_event_info;
42
45
#define WAIT_EVENT_CLASS_MASK 0xFF000000
43
46
#define WAIT_EVENT_ID_MASK 0x0000FFFF
44
47
48
+ /* dynamic allocation counter for custom wait events in extensions */
49
+ typedef struct WaitEventExtensionCounterData
50
+ {
51
+ int nextId ; /* next ID to assign */
52
+ slock_t mutex ; /* protects the counter */
53
+ } WaitEventExtensionCounterData ;
54
+
55
+ /* pointer to the shared memory */
56
+ static WaitEventExtensionCounterData * WaitEventExtensionCounter ;
57
+
58
+ /* first event ID of custom wait events for extensions */
59
+ #define NUM_BUILTIN_WAIT_EVENT_EXTENSION \
60
+ (WAIT_EVENT_EXTENSION_FIRST_USER_DEFINED - WAIT_EVENT_EXTENSION)
61
+
62
+ /*
63
+ * This is indexed by event ID minus NUM_BUILTIN_WAIT_EVENT_EXTENSION, and
64
+ * stores the names of all dynamically-created event IDs known to the current
65
+ * process. Any unused entries in the array will contain NULL.
66
+ */
67
+ static const char * * WaitEventExtensionNames = NULL ;
68
+ static int WaitEventExtensionNamesAllocated = 0 ;
69
+
70
+ static const char * GetWaitEventExtensionIdentifier (uint16 eventId );
71
+
72
+ /*
73
+ * Return the space for dynamic allocation counter.
74
+ */
75
+ Size
76
+ WaitEventExtensionShmemSize (void )
77
+ {
78
+ return sizeof (WaitEventExtensionCounterData );
79
+ }
80
+
81
+ /*
82
+ * Allocate shmem space for dynamic allocation counter.
83
+ */
84
+ void
85
+ WaitEventExtensionShmemInit (void )
86
+ {
87
+ bool found ;
88
+
89
+ WaitEventExtensionCounter = (WaitEventExtensionCounterData * )
90
+ ShmemInitStruct ("WaitEventExtensionCounterData" ,
91
+ WaitEventExtensionShmemSize (), & found );
92
+
93
+ if (!found )
94
+ {
95
+ /* initialize the allocation counter and its spinlock. */
96
+ WaitEventExtensionCounter -> nextId = NUM_BUILTIN_WAIT_EVENT_EXTENSION ;
97
+ SpinLockInit (& WaitEventExtensionCounter -> mutex );
98
+ }
99
+ }
100
+
101
+ /*
102
+ * Allocate a new event ID and return the wait event.
103
+ */
104
+ uint32
105
+ WaitEventExtensionNew (void )
106
+ {
107
+ uint16 eventId ;
108
+
109
+ Assert (LWLockHeldByMeInMode (AddinShmemInitLock , LW_EXCLUSIVE ));
110
+
111
+ SpinLockAcquire (& WaitEventExtensionCounter -> mutex );
112
+
113
+ if (WaitEventExtensionCounter -> nextId > PG_UINT16_MAX )
114
+ {
115
+ SpinLockRelease (& WaitEventExtensionCounter -> mutex );
116
+ ereport (ERROR ,
117
+ errcode (ERRCODE_PROGRAM_LIMIT_EXCEEDED ),
118
+ errmsg ("too many wait events for extensions" ));
119
+ }
120
+
121
+ eventId = WaitEventExtensionCounter -> nextId ++ ;
122
+
123
+ SpinLockRelease (& WaitEventExtensionCounter -> mutex );
124
+
125
+ return PG_WAIT_EXTENSION | eventId ;
126
+ }
127
+
128
+ /*
129
+ * Register a dynamic wait event name for extension in the lookup table
130
+ * of the current process.
131
+ *
132
+ * This routine will save a pointer to the wait event name passed as an argument,
133
+ * so the name should be allocated in a backend-lifetime context
134
+ * (shared memory, TopMemoryContext, static constant, or similar).
135
+ *
136
+ * The "wait_event_name" will be user-visible as a wait event name, so try to
137
+ * use a name that fits the style for those.
138
+ */
139
+ void
140
+ WaitEventExtensionRegisterName (uint32 wait_event_info ,
141
+ const char * wait_event_name )
142
+ {
143
+ uint32 classId ;
144
+ uint16 eventId ;
145
+
146
+ classId = wait_event_info & WAIT_EVENT_CLASS_MASK ;
147
+ eventId = wait_event_info & WAIT_EVENT_ID_MASK ;
148
+
149
+ /* Check the wait event class. */
150
+ if (classId != PG_WAIT_EXTENSION )
151
+ ereport (ERROR ,
152
+ errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
153
+ errmsg ("invalid wait event class %u" , classId ));
154
+
155
+ /* This should only be called for user-defined wait event. */
156
+ if (eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION )
157
+ ereport (ERROR ,
158
+ errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
159
+ errmsg ("invalid wait event ID %u" , eventId ));
160
+
161
+ /* Convert to array index. */
162
+ eventId -= NUM_BUILTIN_WAIT_EVENT_EXTENSION ;
163
+
164
+ /* If necessary, create or enlarge array. */
165
+ if (eventId >= WaitEventExtensionNamesAllocated )
166
+ {
167
+ uint32 newalloc ;
168
+
169
+ newalloc = pg_nextpower2_32 (Max (8 , eventId + 1 ));
170
+
171
+ if (WaitEventExtensionNames == NULL )
172
+ WaitEventExtensionNames = (const char * * )
173
+ MemoryContextAllocZero (TopMemoryContext ,
174
+ newalloc * sizeof (char * ));
175
+ else
176
+ WaitEventExtensionNames =
177
+ repalloc0_array (WaitEventExtensionNames , const char * ,
178
+ WaitEventExtensionNamesAllocated , newalloc );
179
+ WaitEventExtensionNamesAllocated = newalloc ;
180
+ }
181
+
182
+ WaitEventExtensionNames [eventId ] = wait_event_name ;
183
+ }
184
+
185
+ /*
186
+ * Return the name of an wait event ID for extension.
187
+ */
188
+ static const char *
189
+ GetWaitEventExtensionIdentifier (uint16 eventId )
190
+ {
191
+ /* Built-in event? */
192
+ if (eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION )
193
+ return "Extension" ;
194
+
195
+ /*
196
+ * It is a user-defined wait event, so look at WaitEventExtensionNames[].
197
+ * However, it is possible that the name has never been registered by
198
+ * calling WaitEventExtensionRegisterName() in the current process, in
199
+ * which case give up and return "extension".
200
+ */
201
+ eventId -= NUM_BUILTIN_WAIT_EVENT_EXTENSION ;
202
+
203
+ if (eventId >= WaitEventExtensionNamesAllocated ||
204
+ WaitEventExtensionNames [eventId ] == NULL )
205
+ return "extension" ;
206
+
207
+ return WaitEventExtensionNames [eventId ];
208
+ }
209
+
210
+
45
211
/*
46
212
* Configure wait event reporting to report wait events to *wait_event_info.
47
213
* *wait_event_info needs to be valid until pgstat_reset_wait_event_storage()
@@ -151,6 +317,9 @@ pgstat_get_wait_event(uint32 wait_event_info)
151
317
case PG_WAIT_LOCK :
152
318
event_name = GetLockNameFromTagType (eventId );
153
319
break ;
320
+ case PG_WAIT_EXTENSION :
321
+ event_name = GetWaitEventExtensionIdentifier (eventId );
322
+ break ;
154
323
case PG_WAIT_BUFFERPIN :
155
324
{
156
325
WaitEventBufferPin w = (WaitEventBufferPin ) wait_event_info ;
@@ -172,13 +341,6 @@ pgstat_get_wait_event(uint32 wait_event_info)
172
341
event_name = pgstat_get_wait_client (w );
173
342
break ;
174
343
}
175
- case PG_WAIT_EXTENSION :
176
- {
177
- WaitEventExtension w = (WaitEventExtension ) wait_event_info ;
178
-
179
- event_name = pgstat_get_wait_extension (w );
180
- break ;
181
- }
182
344
case PG_WAIT_IPC :
183
345
{
184
346
WaitEventIPC w = (WaitEventIPC ) wait_event_info ;
0 commit comments