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

Commit2950544

Browse files
committed
Improve test coverage for LISTEN/NOTIFY.
Back-patch commitb10f40b into older branches. This adds reportingof NOTIFY messages to isolationtester.c, and extends the async-notifytest to include direct tests of basic NOTIFY functionality.This provides useful infrastructure for testing a bug fix I'm aboutto back-patch, and there seems no good reason not to have better testsof LISTEN/NOTIFY in the back branches. The commit's survived longenough in HEAD to make it unlikely that it will cause problems.Back-patch as far as 9.6. isolationtester.c changed too much in 9.6to make it sane to try to fix older branches this way, and I don'treally want to back-patch those changes too.Discussion:https://postgr.es/m/31304.1564246011@sss.pgh.pa.us
1 parent785206a commit2950544

File tree

3 files changed

+211
-50
lines changed

3 files changed

+211
-50
lines changed
Lines changed: 91 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,102 @@
11
Parsed test spec with 2 sessions
22

3-
starting permutation: listen begin check notify check
4-
step listen: LISTEN a;
5-
step begin: BEGIN;
6-
step check: SELECT pg_notification_queue_usage() > 0 AS nonzero;
3+
starting permutation: listenc notify1 notify2 notify3 notifyf
4+
step listenc: LISTEN c1; LISTEN c2;
5+
step notify1: NOTIFY c1;
6+
notifier: NOTIFY "c1" with payload "" from notifier
7+
step notify2: NOTIFY c2, 'payload';
8+
notifier: NOTIFY "c2" with payload "payload" from notifier
9+
step notify3: NOTIFY c3, 'payload3';
10+
step notifyf: SELECT pg_notify('c2', NULL);
11+
pg_notify
12+
13+
14+
notifier: NOTIFY "c2" with payload "" from notifier
15+
16+
starting permutation: listenc notifyd1 notifyd2 notifys1
17+
step listenc: LISTEN c1; LISTEN c2;
18+
step notifyd1: NOTIFY c2, 'payload'; NOTIFY c1; NOTIFY "c2", 'payload';
19+
notifier: NOTIFY "c2" with payload "payload" from notifier
20+
notifier: NOTIFY "c1" with payload "" from notifier
21+
step notifyd2: NOTIFY c1; NOTIFY c1; NOTIFY c1, 'p1'; NOTIFY c1, 'p2';
22+
notifier: NOTIFY "c1" with payload "" from notifier
23+
notifier: NOTIFY "c1" with payload "p1" from notifier
24+
notifier: NOTIFY "c1" with payload "p2" from notifier
25+
step notifys1:
26+
BEGIN;
27+
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload';
28+
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload';
29+
SAVEPOINT s1;
30+
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload';
31+
NOTIFY c1, 'payloads'; NOTIFY "c2", 'payloads';
32+
NOTIFY c1, 'payload'; NOTIFY "c2", 'payload';
33+
NOTIFY c1, 'payloads'; NOTIFY "c2", 'payloads';
34+
RELEASE SAVEPOINT s1;
35+
SAVEPOINT s2;
36+
NOTIFY c1, 'rpayload'; NOTIFY "c2", 'rpayload';
37+
NOTIFY c1, 'rpayloads'; NOTIFY "c2", 'rpayloads';
38+
NOTIFY c1, 'rpayload'; NOTIFY "c2", 'rpayload';
39+
NOTIFY c1, 'rpayloads'; NOTIFY "c2", 'rpayloads';
40+
ROLLBACK TO SAVEPOINT s2;
41+
COMMIT;
42+
43+
notifier: NOTIFY "c1" with payload "payload" from notifier
44+
notifier: NOTIFY "c2" with payload "payload" from notifier
45+
notifier: NOTIFY "c1" with payload "payload" from notifier
46+
notifier: NOTIFY "c2" with payload "payload" from notifier
47+
notifier: NOTIFY "c1" with payload "payloads" from notifier
48+
notifier: NOTIFY "c2" with payload "payloads" from notifier
49+
50+
starting permutation: llisten notify1 notify2 notify3 notifyf lcheck
51+
step llisten: LISTEN c1; LISTEN c2;
52+
step notify1: NOTIFY c1;
53+
step notify2: NOTIFY c2, 'payload';
54+
step notify3: NOTIFY c3, 'payload3';
55+
step notifyf: SELECT pg_notify('c2', NULL);
56+
pg_notify
57+
58+
59+
step lcheck: SELECT 1 AS x;
60+
x
61+
62+
1
63+
listener: NOTIFY "c1" with payload "" from notifier
64+
listener: NOTIFY "c2" with payload "payload" from notifier
65+
listener: NOTIFY "c2" with payload "" from notifier
66+
67+
starting permutation: listenc llisten notify1 notify2 notify3 notifyf lcheck
68+
step listenc: LISTEN c1; LISTEN c2;
69+
step llisten: LISTEN c1; LISTEN c2;
70+
step notify1: NOTIFY c1;
71+
notifier: NOTIFY "c1" with payload "" from notifier
72+
step notify2: NOTIFY c2, 'payload';
73+
notifier: NOTIFY "c2" with payload "payload" from notifier
74+
step notify3: NOTIFY c3, 'payload3';
75+
step notifyf: SELECT pg_notify('c2', NULL);
76+
pg_notify
77+
78+
79+
notifier: NOTIFY "c2" with payload "" from notifier
80+
step lcheck: SELECT 1 AS x;
81+
x
82+
83+
1
84+
listener: NOTIFY "c1" with payload "" from notifier
85+
listener: NOTIFY "c2" with payload "payload" from notifier
86+
listener: NOTIFY "c2" with payload "" from notifier
87+
88+
starting permutation: llisten lbegin usage bignotify usage
89+
step llisten: LISTEN c1; LISTEN c2;
90+
step lbegin: BEGIN;
91+
step usage: SELECT pg_notification_queue_usage() > 0 AS nonzero;
792
nonzero
893

994
f
10-
stepnotify: SELECT count(pg_notify('a', s::text)) FROM generate_series(1, 1000) s;
95+
stepbignotify: SELECT count(pg_notify('c1', s::text)) FROM generate_series(1, 1000) s;
1196
count
1297

1398
1000
14-
stepcheck: SELECT pg_notification_queue_usage() > 0 AS nonzero;
99+
stepusage: SELECT pg_notification_queue_usage() > 0 AS nonzero;
15100
nonzero
16101

17102
t

‎src/test/isolation/isolationtester.c

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323

2424
/*
2525
* conns[0] is the global setup, teardown, and watchdog connection. Additional
26-
* connections represent spec-defined sessions.
26+
* connections represent spec-defined sessions. We also track the backend
27+
* PID, in numeric and string formats, for each connection.
2728
*/
2829
staticPGconn**conns=NULL;
29-
staticconstchar**backend_pids=NULL;
30+
staticint*backend_pids=NULL;
31+
staticconstchar**backend_pid_strs=NULL;
3032
staticintnconns=0;
3133

3234
/* In dry run only output permutations to be run by the tester. */
@@ -42,7 +44,7 @@ static void run_permutation(TestSpec *testspec, int nsteps, Step **steps);
4244

4345
#defineSTEP_NONBLOCK0x1/* return 0 as soon as cmd waits for a lock */
4446
#defineSTEP_RETRY0x2/* this is a retry of a previously-waiting cmd */
45-
staticbooltry_complete_step(Step*step,intflags);
47+
staticbooltry_complete_step(TestSpec*testspec,Step*step,intflags);
4648

4749
staticintstep_qsort_cmp(constvoid*a,constvoid*b);
4850
staticintstep_bsearch_cmp(constvoid*a,constvoid*b);
@@ -161,8 +163,10 @@ main(int argc, char **argv)
161163
* extra for lock wait detection and global work.
162164
*/
163165
nconns=1+testspec->nsessions;
164-
conns=calloc(nconns,sizeof(PGconn*));
165-
backend_pids=calloc(nconns,sizeof(*backend_pids));
166+
conns= (PGconn**)pg_malloc0(nconns*sizeof(PGconn*));
167+
backend_pids=pg_malloc0(nconns*sizeof(*backend_pids));
168+
backend_pid_strs=pg_malloc0(nconns*sizeof(*backend_pid_strs));
169+
166170
for (i=0;i<nconns;i++)
167171
{
168172
conns[i]=PQconnectdb(conninfo);
@@ -188,26 +192,9 @@ main(int argc, char **argv)
188192
blackholeNoticeProcessor,
189193
NULL);
190194

191-
/* Get the backend pid for lock wait checking. */
192-
res=PQexec(conns[i],"SELECT pg_backend_pid()");
193-
if (PQresultStatus(res)==PGRES_TUPLES_OK)
194-
{
195-
if (PQntuples(res)==1&&PQnfields(res)==1)
196-
backend_pids[i]=pg_strdup(PQgetvalue(res,0,0));
197-
else
198-
{
199-
fprintf(stderr,"backend pid query returned %d rows and %d columns, expected 1 row and 1 column",
200-
PQntuples(res),PQnfields(res));
201-
exit_nicely();
202-
}
203-
}
204-
else
205-
{
206-
fprintf(stderr,"backend pid query failed: %s",
207-
PQerrorMessage(conns[i]));
208-
exit_nicely();
209-
}
210-
PQclear(res);
195+
/* Save each connection's backend PID for subsequent use. */
196+
backend_pids[i]=PQbackendPID(conns[i]);
197+
backend_pid_strs[i]=psprintf("%d",backend_pids[i]);
211198
}
212199

213200
/* Set the session index fields in steps. */
@@ -232,9 +219,9 @@ main(int argc, char **argv)
232219
appendPQExpBufferStr(&wait_query,
233220
"SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{");
234221
/* The spec syntax requires at least one session; assume that here. */
235-
appendPQExpBufferStr(&wait_query,backend_pids[1]);
222+
appendPQExpBufferStr(&wait_query,backend_pid_strs[1]);
236223
for (i=2;i<nconns;i++)
237-
appendPQExpBuffer(&wait_query,",%s",backend_pids[i]);
224+
appendPQExpBuffer(&wait_query,",%s",backend_pid_strs[i]);
238225
appendPQExpBufferStr(&wait_query,"}')");
239226

240227
res=PQprepare(conns[0],PREP_WAITING,wait_query.data,0,NULL);
@@ -553,7 +540,7 @@ run_permutation(TestSpec *testspec, int nsteps, Step **steps)
553540
oldstep=waiting[w];
554541

555542
/* Wait for previous step on this connection. */
556-
try_complete_step(oldstep,STEP_RETRY);
543+
try_complete_step(testspec,oldstep,STEP_RETRY);
557544

558545
/* Remove that step from the waiting[] array. */
559546
if (w+1<nwaiting)
@@ -575,7 +562,8 @@ run_permutation(TestSpec *testspec, int nsteps, Step **steps)
575562
nerrorstep=0;
576563
while (w<nwaiting)
577564
{
578-
if (try_complete_step(waiting[w],STEP_NONBLOCK |STEP_RETRY))
565+
if (try_complete_step(testspec,waiting[w],
566+
STEP_NONBLOCK |STEP_RETRY))
579567
{
580568
/* Still blocked on a lock, leave it alone. */
581569
w++;
@@ -604,14 +592,15 @@ run_permutation(TestSpec *testspec, int nsteps, Step **steps)
604592
}
605593

606594
/* Try to complete this step without blocking. */
607-
mustwait=try_complete_step(step,STEP_NONBLOCK);
595+
mustwait=try_complete_step(testspec,step,STEP_NONBLOCK);
608596

609597
/* Check for completion of any steps that were previously waiting. */
610598
w=0;
611599
nerrorstep=0;
612600
while (w<nwaiting)
613601
{
614-
if (try_complete_step(waiting[w],STEP_NONBLOCK |STEP_RETRY))
602+
if (try_complete_step(testspec,waiting[w],
603+
STEP_NONBLOCK |STEP_RETRY))
615604
w++;
616605
else
617606
{
@@ -634,7 +623,7 @@ run_permutation(TestSpec *testspec, int nsteps, Step **steps)
634623
/* Wait for any remaining queries. */
635624
for (w=0;w<nwaiting;++w)
636625
{
637-
try_complete_step(waiting[w],STEP_RETRY);
626+
try_complete_step(testspec,waiting[w],STEP_RETRY);
638627
report_error_message(waiting[w]);
639628
}
640629

@@ -697,7 +686,7 @@ run_permutation(TestSpec *testspec, int nsteps, Step **steps)
697686
* a lock, returns true. Otherwise, returns false.
698687
*/
699688
staticbool
700-
try_complete_step(Step*step,intflags)
689+
try_complete_step(TestSpec*testspec,Step*step,intflags)
701690
{
702691
PGconn*conn=conns[1+step->session];
703692
fd_setread_set;
@@ -706,6 +695,7 @@ try_complete_step(Step *step, int flags)
706695
intsock=PQsocket(conn);
707696
intret;
708697
PGresult*res;
698+
PGnotify*notify;
709699
boolcanceled= false;
710700

711701
if (sock<0)
@@ -742,7 +732,7 @@ try_complete_step(Step *step, int flags)
742732
boolwaiting;
743733

744734
res=PQexecPrepared(conns[0],PREP_WAITING,1,
745-
&backend_pids[step->session+1],
735+
&backend_pid_strs[step->session+1],
746736
NULL,NULL,0);
747737
if (PQresultStatus(res)!=PGRES_TUPLES_OK||
748738
PQntuples(res)!=1)
@@ -884,6 +874,36 @@ try_complete_step(Step *step, int flags)
884874
PQclear(res);
885875
}
886876

877+
/* Report any available NOTIFY messages, too */
878+
PQconsumeInput(conn);
879+
while ((notify=PQnotifies(conn))!=NULL)
880+
{
881+
/* Try to identify which session it came from */
882+
constchar*sendername=NULL;
883+
charpidstring[32];
884+
inti;
885+
886+
for (i=0;i<testspec->nsessions;i++)
887+
{
888+
if (notify->be_pid==backend_pids[i+1])
889+
{
890+
sendername=testspec->sessions[i]->name;
891+
break;
892+
}
893+
}
894+
if (sendername==NULL)
895+
{
896+
/* Doesn't seem to be any test session, so show the hard way */
897+
snprintf(pidstring,sizeof(pidstring),"PID %d",notify->be_pid);
898+
sendername=pidstring;
899+
}
900+
printf("%s: NOTIFY \"%s\" with payload \"%s\" from %s\n",
901+
testspec->sessions[step->session]->name,
902+
notify->relname,notify->extra,sendername);
903+
PQfreemem(notify);
904+
PQconsumeInput(conn);
905+
}
906+
887907
return false;
888908
}
889909

Lines changed: 66 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,70 @@
1-
# Verify that pg_notification_queue_usage correctly reports a non-zero result,
2-
# after submitting notifications while another connection is listening for
3-
# those notifications and waiting inside an active transaction.
1+
# Tests for LISTEN/NOTIFY
42

5-
session"listener"
6-
step"listen"{LISTENa;}
7-
step"begin"{ BEGIN;}
8-
teardown{ROLLBACK;UNLISTEN *;}
3+
# Most of these tests use only the "notifier" session and hence exercise only
4+
# self-notifies, which are convenient because they minimize timing concerns.
5+
# Note we assume that eachstepis delivered to the backend as a single Query
6+
# message so it will run as one transaction.
97

108
session"notifier"
11-
step"check"{SELECTpg_notification_queue_usage() >0ASnonzero;}
12-
step"notify"{SELECTcount(pg_notify('a',s::text))FROMgenerate_series(1,1000)s;}
9+
step"listenc"{LISTENc1;LISTENc2;}
10+
step"notify1"{NOTIFYc1;}
11+
step"notify2"{NOTIFYc2,'payload';}
12+
step"notify3"{NOTIFYc3,'payload3';}# not listening to c3
13+
step"notifyf"{SELECTpg_notify('c2',NULL);}
14+
step"notifyd1"{NOTIFYc2,'payload';NOTIFYc1;NOTIFY"c2",'payload';}
15+
step"notifyd2"{NOTIFYc1;NOTIFYc1;NOTIFYc1,'p1';NOTIFYc1,'p2';}
16+
step"notifys1"{
17+
BEGIN;
18+
NOTIFYc1,'payload';NOTIFY"c2",'payload';
19+
NOTIFYc1,'payload';NOTIFY"c2",'payload';
20+
SAVEPOINTs1;
21+
NOTIFYc1,'payload';NOTIFY"c2",'payload';
22+
NOTIFYc1,'payloads';NOTIFY"c2",'payloads';
23+
NOTIFYc1,'payload';NOTIFY"c2",'payload';
24+
NOTIFYc1,'payloads';NOTIFY"c2",'payloads';
25+
RELEASESAVEPOINTs1;
26+
SAVEPOINTs2;
27+
NOTIFYc1,'rpayload';NOTIFY"c2",'rpayload';
28+
NOTIFYc1,'rpayloads';NOTIFY"c2",'rpayloads';
29+
NOTIFYc1,'rpayload';NOTIFY"c2",'rpayload';
30+
NOTIFYc1,'rpayloads';NOTIFY"c2",'rpayloads';
31+
ROLLBACKTOSAVEPOINTs2;
32+
COMMIT;
33+
}
34+
step"usage"{SELECTpg_notification_queue_usage() >0ASnonzero;}
35+
step"bignotify"{SELECTcount(pg_notify('c1',s::text))FROMgenerate_series(1,1000)s;}
36+
teardown{UNLISTEN *;}
37+
38+
# The listener session is used for cross-backend notify checks.
39+
40+
session"listener"
41+
step"llisten"{LISTENc1;LISTENc2;}
42+
step"lcheck"{SELECT1ASx;}
43+
step"lbegin"{ BEGIN;}
44+
teardown{UNLISTEN *;}
45+
46+
47+
# Trivial cases.
48+
permutation"listenc""notify1""notify2""notify3""notifyf"
49+
50+
# Check simple and less-simple deduplication.
51+
permutation"listenc""notifyd1""notifyd2""notifys1"
52+
53+
# Cross-backend notification delivery. We use a "select 1" to force the
54+
# listener session to check for notifies. In principle we could just wait
55+
# for delivery, but that would require extra support in isolationtester
56+
# and might have portability-of-timing issues.
57+
permutation"llisten""notify1""notify2""notify3""notifyf""lcheck"
58+
59+
# Again, with local delivery too.
60+
permutation"listenc""llisten""notify1""notify2""notify3""notifyf""lcheck"
61+
62+
# Verify that pg_notification_queue_usage correctly reports a non-zero result,
63+
# after submitting notifications while another connection is listening for
64+
# those notifications and waiting inside an active transaction. We have to
65+
# fill a page of the notify SLRU to make this happen, which is a good deal
66+
# of traffic. To not bloat the expected output, we intentionally don't
67+
# commit the listener's transaction, so that it never reports these events.
68+
# Hence, this should be the last test in this script.
1369

14-
permutation"listen""begin""check""notify""check"
70+
permutation"llisten""lbegin""usage""bignotify""usage"

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp