Re: add function for creating/attaching hash table in DSM registry

Nathan Bossart <nathandbossart@gmail.com>

From: Nathan Bossart <nathandbossart@gmail.com>
To: Sami Imseih <samimseih@gmail.com>
Cc: Florents Tselai <florents.tselai@gmail.com>, Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>, pgsql-hackers@postgresql.org
Date: 2025-06-10T20:21:34Z
Lists: pgsql-hackers
On Tue, Jun 10, 2025 at 02:05:16PM -0500, Sami Imseih wrote:
> There is also that dynamic tranche named are stored in local backend
> look-up table, so if you have some backends that attached some dynamic
> hash table
> and others that did not, only the ones that registered would be able to
> resolve the tranche id to its name.
> 
> This is the case which I encountered yesterday, in which I tested 2
> backends competing for a LWLock on the dshash table, but a third backend
> that did not attach the hashtable reported the wait_event as "extension"
> rather than the extension-specified tranche name.
> 
> If that third backend attaches the hash table, then it's able to report
> the wait_event as the tranche name specified by the extension. So that
> could be confusing as 2 wait events could be reported for the same
> code path. right?

My initial reaction to this was "well yeah, that's how it's designed."  But
after some more research, I see that LWLockRegisterTranche() (commit
ea9df81) predates both the removal of dynamic_shared_memory_type=none
(commit bcbd940) and the introduction of DSAs (commit 13df76a).  lwlock.h
even still has this (arguably outdated) comment:

 * It may seem strange that each process using the tranche must register it
 * separately, but dynamic shared memory segments aren't guaranteed to be
 * mapped at the same address in all coordinating backends, so storing the
 * registration in the main shared memory segment wouldn't work for that case.

So, if we were adding named LWLocks today, I suspect we might do it
differently.  The first thing that comes to mind is that we could store a
shared LWLockTrancheNames table and stop requiring each backend to register
them individually.  For a concrete example, the autoprewarm shared memory
initialization code would become something like:

	static void
	apw_init_state(void *ptr)
	{
		AutoPrewarmSharedState *state = (AutoPrewarmSharedState *) ptr;

		LWLockInitialize(&state->lock, LWLockNewTrancheId("autoprewarm"));
		...
	}

	static bool
	apw_init_shmem(void)
	{
		bool		found;

		apw_state = GetNamedDSMSegment("autoprewarm",
									   sizeof(AutoPrewarmSharedState),
									   apw_init_state,
									   &found);
		return found;
	}

In short, LWLockNewTrancheId() would gain a new name argument, and
LWLockRegisterTranche() would disappear.  We would probably need to be
smart to avoid contention on the name table, but that feels avoidable to
me.

-- 
nathan



Commits

  1. Fix cross-version upgrade test breakage from commit fe07100e82.

  2. Add GetNamedDSA() and GetNamedDSHash().

  3. Remove dynamic_shared_memory_type=none

  4. Introduce dynamic shared memory areas.

  5. Relax the requirement that all lwlocks be stored in a single array.