test_integerset \
test_json_parser \
test_lfind \
+ test_lwlock_tranches \
test_misc \
test_oat_hooks \
test_parser \
subdir('test_integerset')
subdir('test_json_parser')
subdir('test_lfind')
+subdir('test_lwlock_tranches')
subdir('test_misc')
subdir('test_oat_hooks')
subdir('test_parser')
--- /dev/null
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
--- /dev/null
+# src/test/modules/test_lwlock_tranches/Makefile
+
+MODULE_big = test_lwlock_tranches
+OBJS = \
+ $(WIN32RES) \
+ test_lwlock_tranches.o
+PGFILEDESC = "test_lwlock_tranches - test code for LWLock tranches allocated by extensions"
+
+EXTENSION = test_lwlock_tranches
+DATA = test_lwlock_tranches--1.0.sql
+
+REGRESS_OPTS = --temp-config $(top_srcdir)/src/test/modules/test_lwlock_tranches/test_lwlock_tranches.conf
+REGRESS = test_lwlock_tranches
+NO_INSTALLCHECK = 1
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_lwlock_tranches
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
--- /dev/null
+CREATE EXTENSION test_lwlock_tranches;
+SELECT test_lwlock_tranches();
+ test_lwlock_tranches
+----------------------
+
+(1 row)
+
+SELECT test_lwlock_tranche_creation(NULL);
+ERROR: tranche name cannot be NULL
+SELECT test_lwlock_tranche_creation(repeat('a', 64));
+ERROR: tranche name too long
+DETAIL: LWLock tranche names must be no longer than 63 bytes.
+SELECT test_lwlock_tranche_creation('test');
+ERROR: maximum number of tranches already registered
+DETAIL: No more than 256 tranches may be registered.
+SELECT test_lwlock_tranche_lookup('test_lwlock_tranches_startup');
+ test_lwlock_tranche_lookup
+----------------------------
+
+(1 row)
+
+SELECT test_lwlock_tranche_lookup('bogus');
+ERROR: requested tranche is not registered
+SELECT test_lwlock_initialize(65535);
+ERROR: tranche 65535 is not registered
--- /dev/null
+# Copyright (c) 2025, PostgreSQL Global Development Group
+
+test_lwlock_tranches_sources = files(
+ 'test_lwlock_tranches.c',
+)
+
+if host_system == 'windows'
+ test_lwlock_tranches_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'test_lwlock_tranches',
+ '--FILEDESC', 'test_lwlock_tranches - test code for LWLock tranches allocated by extensions',])
+endif
+
+test_lwlock_tranches = shared_module('test_lwlock_tranches',
+ test_lwlock_tranches_sources,
+ kwargs: pg_test_mod_args,
+)
+test_install_libs += test_lwlock_tranches
+
+test_install_data += files(
+ 'test_lwlock_tranches.control',
+ 'test_lwlock_tranches--1.0.sql',
+)
+
+tests += {
+ 'name': 'test_lwlock_tranches',
+ 'sd': meson.current_source_dir(),
+ 'bd': meson.current_build_dir(),
+ 'regress': {
+ 'sql': [
+ 'test_lwlock_tranches',
+ ],
+ 'regress_args': ['--temp-config', files('test_lwlock_tranches.conf')],
+ 'runningcheck': false,
+ },
+}
--- /dev/null
+CREATE EXTENSION test_lwlock_tranches;
+SELECT test_lwlock_tranches();
+SELECT test_lwlock_tranche_creation(NULL);
+SELECT test_lwlock_tranche_creation(repeat('a', 64));
+SELECT test_lwlock_tranche_creation('test');
+SELECT test_lwlock_tranche_lookup('test_lwlock_tranches_startup');
+SELECT test_lwlock_tranche_lookup('bogus');
+SELECT test_lwlock_initialize(65535);
--- /dev/null
+/* src/test/modules/test_lwlock_tranches/test_lwlock_tranches--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION test_lwlock_tranches" to load this file. \quit
+
+CREATE FUNCTION test_lwlock_tranches() RETURNS VOID
+ AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION test_lwlock_tranche_creation(tranche_name TEXT) RETURNS VOID
+ AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION test_lwlock_tranche_lookup(tranche_name TEXT) RETURNS VOID
+ AS 'MODULE_PATHNAME' LANGUAGE C;
+
+CREATE FUNCTION test_lwlock_initialize(tranche_id INT) RETURNS VOID
+ AS 'MODULE_PATHNAME' LANGUAGE C;
--- /dev/null
+/*--------------------------------------------------------------------------
+ *
+ * test_lwlock_tranches.c
+ * Test code for LWLock tranches allocated by extensions.
+ *
+ * Copyright (c) 2025, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * src/test/modules/test_lwlock_tranches/test_lwlock_tranches.c
+ *
+ * -------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "storage/lwlock.h"
+#include "utils/builtins.h"
+#include "utils/wait_classes.h"
+
+PG_MODULE_MAGIC;
+
+#define STARTUP_TRANCHE_NAME "test_lwlock_tranches_startup"
+#define DYNAMIC_TRANCHE_NAME "test_lwlock_tranches_dynamic"
+
+#define NUM_STARTUP_TRANCHES (32)
+#define NUM_DYNAMIC_TRANCHES (256 - NUM_STARTUP_TRANCHES)
+
+#define GET_TRANCHE_NAME(a) GetLWLockIdentifier(PG_WAIT_LWLOCK, (a))
+
+static shmem_request_hook_type prev_shmem_request_hook;
+static void test_lwlock_tranches_shmem_request(void);
+
+void
+_PG_init(void)
+{
+ prev_shmem_request_hook = shmem_request_hook;
+ shmem_request_hook = test_lwlock_tranches_shmem_request;
+}
+
+static void
+test_lwlock_tranches_shmem_request(void)
+{
+ if (prev_shmem_request_hook)
+ prev_shmem_request_hook();
+
+ for (int i = 0; i < NUM_STARTUP_TRANCHES; i++)
+ RequestNamedLWLockTranche(STARTUP_TRANCHE_NAME, 1);
+}
+
+/*
+ * Checks that GetLWLockIdentifier() returns the expected value for tranches
+ * registered via RequestNamedLWLockTranche() and LWLockNewTrancheId().
+ */
+PG_FUNCTION_INFO_V1(test_lwlock_tranches);
+Datum
+test_lwlock_tranches(PG_FUNCTION_ARGS)
+{
+ int dynamic_tranches[NUM_DYNAMIC_TRANCHES];
+
+ for (int i = 0; i < NUM_DYNAMIC_TRANCHES; i++)
+ dynamic_tranches[i] = LWLockNewTrancheId(DYNAMIC_TRANCHE_NAME);
+
+ for (int i = 0; i < NUM_STARTUP_TRANCHES; i++)
+ {
+ if (strcmp(GET_TRANCHE_NAME(LWTRANCHE_FIRST_USER_DEFINED + i),
+ STARTUP_TRANCHE_NAME) != 0)
+ elog(ERROR, "incorrect startup lock tranche name");
+ }
+
+ for (int i = 0; i < NUM_DYNAMIC_TRANCHES; i++)
+ {
+ if (strcmp(GET_TRANCHE_NAME(dynamic_tranches[i]),
+ DYNAMIC_TRANCHE_NAME) != 0)
+ elog(ERROR, "incorrect dynamic lock tranche name");
+ }
+
+ PG_RETURN_VOID();
+}
+
+/*
+ * Wrapper for LWLockNewTrancheId().
+ */
+PG_FUNCTION_INFO_V1(test_lwlock_tranche_creation);
+Datum
+test_lwlock_tranche_creation(PG_FUNCTION_ARGS)
+{
+ char *tranche_name = PG_ARGISNULL(0) ? NULL : TextDatumGetCString(PG_GETARG_DATUM(0));
+
+ (void) LWLockNewTrancheId(tranche_name);
+
+ PG_RETURN_VOID();
+}
+
+/*
+ * Wrapper for GetNamedLWLockTranche().
+ */
+PG_FUNCTION_INFO_V1(test_lwlock_tranche_lookup);
+Datum
+test_lwlock_tranche_lookup(PG_FUNCTION_ARGS)
+{
+ char *tranche_name = TextDatumGetCString(PG_GETARG_DATUM(0));
+
+ (void) GetNamedLWLockTranche(tranche_name);
+
+ PG_RETURN_VOID();
+}
+
+/*
+ * Wrapper for LWLockInitialize().
+ */
+PG_FUNCTION_INFO_V1(test_lwlock_initialize);
+Datum
+test_lwlock_initialize(PG_FUNCTION_ARGS)
+{
+ int tranche_id = PG_GETARG_INT32(0);
+ LWLock lock;
+
+ LWLockInitialize(&lock, tranche_id);
+
+ PG_RETURN_VOID();
+}
--- /dev/null
+shared_preload_libraries = 'test_lwlock_tranches'
--- /dev/null
+comment = 'Test code for LWLock tranches allocated by extensions'
+default_version = '1.0'
+module_pathname = '$libdir/test_lwlock_tranches'
+relocatable = true