@ -22,15 +22,18 @@
*/
*/
# include "postgres.h"
# include "postgres.h"
# include "miscadmin.h"
# include "port/pg_bitutils.h"
# include "storage/lmgr.h" /* for GetLockNameFromTagType */
# include "storage/lmgr.h" /* for GetLockNameFromTagType */
# include "storage/lwlock.h" /* for GetLWLockIdentifier */
# include "storage/lwlock.h" /* for GetLWLockIdentifier */
# include "storage/spin.h"
# include "utils/memutils.h"
# include "utils/wait_event.h"
# include "utils/wait_event.h"
static const char * pgstat_get_wait_activity ( WaitEventActivity w ) ;
static const char * pgstat_get_wait_activity ( WaitEventActivity w ) ;
static const char * pgstat_get_wait_bufferpin ( WaitEventBufferPin 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_client ( WaitEventClient w ) ;
static const char * pgstat_get_wait_extension ( WaitEventExtension w ) ;
static const char * pgstat_get_wait_ipc ( WaitEventIPC 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_timeout ( WaitEventTimeout w ) ;
static const char * pgstat_get_wait_io ( WaitEventIO w ) ;
static const char * pgstat_get_wait_io ( WaitEventIO w ) ;
@ -42,6 +45,169 @@ uint32 *my_wait_event_info = &local_my_wait_event_info;
# define WAIT_EVENT_CLASS_MASK 0xFF000000
# define WAIT_EVENT_CLASS_MASK 0xFF000000
# define WAIT_EVENT_ID_MASK 0x0000FFFF
# define WAIT_EVENT_ID_MASK 0x0000FFFF
/* dynamic allocation counter for custom wait events in extensions */
typedef struct WaitEventExtensionCounterData
{
int nextId ; /* next ID to assign */
slock_t mutex ; /* protects the counter */
} WaitEventExtensionCounterData ;
/* pointer to the shared memory */
static WaitEventExtensionCounterData * WaitEventExtensionCounter ;
/* first event ID of custom wait events for extensions */
# define NUM_BUILTIN_WAIT_EVENT_EXTENSION \
( WAIT_EVENT_EXTENSION_FIRST_USER_DEFINED - WAIT_EVENT_EXTENSION )
/*
* This is indexed by event ID minus NUM_BUILTIN_WAIT_EVENT_EXTENSION , and
* stores the names of all dynamically - created event IDs known to the current
* process . Any unused entries in the array will contain NULL .
*/
static const char * * WaitEventExtensionNames = NULL ;
static int WaitEventExtensionNamesAllocated = 0 ;
static const char * GetWaitEventExtensionIdentifier ( uint16 eventId ) ;
/*
* Return the space for dynamic allocation counter .
*/
Size
WaitEventExtensionShmemSize ( void )
{
return sizeof ( WaitEventExtensionCounterData ) ;
}
/*
* Allocate shmem space for dynamic allocation counter .
*/
void
WaitEventExtensionShmemInit ( void )
{
bool found ;
WaitEventExtensionCounter = ( WaitEventExtensionCounterData * )
ShmemInitStruct ( " WaitEventExtensionCounterData " ,
WaitEventExtensionShmemSize ( ) , & found ) ;
if ( ! found )
{
/* initialize the allocation counter and its spinlock. */
WaitEventExtensionCounter - > nextId = NUM_BUILTIN_WAIT_EVENT_EXTENSION ;
SpinLockInit ( & WaitEventExtensionCounter - > mutex ) ;
}
}
/*
* Allocate a new event ID and return the wait event .
*/
uint32
WaitEventExtensionNew ( void )
{
uint16 eventId ;
Assert ( LWLockHeldByMeInMode ( AddinShmemInitLock , LW_EXCLUSIVE ) ) ;
SpinLockAcquire ( & WaitEventExtensionCounter - > mutex ) ;
if ( WaitEventExtensionCounter - > nextId > PG_UINT16_MAX )
{
SpinLockRelease ( & WaitEventExtensionCounter - > mutex ) ;
ereport ( ERROR ,
errcode ( ERRCODE_PROGRAM_LIMIT_EXCEEDED ) ,
errmsg ( " too many wait events for extensions " ) ) ;
}
eventId = WaitEventExtensionCounter - > nextId + + ;
SpinLockRelease ( & WaitEventExtensionCounter - > mutex ) ;
return PG_WAIT_EXTENSION | eventId ;
}
/*
* Register a dynamic wait event name for extension in the lookup table
* of the current process .
*
* This routine will save a pointer to the wait event name passed as an argument ,
* so the name should be allocated in a backend - lifetime context
* ( shared memory , TopMemoryContext , static constant , or similar ) .
*
* The " wait_event_name " will be user - visible as a wait event name , so try to
* use a name that fits the style for those .
*/
void
WaitEventExtensionRegisterName ( uint32 wait_event_info ,
const char * wait_event_name )
{
uint32 classId ;
uint16 eventId ;
classId = wait_event_info & WAIT_EVENT_CLASS_MASK ;
eventId = wait_event_info & WAIT_EVENT_ID_MASK ;
/* Check the wait event class. */
if ( classId ! = PG_WAIT_EXTENSION )
ereport ( ERROR ,
errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " invalid wait event class %u " , classId ) ) ;
/* This should only be called for user-defined wait event. */
if ( eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION )
ereport ( ERROR ,
errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " invalid wait event ID %u " , eventId ) ) ;
/* Convert to array index. */
eventId - = NUM_BUILTIN_WAIT_EVENT_EXTENSION ;
/* If necessary, create or enlarge array. */
if ( eventId > = WaitEventExtensionNamesAllocated )
{
uint32 newalloc ;
newalloc = pg_nextpower2_32 ( Max ( 8 , eventId + 1 ) ) ;
if ( WaitEventExtensionNames = = NULL )
WaitEventExtensionNames = ( const char * * )
MemoryContextAllocZero ( TopMemoryContext ,
newalloc * sizeof ( char * ) ) ;
else
WaitEventExtensionNames =
repalloc0_array ( WaitEventExtensionNames , const char * ,
WaitEventExtensionNamesAllocated , newalloc ) ;
WaitEventExtensionNamesAllocated = newalloc ;
}
WaitEventExtensionNames [ eventId ] = wait_event_name ;
}
/*
* Return the name of an wait event ID for extension .
*/
static const char *
GetWaitEventExtensionIdentifier ( uint16 eventId )
{
/* Built-in event? */
if ( eventId < NUM_BUILTIN_WAIT_EVENT_EXTENSION )
return " Extension " ;
/*
* It is a user - defined wait event , so look at WaitEventExtensionNames [ ] .
* However , it is possible that the name has never been registered by
* calling WaitEventExtensionRegisterName ( ) in the current process , in
* which case give up and return " extension " .
*/
eventId - = NUM_BUILTIN_WAIT_EVENT_EXTENSION ;
if ( eventId > = WaitEventExtensionNamesAllocated | |
WaitEventExtensionNames [ eventId ] = = NULL )
return " extension " ;
return WaitEventExtensionNames [ eventId ] ;
}
/*
/*
* Configure wait event reporting to report wait events to * wait_event_info .
* 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 ( )
* * 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)
case PG_WAIT_LOCK :
case PG_WAIT_LOCK :
event_name = GetLockNameFromTagType ( eventId ) ;
event_name = GetLockNameFromTagType ( eventId ) ;
break ;
break ;
case PG_WAIT_EXTENSION :
event_name = GetWaitEventExtensionIdentifier ( eventId ) ;
break ;
case PG_WAIT_BUFFERPIN :
case PG_WAIT_BUFFERPIN :
{
{
WaitEventBufferPin w = ( WaitEventBufferPin ) wait_event_info ;
WaitEventBufferPin w = ( WaitEventBufferPin ) wait_event_info ;
@ -172,13 +341,6 @@ pgstat_get_wait_event(uint32 wait_event_info)
event_name = pgstat_get_wait_client ( w ) ;
event_name = pgstat_get_wait_client ( w ) ;
break ;
break ;
}
}
case PG_WAIT_EXTENSION :
{
WaitEventExtension w = ( WaitEventExtension ) wait_event_info ;
event_name = pgstat_get_wait_extension ( w ) ;
break ;
}
case PG_WAIT_IPC :
case PG_WAIT_IPC :
{
{
WaitEventIPC w = ( WaitEventIPC ) wait_event_info ;
WaitEventIPC w = ( WaitEventIPC ) wait_event_info ;