Add wait event type "InjectionPoint", a custom type like "Extension".
authorNoah Misch <[email protected]>
Fri, 28 Jun 2024 02:21:05 +0000 (19:21 -0700)
committerNoah Misch <[email protected]>
Fri, 28 Jun 2024 02:21:05 +0000 (19:21 -0700)
Both injection points and customization of type "Extension" are new in
v17, so this just changes a detail of an unreleased feature.

Reported by Robert Haas.  Reviewed by Michael Paquier.

Discussion: https://postgr.es/m/CA+TgmobfMU5pdXP36D5iAwxV5WKE_vuDLtp_1QyH+H5jMMt21g@mail.gmail.com

13 files changed:
doc/src/sgml/monitoring.sgml
doc/src/sgml/xfunc.sgml
src/backend/storage/ipc/ipci.c
src/backend/utils/activity/generate-wait_event_types.pl
src/backend/utils/activity/wait_event.c
src/backend/utils/activity/wait_event_funcs.c
src/backend/utils/activity/wait_event_names.txt
src/include/storage/lwlocklist.h
src/include/utils/wait_event.h
src/test/modules/injection_points/injection_points.c
src/test/regress/expected/sysviews.out
src/test/regress/sql/sysviews.sql
src/tools/pgindent/typedefs.list

index b2ad9b446f39942ce46d40141000ebf853f11bb6..991f629907518106b9e64ec8cae552b5e7ab04a5 100644 (file)
@@ -1063,6 +1063,14 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
        See <xref linkend="wait-event-extension-table"/>.
       </entry>
      </row>
+     <row>
+      <entry><literal>InjectionPoint</literal></entry>
+      <entry>The server process is waiting for an injection point to reach an
+       outcome defined in a test.  See
+       <xref linkend="xfunc-addin-injection-points"/> for more details.  This
+       type has no predefined wait points.
+      </entry>
+     </row>
      <row>
       <entry><literal>IO</literal></entry>
       <entry>The server process is waiting for an I/O operation to complete.
@@ -1139,8 +1147,8 @@ description | Waiting for a newly initialized WAL file to reach durable storage
 
    <note>
     <para>
-     Extensions can add <literal>Extension</literal> and
-     <literal>LWLock</literal> events
+     Extensions can add <literal>Extension</literal>,
+     <literal>InjectionPoint</literal>. and <literal>LWLock</literal> events
      to the lists shown in <xref linkend="wait-event-extension-table"/> and
      <xref linkend="wait-event-lwlock-table"/>. In some cases, the name
      of an <literal>LWLock</literal> assigned by an extension will not be
index 1d0b65193e3f482539b99bc37f6988fac6120bb9..f3a3e4e2f8f603010989a501e84bfb2d3655ca31 100644 (file)
@@ -3643,7 +3643,11 @@ extern void InjectionPointAttach(const char *name,
 static void
 custom_injection_callback(const char *name, const void *private_data)
 {
+    uint32 wait_event_info = WaitEventInjectionPointNew(name);
+
+    pgstat_report_wait_start(wait_event_info);
     elog(NOTICE, "%s: executed custom callback", name);
+    pgstat_report_wait_end();
 }
 </programlisting>
      This callback prints a message to server error log with severity
index 521ed5418ccc019b2a14f9d30225cafc408a76c7..2100150f01cd41e7a72cc65e0123fd3c9a6b0ef3 100644 (file)
@@ -149,7 +149,7 @@ CalculateShmemSize(int *num_semaphores)
    size = add_size(size, SyncScanShmemSize());
    size = add_size(size, AsyncShmemSize());
    size = add_size(size, StatsShmemSize());
-   size = add_size(size, WaitEventExtensionShmemSize());
+   size = add_size(size, WaitEventCustomShmemSize());
    size = add_size(size, InjectionPointShmemSize());
    size = add_size(size, SlotSyncShmemSize());
 #ifdef EXEC_BACKEND
@@ -355,7 +355,7 @@ CreateOrAttachShmemStructs(void)
    SyncScanShmemInit();
    AsyncShmemInit();
    StatsShmemInit();
-   WaitEventExtensionShmemInit();
+   WaitEventCustomShmemInit();
    InjectionPointShmemInit();
 }
 
index 42f36f405bd767a0c272c7d823eba89d945266e4..6a9c0a5d347113c16a2782058d1c615e07c8ebb5 100644 (file)
@@ -181,9 +181,10 @@ if ($gen_code)
    foreach my $waitclass (sort { uc($a) cmp uc($b) } keys %hashwe)
    {
        # Don't generate the pgstat_wait_event.c and wait_event_types.h files
-       # for Extension, LWLock and Lock, these are handled independently.
+       # for types handled independently.
        next
          if ( $waitclass eq 'WaitEventExtension'
+           || $waitclass eq 'WaitEventInjectionPoint'
            || $waitclass eq 'WaitEventLWLock'
            || $waitclass eq 'WaitEventLock');
 
index 084a9dfdc28a6ce6c301d3687a515675aa40cea4..bbf59482be19623e959454079a9a78a9564c0042 100644 (file)
@@ -47,68 +47,69 @@ uint32     *my_wait_event_info = &local_my_wait_event_info;
  * Hash tables for storing custom wait event ids and their names in
  * shared memory.
  *
- * WaitEventExtensionHashById is used to find the name from an event id.
- * Any backend can search it to find custom wait events.
+ * WaitEventCustomHashByInfo is used to find the name from wait event
+ * information.  Any backend can search it to find custom wait events.
  *
- * WaitEventExtensionHashByName is used to find the event ID from a name.
- * It is used to ensure that no duplicated entries are registered.
+ * WaitEventCustomHashByName is used to find the wait event information from a
+ * name.  It is used to ensure that no duplicated entries are registered.
+ *
+ * For simplicity, we use the same ID counter across types of custom events.
+ * We could end that anytime the need arises.
  *
  * The size of the hash table is based on the assumption that
- * WAIT_EVENT_EXTENSION_HASH_INIT_SIZE is enough for most cases, and it seems
+ * WAIT_EVENT_CUSTOM_HASH_INIT_SIZE is enough for most cases, and it seems
  * unlikely that the number of entries will reach
- * WAIT_EVENT_EXTENSION_HASH_MAX_SIZE.
+ * WAIT_EVENT_CUSTOM_HASH_MAX_SIZE.
  */
-static HTAB *WaitEventExtensionHashById;   /* find names from IDs */
-static HTAB *WaitEventExtensionHashByName; /* find IDs from names */
+static HTAB *WaitEventCustomHashByInfo; /* find names from infos */
+static HTAB *WaitEventCustomHashByName; /* find infos from names */
 
-#define WAIT_EVENT_EXTENSION_HASH_INIT_SIZE    16
-#define WAIT_EVENT_EXTENSION_HASH_MAX_SIZE 128
+#define WAIT_EVENT_CUSTOM_HASH_INIT_SIZE   16
+#define WAIT_EVENT_CUSTOM_HASH_MAX_SIZE    128
 
 /* hash table entries */
-typedef struct WaitEventExtensionEntryById
+typedef struct WaitEventCustomEntryByInfo
 {
-   uint16      event_id;       /* hash key */
+   uint32      wait_event_info;    /* hash key */
    char        wait_event_name[NAMEDATALEN];   /* custom wait event name */
-} WaitEventExtensionEntryById;
+} WaitEventCustomEntryByInfo;
 
-typedef struct WaitEventExtensionEntryByName
+typedef struct WaitEventCustomEntryByName
 {
    char        wait_event_name[NAMEDATALEN];   /* hash key */
-   uint16      event_id;       /* wait event ID */
-} WaitEventExtensionEntryByName;
+   uint32      wait_event_info;
+} WaitEventCustomEntryByName;
 
 
-/* dynamic allocation counter for custom wait events in extensions */
-typedef struct WaitEventExtensionCounterData
+/* dynamic allocation counter for custom wait events */
+typedef struct WaitEventCustomCounterData
 {
    int         nextId;         /* next ID to assign */
    slock_t     mutex;          /* protects the counter */
-} WaitEventExtensionCounterData;
+} WaitEventCustomCounterData;
 
 /* pointer to the shared memory */
-static WaitEventExtensionCounterData *WaitEventExtensionCounter;
-
-/* first event ID of custom wait events for extensions */
-#define WAIT_EVENT_EXTENSION_INITIAL_ID    1
+static WaitEventCustomCounterData *WaitEventCustomCounter;
 
-/* wait event info for extensions */
-#define WAIT_EVENT_EXTENSION_INFO(eventId) (PG_WAIT_EXTENSION | eventId)
+/* first event ID of custom wait events */
+#define WAIT_EVENT_CUSTOM_INITIAL_ID   1
 
-static const char *GetWaitEventExtensionIdentifier(uint16 eventId);
+static uint32 WaitEventCustomNew(uint32 classId, const char *wait_event_name);
+static const char *GetWaitEventCustomIdentifier(uint32 wait_event_info);
 
 /*
  *  Return the space for dynamic shared hash tables and dynamic allocation counter.
  */
 Size
-WaitEventExtensionShmemSize(void)
+WaitEventCustomShmemSize(void)
 {
    Size        sz;
 
-   sz = MAXALIGN(sizeof(WaitEventExtensionCounterData));
-   sz = add_size(sz, hash_estimate_size(WAIT_EVENT_EXTENSION_HASH_MAX_SIZE,
-                                        sizeof(WaitEventExtensionEntryById)));
-   sz = add_size(sz, hash_estimate_size(WAIT_EVENT_EXTENSION_HASH_MAX_SIZE,
-                                        sizeof(WaitEventExtensionEntryByName)));
+   sz = MAXALIGN(sizeof(WaitEventCustomCounterData));
+   sz = add_size(sz, hash_estimate_size(WAIT_EVENT_CUSTOM_HASH_MAX_SIZE,
+                                        sizeof(WaitEventCustomEntryByInfo)));
+   sz = add_size(sz, hash_estimate_size(WAIT_EVENT_CUSTOM_HASH_MAX_SIZE,
+                                        sizeof(WaitEventCustomEntryByName)));
    return sz;
 }
 
@@ -116,39 +117,41 @@ WaitEventExtensionShmemSize(void)
  * Allocate shmem space for dynamic shared hash and dynamic allocation counter.
  */
 void
-WaitEventExtensionShmemInit(void)
+WaitEventCustomShmemInit(void)
 {
    bool        found;
    HASHCTL     info;
 
-   WaitEventExtensionCounter = (WaitEventExtensionCounterData *)
-       ShmemInitStruct("WaitEventExtensionCounterData",
-                       sizeof(WaitEventExtensionCounterData), &found);
+   WaitEventCustomCounter = (WaitEventCustomCounterData *)
+       ShmemInitStruct("WaitEventCustomCounterData",
+                       sizeof(WaitEventCustomCounterData), &found);
 
    if (!found)
    {
        /* initialize the allocation counter and its spinlock. */
-       WaitEventExtensionCounter->nextId = WAIT_EVENT_EXTENSION_INITIAL_ID;
-       SpinLockInit(&WaitEventExtensionCounter->mutex);
+       WaitEventCustomCounter->nextId = WAIT_EVENT_CUSTOM_INITIAL_ID;
+       SpinLockInit(&WaitEventCustomCounter->mutex);
    }
 
    /* initialize or attach the hash tables to store custom wait events */
-   info.keysize = sizeof(uint16);
-   info.entrysize = sizeof(WaitEventExtensionEntryById);
-   WaitEventExtensionHashById = ShmemInitHash("WaitEventExtension hash by id",
-                                              WAIT_EVENT_EXTENSION_HASH_INIT_SIZE,
-                                              WAIT_EVENT_EXTENSION_HASH_MAX_SIZE,
-                                              &info,
-                                              HASH_ELEM | HASH_BLOBS);
+   info.keysize = sizeof(uint32);
+   info.entrysize = sizeof(WaitEventCustomEntryByInfo);
+   WaitEventCustomHashByInfo =
+       ShmemInitHash("WaitEventCustom hash by wait event information",
+                     WAIT_EVENT_CUSTOM_HASH_INIT_SIZE,
+                     WAIT_EVENT_CUSTOM_HASH_MAX_SIZE,
+                     &info,
+                     HASH_ELEM | HASH_BLOBS);
 
    /* key is a NULL-terminated string */
    info.keysize = sizeof(char[NAMEDATALEN]);
-   info.entrysize = sizeof(WaitEventExtensionEntryByName);
-   WaitEventExtensionHashByName = ShmemInitHash("WaitEventExtension hash by name",
-                                                WAIT_EVENT_EXTENSION_HASH_INIT_SIZE,
-                                                WAIT_EVENT_EXTENSION_HASH_MAX_SIZE,
-                                                &info,
-                                                HASH_ELEM | HASH_STRINGS);
+   info.entrysize = sizeof(WaitEventCustomEntryByName);
+   WaitEventCustomHashByName =
+       ShmemInitHash("WaitEventCustom hash by name",
+                     WAIT_EVENT_CUSTOM_HASH_INIT_SIZE,
+                     WAIT_EVENT_CUSTOM_HASH_MAX_SIZE,
+                     &info,
+                     HASH_ELEM | HASH_STRINGS);
 }
 
 /*
@@ -159,11 +162,24 @@ WaitEventExtensionShmemInit(void)
  */
 uint32
 WaitEventExtensionNew(const char *wait_event_name)
+{
+   return WaitEventCustomNew(PG_WAIT_EXTENSION, wait_event_name);
+}
+
+uint32
+WaitEventInjectionPointNew(const char *wait_event_name)
+{
+   return WaitEventCustomNew(PG_WAIT_INJECTIONPOINT, wait_event_name);
+}
+
+static uint32
+WaitEventCustomNew(uint32 classId, const char *wait_event_name)
 {
    uint16      eventId;
    bool        found;
-   WaitEventExtensionEntryByName *entry_by_name;
-   WaitEventExtensionEntryById *entry_by_id;
+   WaitEventCustomEntryByName *entry_by_name;
+   WaitEventCustomEntryByInfo *entry_by_info;
+   uint32      wait_event_info;
 
    /* Check the limit of the length of the event name */
    if (strlen(wait_event_name) >= NAMEDATALEN)
@@ -175,13 +191,24 @@ WaitEventExtensionNew(const char *wait_event_name)
     * Check if the wait event info associated to the name is already defined,
     * and return it if so.
     */
-   LWLockAcquire(WaitEventExtensionLock, LW_SHARED);
-   entry_by_name = (WaitEventExtensionEntryByName *)
-       hash_search(WaitEventExtensionHashByName, wait_event_name,
+   LWLockAcquire(WaitEventCustomLock, LW_SHARED);
+   entry_by_name = (WaitEventCustomEntryByName *)
+       hash_search(WaitEventCustomHashByName, wait_event_name,
                    HASH_FIND, &found);
-   LWLockRelease(WaitEventExtensionLock);
+   LWLockRelease(WaitEventCustomLock);
    if (found)
-       return WAIT_EVENT_EXTENSION_INFO(entry_by_name->event_id);
+   {
+       uint32      oldClassId;
+
+       oldClassId = entry_by_name->wait_event_info & WAIT_EVENT_CLASS_MASK;
+       if (oldClassId != classId)
+           ereport(ERROR,
+                   (errcode(ERRCODE_DUPLICATE_OBJECT),
+                    errmsg("wait event \"%s\" already exists in type \"%s\"",
+                           wait_event_name,
+                           pgstat_get_wait_event_type(entry_by_name->wait_event_info))));
+       return entry_by_name->wait_event_info;
+   }
 
    /*
     * Allocate and register a new wait event.  Recheck if the event name
@@ -189,113 +216,123 @@ WaitEventExtensionNew(const char *wait_event_name)
     * one with the same name since the LWLock acquired again here was
     * previously released.
     */
-   LWLockAcquire(WaitEventExtensionLock, LW_EXCLUSIVE);
-   entry_by_name = (WaitEventExtensionEntryByName *)
-       hash_search(WaitEventExtensionHashByName, wait_event_name,
+   LWLockAcquire(WaitEventCustomLock, LW_EXCLUSIVE);
+   entry_by_name = (WaitEventCustomEntryByName *)
+       hash_search(WaitEventCustomHashByName, wait_event_name,
                    HASH_FIND, &found);
    if (found)
    {
-       LWLockRelease(WaitEventExtensionLock);
-       return WAIT_EVENT_EXTENSION_INFO(entry_by_name->event_id);
+       uint32      oldClassId;
+
+       LWLockRelease(WaitEventCustomLock);
+       oldClassId = entry_by_name->wait_event_info & WAIT_EVENT_CLASS_MASK;
+       if (oldClassId != classId)
+           ereport(ERROR,
+                   (errcode(ERRCODE_DUPLICATE_OBJECT),
+                    errmsg("wait event \"%s\" already exists in type \"%s\"",
+                           wait_event_name,
+                           pgstat_get_wait_event_type(entry_by_name->wait_event_info))));
+       return entry_by_name->wait_event_info;
    }
 
    /* Allocate a new event Id */
-   SpinLockAcquire(&WaitEventExtensionCounter->mutex);
+   SpinLockAcquire(&WaitEventCustomCounter->mutex);
 
-   if (WaitEventExtensionCounter->nextId >= WAIT_EVENT_EXTENSION_HASH_MAX_SIZE)
+   if (WaitEventCustomCounter->nextId >= WAIT_EVENT_CUSTOM_HASH_MAX_SIZE)
    {
-       SpinLockRelease(&WaitEventExtensionCounter->mutex);
+       SpinLockRelease(&WaitEventCustomCounter->mutex);
        ereport(ERROR,
                errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-               errmsg("too many wait events for extensions"));
+               errmsg("too many custom wait events"));
    }
 
-   eventId = WaitEventExtensionCounter->nextId++;
+   eventId = WaitEventCustomCounter->nextId++;
 
-   SpinLockRelease(&WaitEventExtensionCounter->mutex);
+   SpinLockRelease(&WaitEventCustomCounter->mutex);
 
    /* Register the new wait event */
-   entry_by_id = (WaitEventExtensionEntryById *)
-       hash_search(WaitEventExtensionHashById, &eventId,
+   wait_event_info = classId | eventId;
+   entry_by_info = (WaitEventCustomEntryByInfo *)
+       hash_search(WaitEventCustomHashByInfo, &wait_event_info,
                    HASH_ENTER, &found);
    Assert(!found);
-   strlcpy(entry_by_id->wait_event_name, wait_event_name,
-           sizeof(entry_by_id->wait_event_name));
+   strlcpy(entry_by_info->wait_event_name, wait_event_name,
+           sizeof(entry_by_info->wait_event_name));
 
-   entry_by_name = (WaitEventExtensionEntryByName *)
-       hash_search(WaitEventExtensionHashByName, wait_event_name,
+   entry_by_name = (WaitEventCustomEntryByName *)
+       hash_search(WaitEventCustomHashByName, wait_event_name,
                    HASH_ENTER, &found);
    Assert(!found);
-   entry_by_name->event_id = eventId;
+   entry_by_name->wait_event_info = wait_event_info;
 
-   LWLockRelease(WaitEventExtensionLock);
+   LWLockRelease(WaitEventCustomLock);
 
-   return WAIT_EVENT_EXTENSION_INFO(eventId);
+   return wait_event_info;
 }
 
 /*
- * Return the name of an wait event ID for extension.
+ * Return the name of a custom wait event information.
  */
 static const char *
-GetWaitEventExtensionIdentifier(uint16 eventId)
+GetWaitEventCustomIdentifier(uint32 wait_event_info)
 {
    bool        found;
-   WaitEventExtensionEntryById *entry;
+   WaitEventCustomEntryByInfo *entry;
 
    /* Built-in event? */
-   if (eventId < WAIT_EVENT_EXTENSION_INITIAL_ID)
+   if (wait_event_info == PG_WAIT_EXTENSION)
        return "Extension";
 
    /* It is a user-defined wait event, so lookup hash table. */
-   LWLockAcquire(WaitEventExtensionLock, LW_SHARED);
-   entry = (WaitEventExtensionEntryById *)
-       hash_search(WaitEventExtensionHashById, &eventId,
+   LWLockAcquire(WaitEventCustomLock, LW_SHARED);
+   entry = (WaitEventCustomEntryByInfo *)
+       hash_search(WaitEventCustomHashByInfo, &wait_event_info,
                    HASH_FIND, &found);
-   LWLockRelease(WaitEventExtensionLock);
+   LWLockRelease(WaitEventCustomLock);
 
    if (!entry)
-       elog(ERROR, "could not find custom wait event name for ID %u",
-            eventId);
+       elog(ERROR,
+            "could not find custom name for wait event information %u",
+            wait_event_info);
 
    return entry->wait_event_name;
 }
 
 
 /*
- * Returns a list of currently defined custom wait event names for extensions.
- * The result is a palloc'd array, with the number of elements saved in
- * *nwaitevents.
+ * Returns a list of currently defined custom wait event names.  The result is
+ * a palloc'd array, with the number of elements saved in *nwaitevents.
  */
 char     **
-GetWaitEventExtensionNames(int *nwaitevents)
+GetWaitEventCustomNames(uint32 classId, int *nwaitevents)
 {
    char      **waiteventnames;
-   WaitEventExtensionEntryByName *hentry;
+   WaitEventCustomEntryByName *hentry;
    HASH_SEQ_STATUS hash_seq;
    int         index;
    int         els;
 
-   LWLockAcquire(WaitEventExtensionLock, LW_SHARED);
+   LWLockAcquire(WaitEventCustomLock, LW_SHARED);
 
    /* Now we can safely count the number of entries */
-   els = hash_get_num_entries(WaitEventExtensionHashByName);
+   els = hash_get_num_entries(WaitEventCustomHashByName);
 
    /* Allocate enough space for all entries */
    waiteventnames = palloc(els * sizeof(char *));
 
    /* Now scan the hash table to copy the data */
-   hash_seq_init(&hash_seq, WaitEventExtensionHashByName);
+   hash_seq_init(&hash_seq, WaitEventCustomHashByName);
 
    index = 0;
-   while ((hentry = (WaitEventExtensionEntryByName *) hash_seq_search(&hash_seq)) != NULL)
+   while ((hentry = (WaitEventCustomEntryByName *) hash_seq_search(&hash_seq)) != NULL)
    {
+       if ((hentry->wait_event_info & WAIT_EVENT_CLASS_MASK) != classId)
+           continue;
        waiteventnames[index] = pstrdup(hentry->wait_event_name);
        index++;
    }
 
-   LWLockRelease(WaitEventExtensionLock);
-
-   Assert(index == els);
+   LWLockRelease(WaitEventCustomLock);
 
    *nwaitevents = index;
    return waiteventnames;
@@ -374,6 +411,9 @@ pgstat_get_wait_event_type(uint32 wait_event_info)
        case PG_WAIT_IO:
            event_type = "IO";
            break;
+       case PG_WAIT_INJECTIONPOINT:
+           event_type = "InjectionPoint";
+           break;
        default:
            event_type = "???";
            break;
@@ -411,7 +451,8 @@ pgstat_get_wait_event(uint32 wait_event_info)
            event_name = GetLockNameFromTagType(eventId);
            break;
        case PG_WAIT_EXTENSION:
-           event_name = GetWaitEventExtensionIdentifier(eventId);
+       case PG_WAIT_INJECTIONPOINT:
+           event_name = GetWaitEventCustomIdentifier(wait_event_info);
            break;
        case PG_WAIT_BUFFERPIN:
            {
index ba244c2cf3678f801513c75c2e30d2ac019e09c3..fa8bc05c0c73f4d9934fff199dce5adbe4089189 100644 (file)
@@ -48,7 +48,7 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
 #define PG_GET_WAIT_EVENTS_COLS 3
    ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
    char      **waiteventnames;
-   int         nbextwaitevents;
+   int         nbwaitevents;
 
    /* Build tuplestore to hold the result rows */
    InitMaterializedSRF(fcinfo, 0);
@@ -67,9 +67,10 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
    }
 
    /* Handle custom wait events for extensions */
-   waiteventnames = GetWaitEventExtensionNames(&nbextwaitevents);
+   waiteventnames = GetWaitEventCustomNames(PG_WAIT_EXTENSION,
+                                            &nbwaitevents);
 
-   for (int idx = 0; idx < nbextwaitevents; idx++)
+   for (int idx = 0; idx < nbwaitevents; idx++)
    {
        StringInfoData buf;
        Datum       values[PG_GET_WAIT_EVENTS_COLS] = {0};
@@ -89,5 +90,29 @@ pg_get_wait_events(PG_FUNCTION_ARGS)
        tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
    }
 
+   /* Likewise for injection points */
+   waiteventnames = GetWaitEventCustomNames(PG_WAIT_INJECTIONPOINT,
+                                            &nbwaitevents);
+
+   for (int idx = 0; idx < nbwaitevents; idx++)
+   {
+       StringInfoData buf;
+       Datum       values[PG_GET_WAIT_EVENTS_COLS] = {0};
+       bool        nulls[PG_GET_WAIT_EVENTS_COLS] = {0};
+
+
+       values[0] = CStringGetTextDatum("InjectionPoint");
+       values[1] = CStringGetTextDatum(waiteventnames[idx]);
+
+       initStringInfo(&buf);
+       appendStringInfo(&buf,
+                        "Waiting for injection point \"%s\"",
+                        waiteventnames[idx]);
+
+       values[2] = CStringGetTextDatum(buf.data);
+
+       tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
+   }
+
    return (Datum) 0;
 }
index 87cbca28118c43a53cbae0b89fb59eb18230fbe8..db37beeaae6109e433491f9a03c156909bfbaef0 100644 (file)
@@ -340,7 +340,7 @@ LogicalRepWorker    "Waiting to read or update the state of logical replication wor
 XactTruncation "Waiting to execute <function>pg_xact_status</function> or update the oldest transaction ID available to it."
 WrapLimitsVacuum   "Waiting to update limits on transaction id and multixact consumption."
 NotifyQueueTail    "Waiting to update limit on <command>NOTIFY</command> message storage."
-WaitEventExtension "Waiting to read or update custom wait events information for extensions."
+WaitEventCustom    "Waiting to read or update custom wait events information."
 WALSummarizer  "Waiting to read or update WAL summarization state."
 DSMRegistry    "Waiting to read or update the dynamic shared memory registry."
 InjectionPoint "Waiting to read or update information related to injection points."
index 85f6568b9e4c227ec7deac5d3206cd115a63c73c..6a2f64c54fb5700719bc6a21369dbdf0b1406781 100644 (file)
@@ -78,7 +78,7 @@ PG_LWLOCK(44, XactTruncation)
 /* 45 was XactTruncationLock until removal of BackendRandomLock */
 PG_LWLOCK(46, WrapLimitsVacuum)
 PG_LWLOCK(47, NotifyQueueTail)
-PG_LWLOCK(48, WaitEventExtension)
+PG_LWLOCK(48, WaitEventCustom)
 PG_LWLOCK(49, WALSummarizer)
 PG_LWLOCK(50, DSMRegistry)
 PG_LWLOCK(51, InjectionPoint)
index 1b735d4a0e74cccdd202a2bf3c4780d00cc4b5af..9f18a753d47efef586be8844e5bf9ab408a7bb55 100644 (file)
@@ -24,6 +24,7 @@
 #define PG_WAIT_IPC                    0x08000000U
 #define PG_WAIT_TIMEOUT                0x09000000U
 #define PG_WAIT_IO                 0x0A000000U
+#define PG_WAIT_INJECTIONPOINT     0x0B000000U
 
 /* enums for wait events */
 #include "utils/wait_event_types.h"
@@ -38,26 +39,28 @@ extern void pgstat_reset_wait_event_storage(void);
 extern PGDLLIMPORT uint32 *my_wait_event_info;
 
 
-/* ----------
- * Wait Events - Extension
+/*
+ * Wait Events - Extension, InjectionPoint
  *
- * Use this category when the server process is waiting for some condition
- * defined by an extension module.
+ * Use InjectionPoint when the server process is waiting in an injection
+ * point.  Use Extension for other cases of the server process waiting for
+ * some condition defined by an extension module.
  *
- * Extensions can define their own wait events in this category.  They should
- * call WaitEventExtensionNew() with a wait event string.  If the wait event
- * associated to a string is already allocated, it returns the wait event
- * information to use.  If not, it gets one wait event ID allocated from
+ * Extensions can define their own wait events in these categories.  They
+ * should call one of these functions with a wait event string.  If the wait
+ * event associated to a string is already allocated, it returns the wait
+ * event information to use.  If not, it gets one wait event ID allocated from
  * a shared counter, associates the string to the ID in the shared dynamic
  * hash and returns the wait event information.
  *
  * The ID retrieved can be used with pgstat_report_wait_start() or equivalent.
  */
-extern void WaitEventExtensionShmemInit(void);
-extern Size WaitEventExtensionShmemSize(void);
-
 extern uint32 WaitEventExtensionNew(const char *wait_event_name);
-extern char **GetWaitEventExtensionNames(int *nwaitevents);
+extern uint32 WaitEventInjectionPointNew(const char *wait_event_name);
+
+extern void WaitEventCustomShmemInit(void);
+extern Size WaitEventCustomShmemSize(void);
+extern char **GetWaitEventCustomNames(uint32 classId, int *nwaitevents);
 
 /* ----------
  * pgstat_report_wait_start() -
index 5c44625d1d711122d8634288eece57c3cb4ff5a9..1b695a1820321f27a70b6e68144a31b5a0747a37 100644 (file)
@@ -216,7 +216,7 @@ injection_wait(const char *name, const void *private_data)
     * this custom wait event name is not released, but we don't care much for
     * testing as this should be short-lived.
     */
-   injection_wait_event = WaitEventExtensionNew(name);
+   injection_wait_event = WaitEventInjectionPointNew(name);
 
    /*
     * Find a free slot to wait for, and register this injection point's name.
index dbfd0c13d46f45f35bd7240a3702dafab3eeff81..2176a54bca1aec4fd66f31cafb7764965abb07c1 100644 (file)
@@ -158,9 +158,10 @@ select name, setting from pg_settings where name like 'enable%';
  enable_tidscan                 | on
 (22 rows)
 
--- There are always wait event descriptions for various types.
+-- There are always wait event descriptions for various types.  InjectionPoint
+-- may be present or absent, depending on history since last postmaster start.
 select type, count(*) > 0 as ok FROM pg_wait_events
-  group by type order by type COLLATE "C";
+  where type <> 'InjectionPoint' group by type order by type COLLATE "C";
    type    | ok 
 -----------+----
  Activity  | t
index c4f59ddc89a18561f9ffaabe1ff5eca20b4bcdb5..b047fb55e708bba1eb56dd15fd6dbf26a4899946 100644 (file)
@@ -70,9 +70,10 @@ select count(*) = 0 as ok from pg_stat_wal_receiver;
 -- a regression test run.
 select name, setting from pg_settings where name like 'enable%';
 
--- There are always wait event descriptions for various types.
+-- There are always wait event descriptions for various types.  InjectionPoint
+-- may be present or absent, depending on history since last postmaster start.
 select type, count(*) > 0 as ok FROM pg_wait_events
-  group by type order by type COLLATE "C";
+  where type <> 'InjectionPoint' group by type order by type COLLATE "C";
 
 -- Test that the pg_timezone_names and pg_timezone_abbrevs views are
 -- more-or-less working.  We can't test their contents in any great detail
index d90982466c5c9e7028cd381023221e91bc859a4c..82b3b411fb56eba053af32d29fb78f79bf572613 100644 (file)
@@ -3099,9 +3099,9 @@ WaitEvent
 WaitEventActivity
 WaitEventBufferPin
 WaitEventClient
-WaitEventExtensionCounterData
-WaitEventExtensionEntryById
-WaitEventExtensionEntryByName
+WaitEventCustomCounterData
+WaitEventCustomEntryByInfo
+WaitEventCustomEntryByName
 WaitEventIO
 WaitEventIPC
 WaitEventSet