From 583c818e3121c0f7c6506b434497c81ae94ee9cb Mon Sep 17 00:00:00 2001
From: Craig Ringer <craig.ringer@2ndquadrant.com>
Date: Thu, 19 Nov 2020 17:30:47 +0800
Subject: [PATCH v1 4/4] Comments on LWLock tranches

---
 src/backend/storage/lmgr/lwlock.c | 49 +++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 3 deletions(-)

diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index cfdfa7f328..123bcc463e 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -112,11 +112,14 @@ extern slock_t *ShmemLock;
  *
  * 1. The individually-named locks defined in lwlocknames.h each have their
  * own tranche.  The names of these tranches appear in IndividualLWLockNames[]
- * in lwlocknames.c.
+ * in lwlocknames.c. The LWLock structs are allocated in MainLWLockArray.
  *
  * 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.
+ * appear in BuiltinTrancheNames[] below. The LWLock structs are allocated
+ * elsewhere under the control of the subsystem that manages the tranche. The
+ * LWLock code does not know or care where in shared memory they are allocated
+ * or how many there are in a tranche.
  *
  * 3. Extensions can create new tranches, via either RequestNamedLWLockTranche
  * or LWLockRegisterTranche.  The names of these that are known in the current
@@ -196,6 +199,13 @@ static int	LWLockTrancheNamesAllocated = 0;
  * This points to the main array of LWLocks in shared memory.  Backends inherit
  * the pointer by fork from the postmaster (except in the EXEC_BACKEND case,
  * where we have special measures to pass it down).
+ *
+ * This array holds individual LWLocks and LWLocks allocated in named tranches.
+ *
+ * It does not hold locks for any LWLock that's separately initialized with
+ * LWLockInitialize(). Locks in tranches listed in BuiltinTrancheIds or
+ * allocated with LWLockNewTrancheId() can be embedded in other structs
+ * anywhere in shared memory.
  */
 LWLockPadded *MainLWLockArray = NULL;
 
@@ -593,6 +603,12 @@ InitLWLockAccess(void)
  * Caller needs to retrieve the requested number of LWLocks starting from
  * the base lock address returned by this API.  This can be used for
  * tranches that are requested by using RequestNamedLWLockTranche() API.
+ *
+ * The locks are already initialized.
+ *
+ * This function can not be used for locks in builtin tranches or tranches
+ * registered with LWLockRegisterTranche(). There is no way to look those locks
+ * up by name.
  */
 LWLockPadded *
 GetNamedLWLockTranche(const char *tranche_name)
@@ -647,6 +663,14 @@ LWLockNewTrancheId(void)
  *
  * The tranche name will be user-visible as a wait event name, so try to
  * use a name that fits the style for those.
+ *
+ * The tranche ID should be a user-defined tranche ID acquired from
+ * LWLockNewTrancheId(). It is not necessary to call this for tranches
+ * allocated by RequestNamedLWLockTranche().
+ *
+ * The LWLock subsystem does not know where LWLock(s) that will be assigned to
+ * this tranche are stored, or how many of them there are. The caller allocates
+ * suitable shared memory storage and initializes locks with LWLockInitialize().
  */
 void
 LWLockRegisterTranche(int tranche_id, const char *tranche_name)
@@ -699,6 +723,10 @@ LWLockRegisterTranche(int tranche_id, const char *tranche_name)
  *
  * The tranche name will be user-visible as a wait event name, so try to
  * use a name that fits the style for those.
+ *
+ * The LWLocks allocated here are retrieved after shmem startup using
+ * GetNamedLWLockTranche(). They are intialized during shared memory startup so
+ * it is not necessary to call LWLockInitialize() on them.
  */
 void
 RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
@@ -739,10 +767,17 @@ RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
 
 /*
  * LWLockInitialize - initialize a new lwlock; it's initially unlocked
+ *
+ * For callers outside the LWLock subsystem itself, the tranche ID must either
+ * be a BuiltinTrancheIds entry for the calling subsysytem or a tranche ID
+ * assigned with LWLockNewTrancheId().
  */
 void
 LWLockInitialize(LWLock *lock, int tranche_id)
 {
+	/* Re-initialization of individual LWLocks is not permitted */
+	Assert(tranche_id >= NUM_INDIVIDUAL_LWLOCKS || !IsUnderPostmaster);
+
 	pg_atomic_init_u32(&lock->state, LW_FLAG_RELEASE_OK);
 #ifdef LOCK_DEBUG
 	pg_atomic_init_u32(&lock->nwaiters, 0);
@@ -803,6 +838,11 @@ GetLWTrancheName(uint16 trancheId)
 
 /*
  * Return an identifier for an LWLock based on the wait class and event.
+ *
+ * Note that there's no way to identify a individual LWLock within a tranche by
+ * anything except its address. The LWLock subsystem doesn't know how many
+ * locks there are in all tranches and there's no requirement that they be
+ * stored in contiguous arrays.
  */
 const char *
 GetLWLockIdentifier(uint32 classId, uint16 eventId)
@@ -1010,7 +1050,7 @@ LWLockWakeup(LWLock *lock)
 
 	Assert(proclist_is_empty(&wakeup) || pg_atomic_read_u32(&lock->state) & LW_FLAG_HAS_WAITERS);
 
-	/* unset required flags, and release lock, in one fell swoop */
+	/* unset required flags, and release waitlist lock, in one fell swoop */
 	{
 		uint32		old_state;
 		uint32		desired_state;
@@ -1837,6 +1877,9 @@ LWLockUpdateVar(LWLock *lock, uint64 *valptr, uint64 val)
 
 /*
  * LWLockRelease - release a previously acquired lock
+ *
+ * The actual lock acquire corresponding to this release happens in
+ * LWLockAttemptLock().
  */
 void
 LWLockRelease(LWLock *lock)
-- 
2.29.2

