Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit768a9fd

Browse files
committed
Add injection-point test for new multixact CV usage
Before commita0e0fb1, multixact.c contained a case in themultixact-read path where it would loop sleeping 1ms each time untilanother multixact-create path completed, which was uncovered by anytests. That commit changed the code to rely on a condition variableinstead. Add a test now, which relies on injection points and "loading"thereof (because of it being in a critical section), per commit4b21100.Author: Andrey Borodin <x4mmm@yandex-team.ru>Reviewed-by: Michaël Paquier <michael@paquier.xyz>Discussion:https://postgr.es/m/0925F9A9-4D53-4B27-A87E-3D83A757B0E0@yandex-team.ru
1 parent4d93bbd commit768a9fd

File tree

6 files changed

+207
-1
lines changed

6 files changed

+207
-1
lines changed

‎src/backend/access/transam/multixact.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
#include"storage/proc.h"
8989
#include"storage/procarray.h"
9090
#include"utils/fmgrprotos.h"
91+
#include"utils/injection_point.h"
9192
#include"utils/guc_hooks.h"
9293
#include"utils/memutils.h"
9394

@@ -868,6 +869,8 @@ MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
868869
*/
869870
multi=GetNewMultiXactId(nmembers,&offset);
870871

872+
INJECTION_POINT("multixact-create-from-members");
873+
871874
/* Make an XLOG entry describing the new MXID. */
872875
xlrec.mid=multi;
873876
xlrec.moff=offset;
@@ -1480,6 +1483,8 @@ GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members,
14801483
LWLockRelease(lock);
14811484
CHECK_FOR_INTERRUPTS();
14821485

1486+
INJECTION_POINT("multixact-get-members-cv-sleep");
1487+
14831488
ConditionVariableSleep(&MultiXactState->nextoff_cv,
14841489
WAIT_EVENT_MULTIXACT_CREATION);
14851490
slept= true;

‎src/test/modules/test_slru/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@
33
MODULE_big = test_slru
44
OBJS =\
55
$(WIN32RES)\
6-
test_slru.o
6+
test_slru.o\
7+
test_multixact.o
78
PGFILEDESC = "test_slru - test module for SLRUs"
89

10+
EXTRA_INSTALL=src/test/modules/injection_points
11+
exportenable_injection_pointsenable_injection_points
12+
TAP_TESTS = 1
13+
914
EXTENSION = test_slru
1015
DATA = test_slru--1.0.sql
1116

‎src/test/modules/test_slru/meson.build

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
test_slru_sources=files(
44
'test_slru.c',
5+
'test_multixact.c',
56
)
67

78
if host_system=='windows'
@@ -32,4 +33,12 @@ tests += {
3233
'regress_args': ['--temp-config',files('test_slru.conf')],
3334
'runningcheck':false,
3435
},
36+
'tap': {
37+
'env': {
38+
'enable_injection_points':get_option('injection_points') ?'yes' :'no',
39+
},
40+
'tests': [
41+
't/001_multixact.pl'
42+
],
43+
},
3544
}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Copyright (c) 2024, PostgreSQL Global Development Group
2+
3+
# This test verifies edge case of reading a multixact:
4+
# when we have multixact that is followed by exactly one another multixact,
5+
# and another multixact have no offset yet, we must wait until this offset
6+
# becomes observable. Previously we used to wait for 1ms in a loop in this
7+
# case, but now we use CV for this. This test is exercising such a sleep.
8+
9+
use strict;
10+
use warningsFATAL=>'all';
11+
12+
use PostgreSQL::Test::Cluster;
13+
use PostgreSQL::Test::Utils;
14+
15+
use Test::More;
16+
17+
if ($ENV{enable_injection_points}ne'yes')
18+
{
19+
planskip_all=>'Injection points not supported by this build';
20+
}
21+
22+
my ($node,$result);
23+
24+
$node = PostgreSQL::Test::Cluster->new('mike');
25+
$node->init;
26+
$node->append_conf('postgresql.conf',
27+
"shared_preload_libraries = 'test_slru'");
28+
$node->start;
29+
$node->safe_psql('postgres',q(CREATE EXTENSION injection_points));
30+
$node->safe_psql('postgres',q(CREATE EXTENSION test_slru));
31+
32+
# Test for Multixact generation edge case
33+
$node->safe_psql('postgres',
34+
q{select injection_points_attach('test-multixact-read','wait')});
35+
$node->safe_psql('postgres',
36+
q{select injection_points_attach('multixact-get-members-cv-sleep','wait')}
37+
);
38+
39+
# This session must observe sleep on the condition variable while generating a
40+
# multixact. To achieve this it first will create a multixact, then pause
41+
# before reading it.
42+
my$observer =$node->background_psql('postgres');
43+
44+
# This query will create a multixact, and hang just before reading it.
45+
$observer->query_until(
46+
qr/start/,
47+
q{
48+
\echo start
49+
SELECT test_read_multixact(test_create_multixact());
50+
});
51+
$node->wait_for_event('client backend','test-multixact-read');
52+
53+
# This session will create the next Multixact. This is necessary to avoid
54+
# multixact.c's non-sleeping edge case 1.
55+
my$creator =$node->background_psql('postgres');
56+
$node->safe_psql('postgres',
57+
q{SELECT injection_points_attach('multixact-create-from-members','wait');}
58+
);
59+
60+
# We expect this query to hang in the critical section after generating new
61+
# multixact, but before filling it's offset into SLRU.
62+
# Running an injection point inside a critical section requires it to be
63+
# loaded beforehand.
64+
$creator->query_until(
65+
qr/start/,q{
66+
\echo start
67+
SELECT injection_points_load('multixact-create-from-members');
68+
SELECT test_create_multixact();
69+
});
70+
71+
$node->wait_for_event('client backend','multixact-create-from-members');
72+
73+
# Ensure we have the backends waiting that we expect
74+
is($node->safe_psql(
75+
'postgres',
76+
q{SELECT string_agg(wait_event, ', ' ORDER BY wait_event)
77+
FROM pg_stat_activity WHERE wait_event_type = 'InjectionPoint'}
78+
),
79+
'multixact-create-from-members, test-multixact-read',
80+
"matching injection point waits");
81+
82+
# Now wake observer to get it to read the initial multixact. A subsequent
83+
# multixact already exists, but that one doesn't have an offset assigned, so
84+
# this will hit multixact.c's edge case 2.
85+
$node->safe_psql('postgres',
86+
q{SELECT injection_points_wakeup('test-multixact-read')});
87+
$node->wait_for_event('client backend','multixact-get-members-cv-sleep');
88+
89+
# Ensure we have the backends waiting that we expect
90+
is($node->safe_psql(
91+
'postgres',
92+
q{SELECT string_agg(wait_event, ', ' ORDER BY wait_event)
93+
FROM pg_stat_activity WHERE wait_event_type = 'InjectionPoint'}
94+
),
95+
'multixact-create-from-members, multixact-get-members-cv-sleep',
96+
"matching injection point waits");
97+
98+
# Now we have two backends waiting in multixact-create-from-members and
99+
# multixact-get-members-cv-sleep. Also we have 3 injections points set to wait.
100+
# If we wakeup multixact-get-members-cv-sleep it will happen again, so we must
101+
# detach it first. So let's detach all injection points, then wake up all
102+
# backends.
103+
104+
$node->safe_psql('postgres',
105+
q{SELECT injection_points_detach('test-multixact-read')});
106+
$node->safe_psql('postgres',
107+
q{SELECT injection_points_detach('multixact-create-from-members')});
108+
$node->safe_psql('postgres',
109+
q{SELECT injection_points_detach('multixact-get-members-cv-sleep')});
110+
111+
$node->safe_psql('postgres',
112+
q{SELECT injection_points_wakeup('multixact-create-from-members')});
113+
$node->safe_psql('postgres',
114+
q{SELECT injection_points_wakeup('multixact-get-members-cv-sleep')});
115+
116+
# Background psql will now be able to read the result and disconnect.
117+
$observer->quit;
118+
$creator->quit;
119+
120+
$node->stop;
121+
122+
# If we reached this point - everything is OK.
123+
ok(1);
124+
done_testing();
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*--------------------------------------------------------------------------
2+
*
3+
* test_multixact.c
4+
*Support code for multixact testing
5+
*
6+
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7+
* Portions Copyright (c) 1994, Regents of the University of California
8+
*
9+
* IDENTIFICATION
10+
*src/test/modules/test_slru/test_multixact.c
11+
*
12+
* -------------------------------------------------------------------------
13+
*/
14+
15+
#include"postgres.h"
16+
17+
#include"access/multixact.h"
18+
#include"access/xact.h"
19+
#include"utils/builtins.h"
20+
#include"utils/injection_point.h"
21+
22+
PG_FUNCTION_INFO_V1(test_create_multixact);
23+
PG_FUNCTION_INFO_V1(test_read_multixact);
24+
25+
/*
26+
* Produces multixact with 2 current xids
27+
*/
28+
Datum
29+
test_create_multixact(PG_FUNCTION_ARGS)
30+
{
31+
MultiXactIdid;
32+
33+
MultiXactIdSetOldestMember();
34+
id=MultiXactIdCreate(GetCurrentTransactionId(),MultiXactStatusUpdate,
35+
GetCurrentTransactionId(),MultiXactStatusForShare);
36+
PG_RETURN_TRANSACTIONID(id);
37+
}
38+
39+
/*
40+
* Reads given multixact after running an injection point. Discards local cache
41+
* to make a real read. Tailored for multixact testing.
42+
*/
43+
Datum
44+
test_read_multixact(PG_FUNCTION_ARGS)
45+
{
46+
MultiXactIdid=PG_GETARG_TRANSACTIONID(0);
47+
MultiXactMember*members;
48+
49+
INJECTION_POINT("test-multixact-read");
50+
/* discard caches */
51+
AtEOXact_MultiXact();
52+
53+
if (GetMultiXactIdMembers(id,&members, false, false)==-1)
54+
elog(ERROR,"MultiXactId not found");
55+
56+
PG_RETURN_VOID();
57+
}

‎src/test/modules/test_slru/test_slru--1.0.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,9 @@ CREATE OR REPLACE FUNCTION test_slru_page_truncate(bigint) RETURNS VOID
1919
AS'MODULE_PATHNAME','test_slru_page_truncate' LANGUAGE C;
2020
CREATE OR REPLACEFUNCTIONtest_slru_delete_all() RETURNS VOID
2121
AS'MODULE_PATHNAME','test_slru_delete_all' LANGUAGE C;
22+
23+
24+
CREATE OR REPLACEFUNCTIONtest_create_multixact() RETURNS xid
25+
AS'MODULE_PATHNAME','test_create_multixact' LANGUAGE C;
26+
CREATE OR REPLACEFUNCTIONtest_read_multixact(xid) RETURNS VOID
27+
AS'MODULE_PATHNAME','test_read_multixact'LANGUAGE C;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp