Re: Improve LWLock tranche name visibility across backends - Mailing list pgsql-hackers

From Bertrand Drouvot
Subject Re: Improve LWLock tranche name visibility across backends
Date
Msg-id aKL1w6tczBqsqLiJ@ip-10-97-1-34.eu-west-3.compute.internal
Whole thread Raw
In response to Re: Improve LWLock tranche name visibility across backends  (Sami Imseih <samimseih@gmail.com>)
List pgsql-hackers
Hi,

On Sat, Aug 16, 2025 at 10:18:05PM -0500, Sami Imseih wrote:
> Attached is v8.

Thanks for the new version!

A few random comments about 0001:

1 ===

+}                      LWLockTrancheNamesShmem;

+}                      LWLockTrancheNamesStruct;

Add LWLockTrancheNamesShmem and LWLockTrancheNamesStruct to
src/tools/pgindent/typedefs.list?

2 ===

Maybe a comment before the above structs definitions to explain what they are
used for?

3 ===

+static void
+SetSharedTrancheName(int tranche_index, const char *tranche_name)
 {
-       /* This should only be called for user-defined tranches. */
-       if (tranche_id < LWTRANCHE_FIRST_USER_DEFINED)
-               return;
+       dsa_pointer *name_ptrs;
+       dsa_pointer str_ptr;
+       char       *str_addr;
+       int                     len;
+       int                     current_allocated;
+       int                     new_alloc = 0;

-       /* Convert to array index. */
-       tranche_id -= LWTRANCHE_FIRST_USER_DEFINED;
+       LWLockAcquire(&LWLockTrancheNames.shmem->lock, LW_EXCLUSIVE);

Add Assert(IsUnderPostmaster || !IsPostmasterEnvironment);?

4 ===

+static void
+SetLocalTrancheName(int tranche_index, const char *tranche_name)
+{
+       int                     newalloc;
+
+       Assert(tranche_name);

should we add some assert on IsUnderPostmaster and/or IsPostmasterEnvironment too?

5 ===

+       while (i < NamedLWLockTrancheRequests)
+       {
+               NamedLWLockTranche *tranche;
+
+               tranche = &NamedLWLockTrancheArray[i];
+
+               SetLocalTrancheName(i, tranche->trancheName);
+
+               i++;
+       }

Maybe add a comment that those are the ones allocated by the postmaster during
startup?

Also, as this will be done during each sync and those tranches don't change,
so one could think there is room for improvement. Maybe add a comment that's
probably not worth optimizing (due to the fact that NamedLWLockTrancheRequests
should be small enough and the sync rare)?

6 ===

There is this existing comment:

/*
 * 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;

Maybe add something like? "Additional dynamic tranche names beyond this count
are stored in a DSA".

7 ===

+               old_ptrs = dsa_get_address(LWLockTrancheNames.dsa,
+                                                                  LWLockTrancheNames.shmem->list_ptr);
+
+               name_ptrs = dsa_get_address(LWLockTrancheNames.dsa, new_list);
+
+               memset(name_ptrs, InvalidDsaPointer, new_alloc);
+               memcpy(name_ptrs, old_ptrs, sizeof(dsa_pointer) * current_allocated);
+
+               dsa_free(LWLockTrancheNames.dsa, LWLockTrancheNames.shmem->list_ptr);

maybe use local variable for LWLockTrancheNames.shmem->list_ptr (and 
LWLockTrancheNames.dsa)?

8 ===

+       needs_sync = (trancheId >= LWLockTrancheNames.allocated ||
+                                 LWLockTrancheNames.local[trancheId] == NULL)
+               && (IsUnderPostmaster || !IsPostmasterEnvironment);

formating does not look good.

9 ===

-       if (trancheId >= LWLockTrancheNamesAllocated ||
-               LWLockTrancheNames[trancheId] == NULL)
-               return "extension";
+       if (trancheId < LWLockTrancheNames.allocated)
+               tranche_name = LWLockTrancheNames.local[trancheId];

-       return LWLockTrancheNames[trancheId];
+       if (!tranche_name)
+               elog(ERROR, "tranche ID %d is not registered", tranche_id_saved);

We now error out instead of returning "extension". That looks ok given the 
up-thread discussion but then the commit message needs some updates as it
states:

"
Additionally, while users should not pass arbitrary tranche IDs (that is,
IDs not created via LWLockNewTrancheId) to LWLockInitialize, nothing
technically prevents them from doing so. Therefore, we must continue to
handle such cases gracefully by returning a default "extension" tranche name.
"

10 ===

+LWLockTrancheNamesInitSize()
+{
+       Size            sz;
+
+       /*
+        * This value is used by other facilities, see pgstat_shmem.c, so it's
+        * good enough.
+        */
+       sz = 256 * 1024;

use DSA_MIN_SEGMENT_SIZE?

11 ===

+       if (!IsUnderPostmaster)
+       {
+               dsa_area   *dsa;
+               LWLockTrancheNamesShmem *ctl = LWLockTrancheNames.shmem;
+               char       *p = (char *) ctl;
+
+               /* Calculate layout within the shared memory region */
+               p += MAXALIGN(sizeof(LWLockTrancheNamesShmem));
+               ctl->raw_dsa_area = p;
+               p += MAXALIGN(LWLockTrancheNamesInitSize());

LWLockTrancheNamesInitSize() already does MAXALIGN() so the last one
above is not needed. But the last p advance seems not necessary as not used
after. I think the same is true in StatsShmemInit() (see [1]).

12 ===

+LWLockTrancheNamesBEInit(void)
+{
+       /* already attached, nothing to do */
+       if (LWLockTrancheNames.dsa)
+               return;
+
+       LWLockTrancheNamesAttach();
+
+       /* Set up a process-exit hook to clean up */

s/already/Already/?

For 0002, a quick review:

13 ===

+       if (log)
+               elog(DEBUG3, "current_allocated: %d in tranche names shared memory", new_alloc);

Instead of this, could we elog distinct messages where the patch currently sets
log = true?


14 ===

-                 xid_wraparound
+                 xid_wraparound \
+                 test_lwlock_tranches

breaks the ordering.

15 ===

 subdir('worker_spi')
 subdir('xid_wraparound')
+subdir('test_lwlock_tranches')

Same, breaks the ordering.

16 ===

+my $ENABLE_LOG_WAIT = 1;
+
+my $isession;
+my $log_location;
+
+# Helper function: wait for one or more logs if $ENABLE_LOG_WAIT is true
+sub maybe_wait_for_log {
+    my ($node, $logs, $log_loc) = @_;
+    return $log_loc unless $ENABLE_LOG_WAIT;

is ENABLE_LOG_WAIT needed as it does not change?


[1]: https://www.postgresql.org/message-id/aKLsu2sdpnyeuSSc%40ip-10-97-1-34.eu-west-3.compute.internal

Regards,

-- 
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com



pgsql-hackers by date:

Previous
From: Bertrand Drouvot
Date:
Subject: Re: Remove useless pointer advance in StatsShmemInit()
Next
From: vignesh C
Date:
Subject: Re: Logical Replication of sequences