v11-0002-Tests-for-LWLock-tranche-registration-improvemen.patch
application/octet-stream
Filename: v11-0002-Tests-for-LWLock-tranche-registration-improvemen.patch
Type: application/octet-stream
Part: 1
Patch
Format: format-patch
Series: patch v11-0002
Subject: Tests for LWLock tranche registration improvements
| File | + | − |
|---|---|---|
| src/test/modules/Makefile | 2 | 1 |
| src/test/modules/meson.build | 1 | 0 |
| src/test/modules/test_tranches/Makefile | 23 | 0 |
| src/test/modules/test_tranches/meson.build | 33 | 0 |
| src/test/modules/test_tranches/t/001_test_tranches.pl | 115 | 0 |
| src/test/modules/test_tranches/test_tranches--1.0.sql | 21 | 0 |
| src/test/modules/test_tranches/test_tranches.c | 165 | 0 |
| src/test/modules/test_tranches/test_tranches.control | 6 | 0 |
From 3f7ad775a9fc82d2f183a370c2e0cfaf761b1393 Mon Sep 17 00:00:00 2001
From: Sami Imseih <simseih@amazon.com>
Date: Fri, 22 Aug 2025 00:35:45 -0500
Subject: [PATCH v11 2/2] Tests for LWLock tranche registration improvements
---
src/test/modules/Makefile | 3 +-
src/test/modules/meson.build | 1 +
src/test/modules/test_tranches/Makefile | 23 +++
src/test/modules/test_tranches/meson.build | 33 ++++
.../test_tranches/t/001_test_tranches.pl | 115 ++++++++++++
.../test_tranches/test_tranches--1.0.sql | 21 +++
.../modules/test_tranches/test_tranches.c | 165 ++++++++++++++++++
.../test_tranches/test_tranches.control | 6 +
8 files changed, 366 insertions(+), 1 deletion(-)
create mode 100644 src/test/modules/test_tranches/Makefile
create mode 100644 src/test/modules/test_tranches/meson.build
create mode 100644 src/test/modules/test_tranches/t/001_test_tranches.pl
create mode 100644 src/test/modules/test_tranches/test_tranches--1.0.sql
create mode 100644 src/test/modules/test_tranches/test_tranches.c
create mode 100644 src/test/modules/test_tranches/test_tranches.control
diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile
index 903a8ac151a..fd7aa4675c5 100644
--- a/src/test/modules/Makefile
+++ b/src/test/modules/Makefile
@@ -44,7 +44,8 @@ SUBDIRS = \
test_tidstore \
unsafe_tests \
worker_spi \
- xid_wraparound
+ xid_wraparound \
+ test_tranches
ifeq ($(enable_injection_points),yes)
diff --git a/src/test/modules/meson.build b/src/test/modules/meson.build
index 93be0f57289..52883dfb496 100644
--- a/src/test/modules/meson.build
+++ b/src/test/modules/meson.build
@@ -45,3 +45,4 @@ subdir('typcache')
subdir('unsafe_tests')
subdir('worker_spi')
subdir('xid_wraparound')
+subdir('test_tranches')
diff --git a/src/test/modules/test_tranches/Makefile b/src/test/modules/test_tranches/Makefile
new file mode 100644
index 00000000000..5c9e78084da
--- /dev/null
+++ b/src/test/modules/test_tranches/Makefile
@@ -0,0 +1,23 @@
+# src/test/modules/test_tranches/Makefile
+
+MODULE_big = test_tranches
+OBJS = \
+ $(WIN32RES) \
+ test_tranches.o
+PGFILEDESC = "test_tranches - test code LWLock tranche management"
+
+EXTENSION = test_tranches
+DATA = test_tranches--1.0.sql
+
+TAP_TESTS = 1
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_tranches
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_tranches/meson.build b/src/test/modules/test_tranches/meson.build
new file mode 100644
index 00000000000..976ce9f0a25
--- /dev/null
+++ b/src/test/modules/test_tranches/meson.build
@@ -0,0 +1,33 @@
+# Copyright (c) 2024-2025, PostgreSQL Global Development Group
+
+test_tranches_sources = files(
+ 'test_tranches.c',
+)
+
+if host_system == 'windows'
+ test_tranches_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'test_tranches',
+ '--FILEDESC', 'test_tranches - test code LWLock tranche management',])
+endif
+
+test_tranches = shared_module('test_tranches',
+ test_tranches_sources,
+ kwargs: pg_test_mod_args,
+)
+test_install_libs += test_tranches
+
+test_install_data += files(
+ 'test_tranches.control',
+ 'test_tranches--1.0.sql',
+)
+
+tests += {
+ 'name': 'test_tranches',
+ 'sd': meson.current_source_dir(),
+ 'bd': meson.current_build_dir(),
+ 'tap': {
+ 'tests': [
+ 't/001_test_tranches.pl',
+ ],
+ },
+}
\ No newline at end of file
diff --git a/src/test/modules/test_tranches/t/001_test_tranches.pl b/src/test/modules/test_tranches/t/001_test_tranches.pl
new file mode 100644
index 00000000000..9a56b25e204
--- /dev/null
+++ b/src/test/modules/test_tranches/t/001_test_tranches.pl
@@ -0,0 +1,115 @@
+use strict;
+use warnings FATAL => 'all';
+
+use List::Util qw(min);
+use PostgreSQL::Test::Cluster;
+use PostgreSQL::Test::Utils;
+use Test::More;
+
+my $UINT16_MAX = 65535;
+my $MAX_DYNAMIC_TRANCHES = 1024;
+
+# Helper function: wait for one or more logs
+sub maybe_wait_for_log {
+ my ($node, $logs, $log_loc) = @_;
+
+ # Normalize single regex to array
+ $logs = [$logs] unless ref($logs) eq 'ARRAY';
+
+ foreach my $regex (@$logs) {
+ $log_loc = $node->wait_for_log($regex, $log_loc);
+ }
+ return $log_loc;
+}
+
+my $node = PostgreSQL::Test::Cluster->new('primary');
+$node->init();
+
+my $requested_named_tranches = 4;
+
+$node->append_conf('postgresql.conf',
+ qq(shared_preload_libraries='test_tranches'));
+$node->append_conf('postgresql.conf',
+ qq(test_tranches.requested_named_tranches=$requested_named_tranches));
+$node->append_conf('postgresql.conf',
+ qq(log_min_messages=DEBUG3));
+$node->start();
+
+$node->safe_psql('postgres', q(CREATE EXTENSION test_tranches));
+
+my $next_index = 0;
+my $lookup_tranche_id = 0;
+
+my $log_location = -s $node->logfile;
+
+#
+# Lookup requested tranches
+#
+my $last_tranche_id = $node->safe_psql('postgres',
+ qq{select test_tranches_last('fake')});
+
+my $first_tranche_id = $last_tranche_id - $requested_named_tranches;
+my $second_tranche_id = $first_tranche_id + 1;
+
+my $requested_tranches = $node->safe_psql('postgres',
+ qq{select test_tranches_lookup($first_tranche_id);
+ select test_tranches_lookup($second_tranche_id);});
+
+ok ("test_lock_0\ntest_lock_1" eq $requested_tranches, "looked up requested tranches");
+
+#
+# Create tranches
+#
+$node->safe_psql('postgres', qq{select test_tranches_new(100)});
+my $next_tranche_id = $second_tranche_id + 1;
+$requested_tranches = $node->safe_psql('postgres',
+ qq{select test_tranches_lookup($next_tranche_id);});
+ok ("test_lock_2" eq $requested_tranches, "looked up first dynamic tranches");
+
+#
+# get LWLocks
+#
+$node->safe_psql('postgres',
+ qq{select test_tranches_get_named_lwlock('test_lock_3', 3);});
+
+#
+# restart node without requested tranches to test limits
+#
+$node->append_conf('postgresql.conf',
+ qq(test_tranches.requested_named_tranches=0));
+$node->restart;
+
+# long tranche names
+my $good_tranche_name = 'A' x 63;
+my $bad_tranche_name = 'B' x 64;
+$node->safe_psql('postgres', qq{select test_tranches_last('$good_tranche_name');});
+$node->psql('postgres', qq{select test_tranches_last('$bad_tranche_name');});
+$log_location = maybe_wait_for_log($node, qr/ ERROR: tranche name too long/, $log_location);
+ok(1, "check for error on tranche name too long");
+
+#
+# Check for errors with not registered tranches
+#
+my $beyond_limit_id = $MAX_DYNAMIC_TRANCHES + 100;
+$node->psql('postgres',
+ qq{select test_tranches_lookup($beyond_limit_id)});
+$log_location = maybe_wait_for_log($node, qr/ ERROR: LWLock tranche is not registered/, $log_location);
+
+my $within_limit_id = $MAX_DYNAMIC_TRANCHES - 100;
+$node->psql('postgres',
+ qq{select test_tranches_lookup($within_limit_id)});
+$log_location = maybe_wait_for_log($node, qr/ ERROR: LWLock tranche is not registered/, $log_location);
+
+ok(1, "check for error with not registered tranches");
+
+
+# Check for errors with too many tranches registered
+my $dynamic_tranches_count = $MAX_DYNAMIC_TRANCHES;
+$node->safe_psql('postgres',
+ qq{select test_tranches_new($dynamic_tranches_count)});
+$node->psql('postgres',
+ qq{select test_tranches_new(1)});
+$log_location = maybe_wait_for_log($node, qr/ ERROR: too many LWLock tranches registered/, $log_location);
+ok(1, "check for error with too many dynamic tranches");
+
+done_testing();
diff --git a/src/test/modules/test_tranches/test_tranches--1.0.sql b/src/test/modules/test_tranches/test_tranches--1.0.sql
new file mode 100644
index 00000000000..1de8972ab41
--- /dev/null
+++ b/src/test/modules/test_tranches/test_tranches--1.0.sql
@@ -0,0 +1,21 @@
+-- test_tranches--1.0.sql
+
+CREATE FUNCTION test_tranches_new(bigint)
+RETURNS void
+AS 'MODULE_PATHNAME', 'test_tranches_new'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION test_tranches_last(text)
+RETURNS int
+AS 'MODULE_PATHNAME', 'test_tranches_last'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION test_tranches_lookup(int)
+RETURNS text
+AS 'MODULE_PATHNAME', 'test_tranches_lookup'
+LANGUAGE C STRICT;
+
+CREATE FUNCTION test_tranches_get_named_lwlock(text, int)
+RETURNS int
+AS 'MODULE_PATHNAME', 'test_tranches_get_named_lwlock'
+LANGUAGE C STRICT;
diff --git a/src/test/modules/test_tranches/test_tranches.c b/src/test/modules/test_tranches/test_tranches.c
new file mode 100644
index 00000000000..a27455ce5d2
--- /dev/null
+++ b/src/test/modules/test_tranches/test_tranches.c
@@ -0,0 +1,165 @@
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "storage/dsm_registry.h"
+#include "storage/ipc.h"
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
+#include "utils/builtins.h"
+#include "utils/guc.h"
+#include "utils/injection_point.h"
+#include "utils/wait_classes.h"
+
+PG_MODULE_MAGIC;
+
+/* hooks */
+static shmem_request_hook_type prev_shmem_request_hook = NULL;
+static shmem_startup_hook_type prev_shmem_startup_hook = NULL;
+static void test_tranches_shmem_request(void);
+static void test_tranches_shmem_startup(void);
+
+/* GUC */
+static int test_tranches_requested_named_tranches = 0;
+
+typedef struct testTranchesSharedState
+{
+ int next_index;
+} testTranchesSharedState;
+
+static testTranchesSharedState * test_lwlock_ss = NULL;
+
+/*
+ * LWLock wait event masks. Copied from src/backend/utils/activity/wait_event.c
+ */
+#define WAIT_EVENT_CLASS_MASK 0xFF000000
+
+/*
+ * Module load callback
+ */
+void
+_PG_init(void)
+{
+ prev_shmem_request_hook = shmem_request_hook;
+ shmem_request_hook = test_tranches_shmem_request;
+ prev_shmem_startup_hook = shmem_startup_hook;
+ shmem_startup_hook = test_tranches_shmem_startup;
+
+ DefineCustomIntVariable("test_tranches.requested_named_tranches",
+ "Sets the number of locks created during shmem request",
+ NULL,
+ &test_tranches_requested_named_tranches,
+ 2,
+ 0,
+ UINT16_MAX,
+ PGC_POSTMASTER,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+}
+
+static void
+test_tranches_shmem_startup(void)
+{
+ bool found;
+
+ if (prev_shmem_startup_hook)
+ prev_shmem_startup_hook();
+
+ test_lwlock_ss = NULL;
+
+ test_lwlock_ss = ShmemInitStruct("test_tranches",
+ sizeof(testTranchesSharedState),
+ &found);
+ if (!found)
+ {
+ test_lwlock_ss->next_index = test_tranches_requested_named_tranches;
+ }
+}
+
+static Size
+test_tranches_memsize(void)
+{
+ Size size;
+
+ size = MAXALIGN(sizeof(testTranchesSharedState));
+
+ return size;
+}
+
+static void
+test_tranches_shmem_request(void)
+{
+ int i = 0;
+
+ if (prev_shmem_request_hook)
+ prev_shmem_request_hook();
+
+ RequestAddinShmemSpace(test_tranches_memsize());
+
+ for (i = 0; i < test_tranches_requested_named_tranches; i++)
+ {
+ char name[15];
+
+ snprintf(name, sizeof(name), "test_lock_%d", i);
+ RequestNamedLWLockTranche(name, i);
+ }
+}
+
+PG_FUNCTION_INFO_V1(test_tranches_new);
+Datum
+test_tranches_new(PG_FUNCTION_ARGS)
+{
+ int64 num = PG_GETARG_INT64(0);
+ int i;
+
+ for (i = test_lwlock_ss->next_index; i < num + test_lwlock_ss->next_index; i++)
+ {
+ char name[50];
+
+ snprintf(name, 50, "test_lock__%d", i);
+
+ LWLockNewTrancheId(name);
+ }
+
+ test_lwlock_ss->next_index = i;
+
+ PG_RETURN_VOID();
+}
+
+PG_FUNCTION_INFO_V1(test_tranches_last);
+Datum
+test_tranches_last(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_INT32(LWLockNewTrancheId(text_to_cstring(PG_GETARG_TEXT_PP(0))));
+}
+
+PG_FUNCTION_INFO_V1(test_tranches_lookup);
+Datum
+test_tranches_lookup(PG_FUNCTION_ARGS)
+{
+ const char *tranche_name = GetLWLockIdentifier(PG_WAIT_LWLOCK & WAIT_EVENT_CLASS_MASK, PG_GETARG_INT32(0));
+
+ PG_RETURN_TEXT_P(cstring_to_text(tranche_name));
+}
+
+PG_FUNCTION_INFO_V1(test_tranches_get_named_lwlock);
+Datum
+test_tranches_get_named_lwlock(PG_FUNCTION_ARGS)
+{
+ int i;
+ LWLockPadded *locks;
+
+ locks = GetNamedLWLockTranche(text_to_cstring(PG_GETARG_TEXT_PP(0)));
+
+ for (i = 0; i < PG_GETARG_INT32(1); i++)
+ {
+ LWLock *lock = &locks[i].lock;
+
+ LWLockAcquire(lock, LW_SHARED);
+ LWLockRelease(lock);
+ }
+
+ PG_RETURN_INT32(i);
+}
diff --git a/src/test/modules/test_tranches/test_tranches.control b/src/test/modules/test_tranches/test_tranches.control
new file mode 100644
index 00000000000..8e6254a7e43
--- /dev/null
+++ b/src/test/modules/test_tranches/test_tranches.control
@@ -0,0 +1,6 @@
+# test_tranches.control
+
+comment = 'Test LWLock tranch names tracking'
+default_version = '1.0'
+relocatable = false
+module_pathname = '$libdir/test_tranches'
\ No newline at end of file
--
2.39.5 (Apple Git-154)