Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  wait_event.c

  Sprache: C
 

/* ----------
 * wait_event.c
 *   Wait event reporting infrastructure.
 *
 * Copyright (c) 2001-2025, PostgreSQL Global Development Group
 *
 *
 * IDENTIFICATION
 *   src/backend/utils/activity/wait_event.c
 *
 * NOTES
 *
 * To make pgstat_report_wait_start() and pgstat_report_wait_end() as
 * lightweight as possible, they do not check if shared memory (MyProc
 * specifically, where the wait event is stored) is already available. Instead
 * we initially set my_wait_event_info to a process local variable, which then
 * is redirected to shared memory using pgstat_set_wait_event_storage(). For
 * the same reason pgstat_track_activities is not checked - the check adds
 * more work than it saves.
 *
 * ----------
 */

#include "postgres.h"

#include "storage/lmgr.h"  /* for GetLockNameFromTagType */
#include "storage/lwlock.h"  /* for GetLWLockIdentifier */
#include "storage/spin.h"
#include "utils/wait_event.h"


static const char *pgstat_get_wait_activity(WaitEventActivity w);
static const char *pgstat_get_wait_bufferpin(WaitEventBufferPin w);
static const char *pgstat_get_wait_client(WaitEventClient w);
static const char *pgstat_get_wait_ipc(WaitEventIPC w);
static const char *pgstat_get_wait_timeout(WaitEventTimeout w);
static const char *pgstat_get_wait_io(WaitEventIO w);


static uint32 local_my_wait_event_info;
uint32    *my_wait_event_info = &local_my_wait_event_info;

#define WAIT_EVENT_CLASS_MASK 0xFF000000
#define WAIT_EVENT_ID_MASK  0x0000FFFF

/*
 * Hash tables for storing custom wait event ids and their names in
 * shared memory.
 *
 * WaitEventCustomHashByInfo is used to find the name from wait event
 * information.  Any backend can search it to find custom wait events.
 *
 * 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_CUSTOM_HASH_INIT_SIZE is enough for most cases, and it seems
 * unlikely that the number of entries will reach
 * WAIT_EVENT_CUSTOM_HASH_MAX_SIZE.
 */

static HTAB *WaitEventCustomHashByInfo; /* find names from infos */
static HTAB *WaitEventCustomHashByName; /* find infos from names */

#define WAIT_EVENT_CUSTOM_HASH_INIT_SIZE 16
#define WAIT_EVENT_CUSTOM_HASH_MAX_SIZE 128

/* hash table entries */
typedef struct WaitEventCustomEntryByInfo
{
 uint32  wait_event_info; /* hash key */
 char  wait_event_name[NAMEDATALEN]; /* custom wait event name */
} WaitEventCustomEntryByInfo;

typedef struct WaitEventCustomEntryByName
{
 char  wait_event_name[NAMEDATALEN]; /* hash key */
 uint32  wait_event_info;
} WaitEventCustomEntryByName;


/* dynamic allocation counter for custom wait events */
typedef struct WaitEventCustomCounterData
{
 int   nextId;   /* next ID to assign */
 slock_t  mutex;   /* protects the counter */
} WaitEventCustomCounterData;

/* pointer to the shared memory */
static WaitEventCustomCounterData *WaitEventCustomCounter;

/* first event ID of custom wait events */
#define WAIT_EVENT_CUSTOM_INITIAL_ID 1

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
WaitEventCustomShmemSize(void)
{
 Size  sz;

 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;
}

/*
 * Allocate shmem space for dynamic shared hash and dynamic allocation counter.
 */

void
WaitEventCustomShmemInit(void)
{
 bool  found;
 HASHCTL  info;

 WaitEventCustomCounter = (WaitEventCustomCounterData *)
  ShmemInitStruct("WaitEventCustomCounterData",
      sizeof(WaitEventCustomCounterData), &found);

 if (!found)
 {
  /* initialize the allocation counter and its spinlock. */
  WaitEventCustomCounter->nextId = WAIT_EVENT_CUSTOM_INITIAL_ID;
  SpinLockInit(&WaitEventCustomCounter->mutex);
 }

 /* initialize or attach the hash tables to store custom wait events */
 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(WaitEventCustomEntryByName);
 WaitEventCustomHashByName =
  ShmemInitHash("WaitEventCustom hash by name",
       WAIT_EVENT_CUSTOM_HASH_INIT_SIZE,
       WAIT_EVENT_CUSTOM_HASH_MAX_SIZE,
       &info,
       HASH_ELEM | HASH_STRINGS);
}

/*
 * Allocate a new event ID and return the wait event info.
 *
 * If the wait event name is already defined, this does not allocate a new
 * entry; it returns the wait event information associated to the name.
 */

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;
 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)
  elog(ERROR,
    "cannot use custom wait event string longer than %u characters",
    NAMEDATALEN - 1);

 /*
  * Check if the wait event info associated to the name is already defined,
  * and return it if so.
 */

 LWLockAcquire(WaitEventCustomLock, LW_SHARED);
 entry_by_name = (WaitEventCustomEntryByName *)
  hash_search(WaitEventCustomHashByName, wait_event_name,
     HASH_FIND, &found);
 LWLockRelease(WaitEventCustomLock);
 if (found)
 {
  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
  * exists, as it could be possible that a concurrent process has inserted
  * one with the same name since the LWLock acquired again here was
  * previously released.
 */

 LWLockAcquire(WaitEventCustomLock, LW_EXCLUSIVE);
 entry_by_name = (WaitEventCustomEntryByName *)
  hash_search(WaitEventCustomHashByName, wait_event_name,
     HASH_FIND, &found);
 if (found)
 {
  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(&WaitEventCustomCounter->mutex);

 if (WaitEventCustomCounter->nextId >= WAIT_EVENT_CUSTOM_HASH_MAX_SIZE)
 {
  SpinLockRelease(&WaitEventCustomCounter->mutex);
  ereport(ERROR,
    errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
    errmsg("too many custom wait events"));
 }

 eventId = WaitEventCustomCounter->nextId++;

 SpinLockRelease(&WaitEventCustomCounter->mutex);

 /* Register the new wait event */
 wait_event_info = classId | eventId;
 entry_by_info = (WaitEventCustomEntryByInfo *)
  hash_search(WaitEventCustomHashByInfo, &wait_event_info,
     HASH_ENTER, &found);
 Assert(!found);
 strlcpy(entry_by_info->wait_event_name, wait_event_name,
   sizeof(entry_by_info->wait_event_name));

 entry_by_name = (WaitEventCustomEntryByName *)
  hash_search(WaitEventCustomHashByName, wait_event_name,
     HASH_ENTER, &found);
 Assert(!found);
 entry_by_name->wait_event_info = wait_event_info;

 LWLockRelease(WaitEventCustomLock);

 return wait_event_info;
}

/*
 * Return the name of a custom wait event information.
 */

static const char *
GetWaitEventCustomIdentifier(uint32 wait_event_info)
{
 bool  found;
 WaitEventCustomEntryByInfo *entry;

 /* Built-in event? */
 if (wait_event_info == PG_WAIT_EXTENSION)
  return "Extension";

 /* It is a user-defined wait event, so lookup hash table. */
 LWLockAcquire(WaitEventCustomLock, LW_SHARED);
 entry = (WaitEventCustomEntryByInfo *)
  hash_search(WaitEventCustomHashByInfo, &wait_event_info,
     HASH_FIND, &found);
 LWLockRelease(WaitEventCustomLock);

 if (!entry)
  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.  The result is
 * a palloc'd array, with the number of elements saved in *nwaitevents.
 */

char   **
GetWaitEventCustomNames(uint32 classId, int *nwaitevents)
{
 char   **waiteventnames;
 WaitEventCustomEntryByName *hentry;
 HASH_SEQ_STATUS hash_seq;
 int   index;
 int   els;

 LWLockAcquire(WaitEventCustomLock, LW_SHARED);

 /* Now we can safely count the number of entries */
 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, WaitEventCustomHashByName);

 index = 0;
 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(WaitEventCustomLock);

 *nwaitevents = index;
 return waiteventnames;
}

/*
 * Configure wait event reporting to report wait events to *wait_event_info.
 * *wait_event_info needs to be valid until pgstat_reset_wait_event_storage()
 * is called.
 *
 * Expected to be called during backend startup, to point my_wait_event_info
 * into shared memory.
 */

void
pgstat_set_wait_event_storage(uint32 *wait_event_info)
{
 my_wait_event_info = wait_event_info;
}

/*
 * Reset wait event storage location.
 *
 * Expected to be called during backend shutdown, before the location set up
 * pgstat_set_wait_event_storage() becomes invalid.
 */

void
pgstat_reset_wait_event_storage(void)
{
 my_wait_event_info = &local_my_wait_event_info;
}

/* ----------
 * pgstat_get_wait_event_type() -
 *
 * Return a string representing the current wait event type, backend is
 * waiting on.
 */

const char *
pgstat_get_wait_event_type(uint32 wait_event_info)
{
 uint32  classId;
 const char *event_type;

 /* report process as not waiting. */
 if (wait_event_info == 0)
  return NULL;

 classId = wait_event_info & WAIT_EVENT_CLASS_MASK;

 switch (classId)
 {
  case PG_WAIT_LWLOCK:
   event_type = "LWLock";
   break;
  case PG_WAIT_LOCK:
   event_type = "Lock";
   break;
  case PG_WAIT_BUFFERPIN:
   event_type = "BufferPin";
   break;
  case PG_WAIT_ACTIVITY:
   event_type = "Activity";
   break;
  case PG_WAIT_CLIENT:
   event_type = "Client";
   break;
  case PG_WAIT_EXTENSION:
   event_type = "Extension";
   break;
  case PG_WAIT_IPC:
   event_type = "IPC";
   break;
  case PG_WAIT_TIMEOUT:
   event_type = "Timeout";
   break;
  case PG_WAIT_IO:
   event_type = "IO";
   break;
  case PG_WAIT_INJECTIONPOINT:
   event_type = "InjectionPoint";
   break;
  default:
   event_type = "???";
   break;
 }

 return event_type;
}

/* ----------
 * pgstat_get_wait_event() -
 *
 * Return a string representing the current wait event, backend is
 * waiting on.
 */

const char *
pgstat_get_wait_event(uint32 wait_event_info)
{
 uint32  classId;
 uint16  eventId;
 const char *event_name;

 /* report process as not waiting. */
 if (wait_event_info == 0)
  return NULL;

 classId = wait_event_info & WAIT_EVENT_CLASS_MASK;
 eventId = wait_event_info & WAIT_EVENT_ID_MASK;

 switch (classId)
 {
  case PG_WAIT_LWLOCK:
   event_name = GetLWLockIdentifier(classId, eventId);
   break;
  case PG_WAIT_LOCK:
   event_name = GetLockNameFromTagType(eventId);
   break;
  case PG_WAIT_EXTENSION:
  case PG_WAIT_INJECTIONPOINT:
   event_name = GetWaitEventCustomIdentifier(wait_event_info);
   break;
  case PG_WAIT_BUFFERPIN:
   {
    WaitEventBufferPin w = (WaitEventBufferPin) wait_event_info;

    event_name = pgstat_get_wait_bufferpin(w);
    break;
   }
  case PG_WAIT_ACTIVITY:
   {
    WaitEventActivity w = (WaitEventActivity) wait_event_info;

    event_name = pgstat_get_wait_activity(w);
    break;
   }
  case PG_WAIT_CLIENT:
   {
    WaitEventClient w = (WaitEventClient) wait_event_info;

    event_name = pgstat_get_wait_client(w);
    break;
   }
  case PG_WAIT_IPC:
   {
    WaitEventIPC w = (WaitEventIPC) wait_event_info;

    event_name = pgstat_get_wait_ipc(w);
    break;
   }
  case PG_WAIT_TIMEOUT:
   {
    WaitEventTimeout w = (WaitEventTimeout) wait_event_info;

    event_name = pgstat_get_wait_timeout(w);
    break;
   }
  case PG_WAIT_IO:
   {
    WaitEventIO w = (WaitEventIO) wait_event_info;

    event_name = pgstat_get_wait_io(w);
    break;
   }
  default:
   event_name = "unknown wait event";
   break;
 }

 return event_name;
}

#include "utils/pgstat_wait_event.c"

Messung V0.5 in Prozent
C=91 H=95 G=92

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002