Commit 29c3e2dd authored by Tom Lane's avatar Tom Lane

Collect built-in LWLock tranche names statically, not dynamically.

There is little point in using the LWLockRegisterTranche mechanism for
built-in tranche names.  It wastes cycles, it creates opportunities for
bugs (since failing to register a tranche name is a very hard-to-detect
problem), and the lack of any centralized list of names encourages
sloppy nonconformity in name choices.  Moreover, since we have a
centralized list of the tranches anyway in enum BuiltinTrancheIds, we're
certainly not buying any flexibility in return for these disadvantages.

Hence, nuke all the backend-internal LWLockRegisterTranche calls,
and instead provide a const array of the builtin tranche names.

(I have in mind to change a bunch of these names shortly, but this
patch is just about getting them into one place.)

Discussion: https://postgr.es/m/9056.1589419765@sss.pgh.pa.us
parent 07451e1f
...@@ -235,9 +235,6 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, ...@@ -235,9 +235,6 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
else else
Assert(found); Assert(found);
/* Register SLRU tranche in the main tranches array */
LWLockRegisterTranche(tranche_id, name);
/* /*
* Initialize the unshared control struct, including directory path. We * Initialize the unshared control struct, including directory path. We
* assume caller set PagePrecedes. * assume caller set PagePrecedes.
......
...@@ -5116,10 +5116,8 @@ XLOGShmemInit(void) ...@@ -5116,10 +5116,8 @@ XLOGShmemInit(void)
/* both should be present or neither */ /* both should be present or neither */
Assert(foundCFile && foundXLog); Assert(foundCFile && foundXLog);
/* Initialize local copy of WALInsertLocks and register the tranche */ /* Initialize local copy of WALInsertLocks */
WALInsertLocks = XLogCtl->Insert.WALInsertLocks; WALInsertLocks = XLogCtl->Insert.WALInsertLocks;
LWLockRegisterTranche(LWTRANCHE_WAL_INSERT,
"wal_insert");
if (localControlFile) if (localControlFile)
pfree(localControlFile); pfree(localControlFile);
...@@ -5155,7 +5153,6 @@ XLOGShmemInit(void) ...@@ -5155,7 +5153,6 @@ XLOGShmemInit(void)
(WALInsertLockPadded *) allocptr; (WALInsertLockPadded *) allocptr;
allocptr += sizeof(WALInsertLockPadded) * NUM_XLOGINSERT_LOCKS; allocptr += sizeof(WALInsertLockPadded) * NUM_XLOGINSERT_LOCKS;
LWLockRegisterTranche(LWTRANCHE_WAL_INSERT, "wal_insert");
for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++) for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
{ {
LWLockInitialize(&WALInsertLocks[i].l.lock, LWTRANCHE_WAL_INSERT); LWLockInitialize(&WALInsertLocks[i].l.lock, LWTRANCHE_WAL_INSERT);
......
...@@ -517,9 +517,6 @@ ReplicationOriginShmemInit(void) ...@@ -517,9 +517,6 @@ ReplicationOriginShmemInit(void)
ConditionVariableInit(&replication_states[i].origin_cv); ConditionVariableInit(&replication_states[i].origin_cv);
} }
} }
LWLockRegisterTranche(replication_states_ctl->tranche_id,
"replication_origin");
} }
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
......
...@@ -140,9 +140,6 @@ ReplicationSlotsShmemInit(void) ...@@ -140,9 +140,6 @@ ReplicationSlotsShmemInit(void)
ShmemInitStruct("ReplicationSlot Ctl", ReplicationSlotsShmemSize(), ShmemInitStruct("ReplicationSlot Ctl", ReplicationSlotsShmemSize(),
&found); &found);
LWLockRegisterTranche(LWTRANCHE_REPLICATION_SLOT_IO_IN_PROGRESS,
"replication_slot_io");
if (!found) if (!found)
{ {
int i; int i;
......
...@@ -87,9 +87,6 @@ InitBufferPool(void) ...@@ -87,9 +87,6 @@ InitBufferPool(void)
NBuffers * (Size) sizeof(LWLockMinimallyPadded), NBuffers * (Size) sizeof(LWLockMinimallyPadded),
&foundIOLocks); &foundIOLocks);
LWLockRegisterTranche(LWTRANCHE_BUFFER_IO_IN_PROGRESS, "buffer_io");
LWLockRegisterTranche(LWTRANCHE_BUFFER_CONTENT, "buffer_content");
/* /*
* The array used to sort to-be-checkpointed buffer ids is located in * The array used to sort to-be-checkpointed buffer ids is located in
* shared memory, to avoid having to allocate significant amounts of * shared memory, to avoid having to allocate significant amounts of
......
...@@ -267,8 +267,6 @@ CreateSharedProcArray(void) ...@@ -267,8 +267,6 @@ CreateSharedProcArray(void)
mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS), mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
&found); &found);
} }
LWLockRegisterTranche(LWTRANCHE_PROC, "proc");
} }
/* /*
......
...@@ -108,14 +108,85 @@ extern slock_t *ShmemLock; ...@@ -108,14 +108,85 @@ extern slock_t *ShmemLock;
#define LW_SHARED_MASK ((uint32) ((1 << 24)-1)) #define LW_SHARED_MASK ((uint32) ((1 << 24)-1))
/* /*
* This is indexed by tranche ID and stores the names of all tranches known * There are three sorts of LWLock "tranches":
* to the current backend. *
*/ * 1. The individually-named locks defined in lwlocknames.h each have their
static const char **LWLockTrancheArray = NULL; * own tranche. The names of these tranches appear in MainLWLockNames[]
static int LWLockTranchesAllocated = 0; * in lwlocknames.c.
*
* 2. There are some predefined tranches for built-in groups of locks.
* These are listed in enum BuiltinTrancheIds in lwlock.h, and their names
* appear in BuiltinTrancheNames[] below.
*
* 3. Extensions can create new tranches, via either RequestNamedLWLockTranche
* or LWLockRegisterTranche. The names of these that are known in the current
* process appear in LWLockTrancheNames[].
*/
static const char *const BuiltinTrancheNames[] = {
/* LWTRANCHE_CLOG_BUFFERS: */
"clog",
/* LWTRANCHE_COMMITTS_BUFFERS: */
"commit_timestamp",
/* LWTRANCHE_SUBTRANS_BUFFERS: */
"subtrans",
/* LWTRANCHE_MXACTOFFSET_BUFFERS: */
"multixact_offset",
/* LWTRANCHE_MXACTMEMBER_BUFFERS: */
"multixact_member",
/* LWTRANCHE_ASYNC_BUFFERS: */
"async",
/* LWTRANCHE_OLDSERXID_BUFFERS: */
"oldserxid",
/* LWTRANCHE_WAL_INSERT: */
"wal_insert",
/* LWTRANCHE_BUFFER_CONTENT: */
"buffer_content",
/* LWTRANCHE_BUFFER_IO_IN_PROGRESS: */
"buffer_io",
/* LWTRANCHE_REPLICATION_ORIGIN: */
"replication_origin",
/* LWTRANCHE_REPLICATION_SLOT_IO_IN_PROGRESS: */
"replication_slot_io",
/* LWTRANCHE_PROC: */
"proc",
/* LWTRANCHE_BUFFER_MAPPING: */
"buffer_mapping",
/* LWTRANCHE_LOCK_MANAGER: */
"lock_manager",
/* LWTRANCHE_PREDICATE_LOCK_MANAGER: */
"predicate_lock_manager",
/* LWTRANCHE_PARALLEL_HASH_JOIN: */
"parallel_hash_join",
/* LWTRANCHE_PARALLEL_QUERY_DSA: */
"parallel_query_dsa",
/* LWTRANCHE_SESSION_DSA: */
"session_dsa",
/* LWTRANCHE_SESSION_RECORD_TABLE: */
"session_record_table",
/* LWTRANCHE_SESSION_TYPMOD_TABLE: */
"session_typmod_table",
/* LWTRANCHE_SHARED_TUPLESTORE: */
"shared_tuplestore",
/* LWTRANCHE_TBM: */
"tbm",
/* LWTRANCHE_PARALLEL_APPEND: */
"parallel_append",
/* LWTRANCHE_SXACT: */
"serializable_xact"
};
StaticAssertDecl(lengthof(BuiltinTrancheNames) ==
LWTRANCHE_FIRST_USER_DEFINED - NUM_INDIVIDUAL_LWLOCKS,
"missing entries in BuiltinTrancheNames[]");
#define T_NAME(lock) \ /*
(LWLockTrancheArray[(lock)->tranche]) * This is indexed by tranche ID minus LWTRANCHE_FIRST_USER_DEFINED, and
* stores the names of all dynamically-created tranches known to the current
* process. Any unused entries in the array will contain NULL.
*/
static const char **LWLockTrancheNames = NULL;
static int LWLockTrancheNamesAllocated = 0;
/* /*
* This points to the main array of LWLocks in shared memory. Backends inherit * This points to the main array of LWLocks in shared memory. Backends inherit
...@@ -149,19 +220,29 @@ typedef struct NamedLWLockTrancheRequest ...@@ -149,19 +220,29 @@ typedef struct NamedLWLockTrancheRequest
int num_lwlocks; int num_lwlocks;
} NamedLWLockTrancheRequest; } NamedLWLockTrancheRequest;
NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL; static NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL;
static int NamedLWLockTrancheRequestsAllocated = 0; static int NamedLWLockTrancheRequestsAllocated = 0;
/*
* NamedLWLockTrancheRequests is both the valid length of the request array,
* and the length of the shared-memory NamedLWLockTrancheArray later on.
* This variable and NamedLWLockTrancheArray are non-static so that
* postmaster.c can copy them to child processes in EXEC_BACKEND builds.
*/
int NamedLWLockTrancheRequests = 0; int NamedLWLockTrancheRequests = 0;
/* points to data in shared memory: */
NamedLWLockTranche *NamedLWLockTrancheArray = NULL; NamedLWLockTranche *NamedLWLockTrancheArray = NULL;
static bool lock_named_request_allowed = true; static bool lock_named_request_allowed = true;
static void InitializeLWLocks(void); static void InitializeLWLocks(void);
static void RegisterLWLockTranches(void);
static inline void LWLockReportWaitStart(LWLock *lock); static inline void LWLockReportWaitStart(LWLock *lock);
static inline void LWLockReportWaitEnd(void); static inline void LWLockReportWaitEnd(void);
static const char *GetLWTrancheName(uint16 trancheId);
#define T_NAME(lock) \
GetLWTrancheName((lock)->tranche)
#ifdef LWLOCK_STATS #ifdef LWLOCK_STATS
typedef struct lwlock_stats_key typedef struct lwlock_stats_key
...@@ -285,7 +366,7 @@ print_lwlock_stats(int code, Datum arg) ...@@ -285,7 +366,7 @@ print_lwlock_stats(int code, Datum arg)
{ {
fprintf(stderr, fprintf(stderr,
"PID %d lwlock %s %p: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n", "PID %d lwlock %s %p: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n",
MyProcPid, LWLockTrancheArray[lwstats->key.tranche], MyProcPid, GetLWTrancheName(lwstats->key.tranche),
lwstats->key.instance, lwstats->sh_acquire_count, lwstats->key.instance, lwstats->sh_acquire_count,
lwstats->ex_acquire_count, lwstats->block_count, lwstats->ex_acquire_count, lwstats->block_count,
lwstats->spin_delay_count, lwstats->dequeue_self_count); lwstats->spin_delay_count, lwstats->dequeue_self_count);
...@@ -332,7 +413,7 @@ get_lwlock_stats_entry(LWLock *lock) ...@@ -332,7 +413,7 @@ get_lwlock_stats_entry(LWLock *lock)
* allocated in the main array. * allocated in the main array.
*/ */
static int static int
NumLWLocksByNamedTranches(void) NumLWLocksForNamedTranches(void)
{ {
int numLocks = 0; int numLocks = 0;
int i; int i;
...@@ -353,7 +434,8 @@ LWLockShmemSize(void) ...@@ -353,7 +434,8 @@ LWLockShmemSize(void)
int i; int i;
int numLocks = NUM_FIXED_LWLOCKS; int numLocks = NUM_FIXED_LWLOCKS;
numLocks += NumLWLocksByNamedTranches(); /* Calculate total number of locks needed in the main array. */
numLocks += NumLWLocksForNamedTranches();
/* Space for the LWLock array. */ /* Space for the LWLock array. */
size = mul_size(numLocks, sizeof(LWLockPadded)); size = mul_size(numLocks, sizeof(LWLockPadded));
...@@ -368,7 +450,7 @@ LWLockShmemSize(void) ...@@ -368,7 +450,7 @@ LWLockShmemSize(void)
for (i = 0; i < NamedLWLockTrancheRequests; i++) for (i = 0; i < NamedLWLockTrancheRequests; i++)
size = add_size(size, strlen(NamedLWLockTrancheRequestArray[i].tranche_name) + 1); size = add_size(size, strlen(NamedLWLockTrancheRequestArray[i].tranche_name) + 1);
/* Disallow named LWLocks' requests after startup */ /* Disallow adding any more named tranches. */
lock_named_request_allowed = false; lock_named_request_allowed = false;
return size; return size;
...@@ -376,7 +458,7 @@ LWLockShmemSize(void) ...@@ -376,7 +458,7 @@ LWLockShmemSize(void)
/* /*
* Allocate shmem space for the main LWLock array and all tranches and * Allocate shmem space for the main LWLock array and all tranches and
* initialize it. We also register all the LWLock tranches here. * initialize it. We also register extension LWLock tranches here.
*/ */
void void
CreateLWLocks(void) CreateLWLocks(void)
...@@ -416,8 +498,10 @@ CreateLWLocks(void) ...@@ -416,8 +498,10 @@ CreateLWLocks(void)
InitializeLWLocks(); InitializeLWLocks();
} }
/* Register all LWLock tranches */ /* Register named extension LWLock tranches in the current process. */
RegisterLWLockTranches(); for (int i = 0; i < NamedLWLockTrancheRequests; i++)
LWLockRegisterTranche(NamedLWLockTrancheArray[i].trancheId,
NamedLWLockTrancheArray[i].trancheName);
} }
/* /*
...@@ -426,7 +510,7 @@ CreateLWLocks(void) ...@@ -426,7 +510,7 @@ CreateLWLocks(void)
static void static void
InitializeLWLocks(void) InitializeLWLocks(void)
{ {
int numNamedLocks = NumLWLocksByNamedTranches(); int numNamedLocks = NumLWLocksForNamedTranches();
int id; int id;
int i; int i;
int j; int j;
...@@ -452,7 +536,10 @@ InitializeLWLocks(void) ...@@ -452,7 +536,10 @@ InitializeLWLocks(void)
for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++, lock++) for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++, lock++)
LWLockInitialize(&lock->lock, LWTRANCHE_PREDICATE_LOCK_MANAGER); LWLockInitialize(&lock->lock, LWTRANCHE_PREDICATE_LOCK_MANAGER);
/* Initialize named tranches. */ /*
* Copy the info about any named tranches into shared memory (so that
* other processes can see it), and initialize the requested LWLocks.
*/
if (NamedLWLockTrancheRequests > 0) if (NamedLWLockTrancheRequests > 0)
{ {
char *trancheNames; char *trancheNames;
...@@ -485,51 +572,6 @@ InitializeLWLocks(void) ...@@ -485,51 +572,6 @@ InitializeLWLocks(void)
} }
} }
/*
* Register named tranches and tranches for fixed LWLocks.
*/
static void
RegisterLWLockTranches(void)
{
int i;
if (LWLockTrancheArray == NULL)
{
LWLockTranchesAllocated = 128;
LWLockTrancheArray = (const char **)
MemoryContextAllocZero(TopMemoryContext,
LWLockTranchesAllocated * sizeof(char *));
Assert(LWLockTranchesAllocated >= LWTRANCHE_FIRST_USER_DEFINED);
}
for (i = 0; i < NUM_INDIVIDUAL_LWLOCKS; ++i)
LWLockRegisterTranche(i, MainLWLockNames[i]);
LWLockRegisterTranche(LWTRANCHE_BUFFER_MAPPING, "buffer_mapping");
LWLockRegisterTranche(LWTRANCHE_LOCK_MANAGER, "lock_manager");
LWLockRegisterTranche(LWTRANCHE_PREDICATE_LOCK_MANAGER,
"predicate_lock_manager");
LWLockRegisterTranche(LWTRANCHE_PARALLEL_QUERY_DSA,
"parallel_query_dsa");
LWLockRegisterTranche(LWTRANCHE_SESSION_DSA,
"session_dsa");
LWLockRegisterTranche(LWTRANCHE_SESSION_RECORD_TABLE,
"session_record_table");
LWLockRegisterTranche(LWTRANCHE_SESSION_TYPMOD_TABLE,
"session_typmod_table");
LWLockRegisterTranche(LWTRANCHE_SHARED_TUPLESTORE,
"shared_tuplestore");
LWLockRegisterTranche(LWTRANCHE_TBM, "tbm");
LWLockRegisterTranche(LWTRANCHE_PARALLEL_APPEND, "parallel_append");
LWLockRegisterTranche(LWTRANCHE_PARALLEL_HASH_JOIN, "parallel_hash_join");
LWLockRegisterTranche(LWTRANCHE_SXACT, "serializable_xact");
/* Register named tranches. */
for (i = 0; i < NamedLWLockTrancheRequests; i++)
LWLockRegisterTranche(NamedLWLockTrancheArray[i].trancheId,
NamedLWLockTrancheArray[i].trancheName);
}
/* /*
* InitLWLockAccess - initialize backend-local state needed to hold LWLocks * InitLWLockAccess - initialize backend-local state needed to hold LWLocks
*/ */
...@@ -570,7 +612,6 @@ GetNamedLWLockTranche(const char *tranche_name) ...@@ -570,7 +612,6 @@ GetNamedLWLockTranche(const char *tranche_name)
lock_pos += NamedLWLockTrancheRequestArray[i].num_lwlocks; lock_pos += NamedLWLockTrancheRequestArray[i].num_lwlocks;
} }
if (i >= NamedLWLockTrancheRequests)
elog(ERROR, "requested tranche is not registered"); elog(ERROR, "requested tranche is not registered");
/* just to keep compiler quiet */ /* just to keep compiler quiet */
...@@ -595,32 +636,47 @@ LWLockNewTrancheId(void) ...@@ -595,32 +636,47 @@ LWLockNewTrancheId(void)
} }
/* /*
* Register a tranche ID in the lookup table for the current process. This * Register a dynamic tranche name in the lookup table of the current process.
* routine will save a pointer to the tranche name passed as an argument, *
* This routine will save a pointer to the tranche name passed as an argument,
* so the name should be allocated in a backend-lifetime context * so the name should be allocated in a backend-lifetime context
* (TopMemoryContext, static variable, or similar). * (TopMemoryContext, static constant, or similar).
*/ */
void void
LWLockRegisterTranche(int tranche_id, const char *tranche_name) LWLockRegisterTranche(int tranche_id, const char *tranche_name)
{ {
Assert(LWLockTrancheArray != NULL); /* This should only be called for user-defined tranches. */
if (tranche_id < LWTRANCHE_FIRST_USER_DEFINED)
return;
/* Convert to array index. */
tranche_id -= LWTRANCHE_FIRST_USER_DEFINED;
if (tranche_id >= LWLockTranchesAllocated) /* If necessary, create or enlarge array. */
if (tranche_id >= LWLockTrancheNamesAllocated)
{ {
int i = LWLockTranchesAllocated; int newalloc;
int j = LWLockTranchesAllocated;
while (i <= tranche_id) newalloc = Max(LWLockTrancheNamesAllocated, 8);
i *= 2; while (newalloc <= tranche_id)
newalloc *= 2;
LWLockTrancheArray = (const char **) if (LWLockTrancheNames == NULL)
repalloc(LWLockTrancheArray, i * sizeof(char *)); LWLockTrancheNames = (const char **)
LWLockTranchesAllocated = i; MemoryContextAllocZero(TopMemoryContext,
while (j < LWLockTranchesAllocated) newalloc * sizeof(char *));
LWLockTrancheArray[j++] = NULL; else
{
LWLockTrancheNames = (const char **)
repalloc(LWLockTrancheNames, newalloc * sizeof(char *));
memset(LWLockTrancheNames + LWLockTrancheNamesAllocated,
0,
(newalloc - LWLockTrancheNamesAllocated) * sizeof(char *));
}
LWLockTrancheNamesAllocated = newalloc;
} }
LWLockTrancheArray[tranche_id] = tranche_name; LWLockTrancheNames[tranche_id] = tranche_name;
} }
/* /*
...@@ -666,8 +722,8 @@ RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks) ...@@ -666,8 +722,8 @@ RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
} }
request = &NamedLWLockTrancheRequestArray[NamedLWLockTrancheRequests]; request = &NamedLWLockTrancheRequestArray[NamedLWLockTrancheRequests];
Assert(strlen(tranche_name) + 1 < NAMEDATALEN); Assert(strlen(tranche_name) + 1 <= NAMEDATALEN);
StrNCpy(request->tranche_name, tranche_name, NAMEDATALEN); strlcpy(request->tranche_name, tranche_name, NAMEDATALEN);
request->num_lwlocks = num_lwlocks; request->num_lwlocks = num_lwlocks;
NamedLWLockTrancheRequests++; NamedLWLockTrancheRequests++;
} }
...@@ -709,23 +765,42 @@ LWLockReportWaitEnd(void) ...@@ -709,23 +765,42 @@ LWLockReportWaitEnd(void)
} }
/* /*
* Return an identifier for an LWLock based on the wait class and event. * Return the name of an LWLock tranche.
*/ */
const char * static const char *
GetLWLockIdentifier(uint32 classId, uint16 eventId) GetLWTrancheName(uint16 trancheId)
{ {
Assert(classId == PG_WAIT_LWLOCK); /* Individual LWLock? */
if (trancheId < NUM_INDIVIDUAL_LWLOCKS)
return MainLWLockNames[trancheId];
/* Built-in tranche? */
if (trancheId < LWTRANCHE_FIRST_USER_DEFINED)
return BuiltinTrancheNames[trancheId - NUM_INDIVIDUAL_LWLOCKS];
/* /*
* It is quite possible that user has registered tranche in one of the * It's an extension tranche, so look in LWLockTrancheNames[]. However,
* backends (e.g. by allocating lwlocks in dynamic shared memory) but not * it's possible that the tranche has never been registered in the current
* all of them, so we can't assume the tranche is registered here. * process, in which case give up and return "extension".
*/ */
if (eventId >= LWLockTranchesAllocated || trancheId -= LWTRANCHE_FIRST_USER_DEFINED;
LWLockTrancheArray[eventId] == NULL)
if (trancheId >= LWLockTrancheNamesAllocated ||
LWLockTrancheNames[trancheId] == NULL)
return "extension"; return "extension";
return LWLockTrancheArray[eventId]; return LWLockTrancheNames[trancheId];
}
/*
* Return an identifier for an LWLock based on the wait class and event.
*/
const char *
GetLWLockIdentifier(uint32 classId, uint16 eventId)
{
Assert(classId == PG_WAIT_LWLOCK);
/* The event IDs are just tranche numbers. */
return GetLWTrancheName(eventId);
} }
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment