From 61e698159acd8d0a374292a75bbbcd3ad2bf8a48 Mon Sep 17 00:00:00 2001 From: Andrey Borodin Date: Mon, 20 May 2024 15:20:31 +0500 Subject: [PATCH] Add multixact CV sleep --- src/backend/access/transam/multixact.c | 5 ++ .../injection_points--1.0.sql | 2 +- .../injection_points/injection_points.c | 2 +- src/test/modules/test_slru/Makefile | 3 + src/test/modules/test_slru/meson.build | 8 +++ src/test/modules/test_slru/t/001_multixact.pl | 66 +++++++++++++++++++ src/test/modules/test_slru/test_slru--1.0.sql | 6 ++ src/test/modules/test_slru/test_slru.c | 29 ++++++++ 8 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 src/test/modules/test_slru/t/001_multixact.pl diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 54c916e0347..58ec847cf02 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -88,6 +88,7 @@ #include "storage/proc.h" #include "storage/procarray.h" #include "utils/fmgrprotos.h" +#include "utils/injection_point.h" #include "utils/guc_hooks.h" #include "utils/memutils.h" @@ -825,8 +826,12 @@ MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members) * in vacuum. During vacuum, in particular, it would be unacceptable to * keep OldestMulti set, in case it runs for long. */ + INJECTION_POINT_PRELOAD("GetNewMultiXactId-done"); + multi = GetNewMultiXactId(nmembers, &offset); + INJECTION_POINT("GetNewMultiXactId-done"); + /* Make an XLOG entry describing the new MXID. */ xlrec.mid = multi; xlrec.moff = offset; diff --git a/src/test/modules/injection_points/injection_points--1.0.sql b/src/test/modules/injection_points/injection_points--1.0.sql index 29d43cc5566..998a513bffc 100644 --- a/src/test/modules/injection_points/injection_points--1.0.sql +++ b/src/test/modules/injection_points/injection_points--1.0.sql @@ -73,4 +73,4 @@ LANGUAGE C STRICT PARALLEL UNSAFE; CREATE FUNCTION injection_points_detach(IN point_name TEXT) RETURNS void AS 'MODULE_PATHNAME', 'injection_points_detach' -LANGUAGE C STRICT PARALLEL UNSAFE; +LANGUAGE C STRICT PARALLEL UNSAFE; \ No newline at end of file diff --git a/src/test/modules/injection_points/injection_points.c b/src/test/modules/injection_points/injection_points.c index 086b8a6a5e4..a819aebe5b3 100644 --- a/src/test/modules/injection_points/injection_points.c +++ b/src/test/modules/injection_points/injection_points.c @@ -452,4 +452,4 @@ injection_points_detach(PG_FUNCTION_ARGS) } PG_RETURN_VOID(); -} +} \ No newline at end of file diff --git a/src/test/modules/test_slru/Makefile b/src/test/modules/test_slru/Makefile index 936886753b7..a0f49129079 100644 --- a/src/test/modules/test_slru/Makefile +++ b/src/test/modules/test_slru/Makefile @@ -6,6 +6,9 @@ OBJS = \ test_slru.o PGFILEDESC = "test_slru - test module for SLRUs" +EXTRA_INSTALL=src/test/modules/injection_points +TAP_TESTS = 1 + EXTENSION = test_slru DATA = test_slru--1.0.sql diff --git a/src/test/modules/test_slru/meson.build b/src/test/modules/test_slru/meson.build index ce91e606313..4a5bc6349a4 100644 --- a/src/test/modules/test_slru/meson.build +++ b/src/test/modules/test_slru/meson.build @@ -32,4 +32,12 @@ tests += { 'regress_args': ['--temp-config', files('test_slru.conf')], 'runningcheck': false, }, + 'tap': { + 'env': { + 'enable_injection_points': get_option('injection_points') ? 'yes' : 'no', + }, + 'tests': [ + 't/001_multixact.pl' + ], + }, } diff --git a/src/test/modules/test_slru/t/001_multixact.pl b/src/test/modules/test_slru/t/001_multixact.pl new file mode 100644 index 00000000000..b46e0994351 --- /dev/null +++ b/src/test/modules/test_slru/t/001_multixact.pl @@ -0,0 +1,66 @@ + +# Copyright (c) 2024, PostgreSQL Global Development Group + +use strict; +use warnings FATAL => 'all'; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; + +use Test::More; + +my ($node, $result); + +$node = PostgreSQL::Test::Cluster->new('multixact_CV_sleep'); +$node->init; +$node->append_conf('postgresql.conf', + "shared_preload_libraries = 'test_slru'"); +$node->start; +$node->safe_psql('postgres', q(CREATE EXTENSION injection_points)); +$node->safe_psql('postgres', q(CREATE EXTENSION test_slru)); + +# Test for Multixact generation edge case +$node->safe_psql('postgres', q(select injection_points_attach('test_read_multixact','wait'))); +$node->safe_psql('postgres', q(select injection_points_attach('GetMultiXactIdMembers-CV-sleep','notice'))); + +# This session must observe sleep on CV when generating multixact. +# To achive this it first will create a multixact, then pause before reading it. +my $observer = $node->background_psql('postgres'); + +$observer->query_until(qr/start/, +q( + \echo start + select test_read_multixact(test_create_multixact()); +)); + +# This session will create next Multixact, it's necessary to avoid edge case 1 (see multixact.c) +my $creator = $node->background_psql('postgres'); +$node->safe_psql('postgres', q(select injection_points_attach('GetNewMultiXactId-done','wait'))); + +# We expect this query to hand in critical section after generating new multixact, +# but before filling it's offset into SLRU +$creator->query_until(qr/start/, q( + \echo start + select test_create_multixact(); +)); + +# Now we are sure we can reach edge case 2. Proceed session that is reading that multixact. +$node->safe_psql('postgres', q(select injection_points_detach('test_read_multixact'))); + +# Release critical section. We have to do this so everyon can proceed. +# But this is inherent race condition, I hope the tast will not be unstable here. +# The only way to stabilize it will be adding some sleep here. +$node->safe_psql('postgres', q(select injection_points_detach('GetNewMultiXactId-done'))); + +# Here goes the whole purpose of this test: see that sleep in fact occured. +ok( pump_until( + $observer->{run}, $observer->{timeout}, + \$observer->{stderr}, qr/notice triggered for injection point GetMultiXactIdMembers-CV-sleep/), + "sleep observed"); + +$observer->quit; + +$creator->quit; + +$node->stop; +done_testing(); diff --git a/src/test/modules/test_slru/test_slru--1.0.sql b/src/test/modules/test_slru/test_slru--1.0.sql index 202e8da3fde..58300c59a77 100644 --- a/src/test/modules/test_slru/test_slru--1.0.sql +++ b/src/test/modules/test_slru/test_slru--1.0.sql @@ -19,3 +19,9 @@ CREATE OR REPLACE FUNCTION test_slru_page_truncate(bigint) RETURNS VOID AS 'MODULE_PATHNAME', 'test_slru_page_truncate' LANGUAGE C; CREATE OR REPLACE FUNCTION test_slru_delete_all() RETURNS VOID AS 'MODULE_PATHNAME', 'test_slru_delete_all' LANGUAGE C; + + +CREATE OR REPLACE FUNCTION test_create_multixact() RETURNS xid + AS 'MODULE_PATHNAME', 'test_create_multixact' LANGUAGE C; +CREATE OR REPLACE FUNCTION test_read_multixact(xid) RETURNS VOID + AS 'MODULE_PATHNAME', 'test_read_multixact'LANGUAGE C; \ No newline at end of file diff --git a/src/test/modules/test_slru/test_slru.c b/src/test/modules/test_slru/test_slru.c index d227b067034..b3fabc3b6ed 100644 --- a/src/test/modules/test_slru/test_slru.c +++ b/src/test/modules/test_slru/test_slru.c @@ -14,13 +14,16 @@ #include "postgres.h" +#include "access/multixact.h" #include "access/slru.h" +#include "access/xact.h" #include "access/transam.h" #include "miscadmin.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/shmem.h" #include "utils/builtins.h" +#include "utils/injection_point.h" PG_MODULE_MAGIC; @@ -36,6 +39,8 @@ PG_FUNCTION_INFO_V1(test_slru_page_sync); PG_FUNCTION_INFO_V1(test_slru_page_delete); PG_FUNCTION_INFO_V1(test_slru_page_truncate); PG_FUNCTION_INFO_V1(test_slru_delete_all); +PG_FUNCTION_INFO_V1(test_create_multixact); +PG_FUNCTION_INFO_V1(test_read_multixact); /* Number of SLRU page slots */ #define NUM_TEST_BUFFERS 16 @@ -260,3 +265,27 @@ _PG_init(void) prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = test_slru_shmem_startup; } + +Datum +test_create_multixact(PG_FUNCTION_ARGS) +{ + MultiXactId id; + MultiXactIdSetOldestMember(); + id = MultiXactIdCreate(GetCurrentTransactionId(), MultiXactStatusUpdate, + GetCurrentTransactionId(), MultiXactStatusForShare); + PG_RETURN_TRANSACTIONID(id); +} + +Datum +test_read_multixact(PG_FUNCTION_ARGS) +{ + MultiXactId id = PG_GETARG_TRANSACTIONID(0); + MultiXactMember *members; + INJECTION_POINT("test_read_multixact"); + /* discard caches */ + AtEOXact_MultiXact(); + + if (GetMultiXactIdMembers(id,&members,false, false) == -1) + elog(ERROR, "MultiXactId not found"); + PG_RETURN_VOID(); +} \ No newline at end of file -- 2.37.1 (Apple Git-137.1)