#define LW_SHARED_MASK ((uint32) ((1 << 24)-1))
/*
- * This is indexed by tranche ID and stores the names of all tranches known
- * to the current backend.
+ * There are three sorts of LWLock "tranches":
+ *
+ * 1. The individually-named locks defined in lwlocknames.h each have their
+ * own tranche. The names of these tranches appear in MainLWLockNames[]
+ * 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 **LWLockTrancheArray = NULL;
-static int LWLockTranchesAllocated = 0;
-#define T_NAME(lock) \
- (LWLockTrancheArray[(lock)->tranche])
+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[]");
+
+/*
+ * 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
int num_lwlocks;
} NamedLWLockTrancheRequest;
-NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL;
+static NamedLWLockTrancheRequest *NamedLWLockTrancheRequestArray = NULL;
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;
+/* points to data in shared memory: */
NamedLWLockTranche *NamedLWLockTrancheArray = NULL;
static bool lock_named_request_allowed = true;
static void InitializeLWLocks(void);
-static void RegisterLWLockTranches(void);
-
static inline void LWLockReportWaitStart(LWLock *lock);
static inline void LWLockReportWaitEnd(void);
+static const char *GetLWTrancheName(uint16 trancheId);
+
+#define T_NAME(lock) \
+ GetLWTrancheName((lock)->tranche)
#ifdef LWLOCK_STATS
typedef struct lwlock_stats_key
{
fprintf(stderr,
"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->ex_acquire_count, lwstats->block_count,
lwstats->spin_delay_count, lwstats->dequeue_self_count);
* allocated in the main array.
*/
static int
-NumLWLocksByNamedTranches(void)
+NumLWLocksForNamedTranches(void)
{
int numLocks = 0;
int i;
int i;
int numLocks = NUM_FIXED_LWLOCKS;
- numLocks += NumLWLocksByNamedTranches();
+ /* Calculate total number of locks needed in the main array. */
+ numLocks += NumLWLocksForNamedTranches();
/* Space for the LWLock array. */
size = mul_size(numLocks, sizeof(LWLockPadded));
for (i = 0; i < NamedLWLockTrancheRequests; i++)
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;
return size;
/*
* 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
CreateLWLocks(void)
InitializeLWLocks();
}
- /* Register all LWLock tranches */
- RegisterLWLockTranches();
+ /* Register named extension LWLock tranches in the current process. */
+ for (int i = 0; i < NamedLWLockTrancheRequests; i++)
+ LWLockRegisterTranche(NamedLWLockTrancheArray[i].trancheId,
+ NamedLWLockTrancheArray[i].trancheName);
}
/*
static void
InitializeLWLocks(void)
{
- int numNamedLocks = NumLWLocksByNamedTranches();
+ int numNamedLocks = NumLWLocksForNamedTranches();
int id;
int i;
int j;
for (id = 0; id < NUM_PREDICATELOCK_PARTITIONS; id++, lock++)
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)
{
char *trancheNames;
}
}
-/*
- * 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
*/
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 */
return NULL;
}
/*
- * Register a tranche ID in the lookup table for the current process. This
- * routine will save a pointer to the tranche name passed as an argument,
+ * Register a dynamic tranche name in the lookup table of the current process.
+ *
+ * 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
- * (TopMemoryContext, static variable, or similar).
+ * (TopMemoryContext, static constant, or similar).
*/
void
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 j = LWLockTranchesAllocated;
+ int newalloc;
- while (i <= tranche_id)
- i *= 2;
+ newalloc = Max(LWLockTrancheNamesAllocated, 8);
+ while (newalloc <= tranche_id)
+ newalloc *= 2;
- LWLockTrancheArray = (const char **)
- repalloc(LWLockTrancheArray, i * sizeof(char *));
- LWLockTranchesAllocated = i;
- while (j < LWLockTranchesAllocated)
- LWLockTrancheArray[j++] = NULL;
+ if (LWLockTrancheNames == NULL)
+ LWLockTrancheNames = (const char **)
+ MemoryContextAllocZero(TopMemoryContext,
+ newalloc * sizeof(char *));
+ 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;
}
/*
}
request = &NamedLWLockTrancheRequestArray[NamedLWLockTrancheRequests];
- Assert(strlen(tranche_name) + 1 < NAMEDATALEN);
- StrNCpy(request->tranche_name, tranche_name, NAMEDATALEN);
+ Assert(strlen(tranche_name) + 1 <= NAMEDATALEN);
+ strlcpy(request->tranche_name, tranche_name, NAMEDATALEN);
request->num_lwlocks = num_lwlocks;
NamedLWLockTrancheRequests++;
}
}
/*
- * Return an identifier for an LWLock based on the wait class and event.
+ * Return the name of an LWLock tranche.
*/
-const char *
-GetLWLockIdentifier(uint32 classId, uint16 eventId)
+static const char *
+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
- * backends (e.g. by allocating lwlocks in dynamic shared memory) but not
- * all of them, so we can't assume the tranche is registered here.
+ * It's an extension tranche, so look in LWLockTrancheNames[]. However,
+ * it's possible that the tranche has never been registered in the current
+ * process, in which case give up and return "extension".
*/
- if (eventId >= LWLockTranchesAllocated ||
- LWLockTrancheArray[eventId] == NULL)
+ trancheId -= LWTRANCHE_FIRST_USER_DEFINED;
+
+ if (trancheId >= LWLockTrancheNamesAllocated ||
+ LWLockTrancheNames[trancheId] == NULL)
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);
}
/*