isolationtester - allow a session specific connection string
Hi hackers.
I wanted some way to test overlapping transactions from different
publisher sessions so I could better test the logical replication
"parallel apply" feature being developed in another thread [1]parallel apply thread - /messages/by-id/CAA4eK1+wyN6zpaHUkCLorEWNx75MG0xhMwcFhvjqm2KURZEAGw@mail.gmail.com. AFAIK
currently there is no way to do this kind of test except manually
(e.g. using separate psql sessions).
Meanwhile, using the isolationtester spec tests [2]isolation tests - https://github.com/postgres/postgres/blob/master/src/test/isolation/README it is already
possible to test overlapping transactions on multiple sessions. So
isolationtester already does almost everything I wanted except that it
currently only knows about a single connection string (either default
or passed as argument) which every one of the "spec sessions" uses. In
contrast, for my pub/sub testing, I wanted multiple servers.
The test_decoding tests [3]test_decoding spec tests - https://github.com/postgres/postgres/tree/master/contrib/test_decoding/specs have specs a bit similar to this - the
difference is that I want to observe subscriber-side apply workers
execute and actually do something.
~
My patch/idea makes a small change to the isolationtester spec
grammar. Now each session can optionally specify its own connection
string. When specified, this will override any connection string for
that session that would otherwise have been used. This is the only
change.
With this change now it is possible to write spec test code like
below. Here I have 2 publisher sessions and 1 subscriber session, with
my new session ‘conninfo’ specified appropriately for each session
======
# This test assumes there is already setup as follows:
#
# PG server for publisher (running on port 7651)
# - has TABLE tbl
# - has PUBLICATION pub1
#
# PG server for subscriber (running on port 7652)
# - has TABLE tbl
# - has SUBSCRIPTION sub1 subscribing to pub1
#
################
# Publisher node
################
session ps1
conninfo "host=localhost port=7651"
setup
{
TRUNCATE TABLE tbl;
}
step ps1_ins { INSERT INTO tbl VALUES (111); }
step ps1_sel { SELECT * FROM tbl ORDER BY id; }
step ps1_begin { BEGIN; }
step ps1_commit { COMMIT; }
step ps1_rollback { ROLLBACK; }
session ps2
conninfo "host=localhost port=7651"
step ps2_ins { INSERT INTO tbl VALUES (222); }
step ps2_sel { SELECT * FROM tbl ORDER BY id; }
step ps2_begin { BEGIN; }
step ps2_commit { COMMIT; }
step ps2_rollback { ROLLBACK; }
#################
# Subscriber node
#################
session sub
conninfo "host=localhost port=7652"
setup
{
TRUNCATE TABLE tbl;
}
step sub_sleep { SELECT pg_sleep(3); }
step sub_sel { SELECT * FROM tbl ORDER BY id; }
#######
# Tests
#######
# overlapping tx commits
permutation ps1_begin ps1_ins ps2_begin ps2_ins ps2_commit ps1_commit
sub_sleep sub_sel
permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_commit
sub_sleep sub_sel
======
Because there is still some external setup needed to make the 2
servers (with their own configurations and publication/subscription)
this kind of spec test can't be added to the 'isolation_schedule'
file. But even so, it seems to be working OK, so I think this
isolationtester enhancement can be an efficient way to write and run
some difficult pub/sub regression tests without having to test
everything entirely manually each time.
Thoughts?
~~
PSA
v1-0001 - This is the enhancement to add 'conninfo' to the isloationtester.
v1-0002 - An example of how 'conninfo' can be used (requires external setup)
test_init.sh - this is my external setup script pre-requisite for the
pub-sub.spec in v1-0002
------
[1]: parallel apply thread - /messages/by-id/CAA4eK1+wyN6zpaHUkCLorEWNx75MG0xhMwcFhvjqm2KURZEAGw@mail.gmail.com
/messages/by-id/CAA4eK1+wyN6zpaHUkCLorEWNx75MG0xhMwcFhvjqm2KURZEAGw@mail.gmail.com
[2]: isolation tests - https://github.com/postgres/postgres/blob/master/src/test/isolation/README
https://github.com/postgres/postgres/blob/master/src/test/isolation/README
[3]: test_decoding spec tests - https://github.com/postgres/postgres/tree/master/contrib/test_decoding/specs
https://github.com/postgres/postgres/tree/master/contrib/test_decoding/specs
Kind Regards,
Peter Smith
Fujitsu Australia
Attachments:
v1-0001-isolationtester-allow-session-specific-conninfo.patchapplication/octet-stream; name=v1-0001-isolationtester-allow-session-specific-conninfo.patchDownload
From 45d702b45b86a0a09a34f539391e0d87a62dce33 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Mon, 19 Dec 2022 16:27:31 +1100
Subject: [PATCH v1] isolationtester - allow session specific conninfo
---
src/test/isolation/isolationtester.c | 26 +++++++++++++++++++++++++-
src/test/isolation/isolationtester.h | 1 +
src/test/isolation/specparse.y | 20 +++++++++++++-------
src/test/isolation/specscanner.l | 1 +
4 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index 0a66235..76edbf1 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -119,6 +119,8 @@ main(int argc, char **argv)
* as the conninfo string; otherwise default to setting dbname=postgres
* and using environment variables or defaults for all other connection
* parameters.
+ *
+ * Note, this will be overridden by any session specific 'conninfo'.
*/
if (argc > optind)
conninfo = argv[optind];
@@ -153,15 +155,37 @@ main(int argc, char **argv)
for (i = 0; i < nconns; i++)
{
const char *sessionname;
+ const char *sessionconninfo;
if (i == 0)
+ {
sessionname = "control connection";
+ sessionconninfo = NULL;
+ }
else
+ {
sessionname = testspec->sessions[i - 1]->name;
+ sessionconninfo = testspec->sessions[i - 1]->conninfo;
+ }
conns[i].sessionname = sessionname;
- conns[i].conn = PQconnectdb(conninfo);
+ /*
+ * If this spec session has specified a conninfo to use then that
+ * overrides and other conninfo (e.g. passed as an argument)
+ *
+ * Note - the necessary instance to connect to is assumed to exist
+ * already manually setup by the user.
+ */
+ if (sessionconninfo)
+ {
+ fprintf(stderr, "session '%s' specifies connection info '%s'\n", sessionname, sessionconninfo);
+ conns[i].conn = PQconnectdb(sessionconninfo);
+ }
+ else
+ {
+ conns[i].conn = PQconnectdb(conninfo);
+ }
if (PQstatus(conns[i].conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection %d failed: %s",
diff --git a/src/test/isolation/isolationtester.h b/src/test/isolation/isolationtester.h
index 77134b0..317abcd 100644
--- a/src/test/isolation/isolationtester.h
+++ b/src/test/isolation/isolationtester.h
@@ -24,6 +24,7 @@ typedef struct Step Step;
typedef struct
{
char *name;
+ char *conninfo;
char *setupsql;
char *teardownsql;
Step **steps;
diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y
index 657285c..b927362 100644
--- a/src/test/isolation/specparse.y
+++ b/src/test/isolation/specparse.y
@@ -39,7 +39,7 @@ TestSpec parseresult; /* result of parsing is left here */
}
%type <ptr_list> setup_list
-%type <str> opt_setup opt_teardown
+%type <str> opt_conninfo opt_setup opt_teardown
%type <str> setup
%type <ptr_list> step_list session_list permutation_list opt_permutation_list
%type <ptr_list> permutation_step_list blocker_list
@@ -51,7 +51,7 @@ TestSpec parseresult; /* result of parsing is left here */
%token <str> sqlblock identifier
%token <integer> INTEGER
-%token NOTICES PERMUTATION SESSION SETUP STEP TEARDOWN TEST
+%token NOTICES PERMUTATION SESSION CONNINFO SETUP STEP TEARDOWN TEST
%%
@@ -86,6 +86,11 @@ setup_list:
}
;
+opt_conninfo:
+ /* EMPTY */ { $$ = NULL; }
+ | CONNINFO identifier { $$ = $2; }
+ ;
+
opt_setup:
/* EMPTY */ { $$ = NULL; }
| setup { $$ = $1; }
@@ -117,14 +122,15 @@ session_list:
;
session:
- SESSION identifier opt_setup step_list opt_teardown
+ SESSION identifier opt_conninfo opt_setup step_list opt_teardown
{
$$ = pg_malloc(sizeof(Session));
$$->name = $2;
- $$->setupsql = $3;
- $$->steps = (Step **) $4.elements;
- $$->nsteps = $4.nelements;
- $$->teardownsql = $5;
+ $$->conninfo = $3;
+ $$->setupsql = $4;
+ $$->steps = (Step **) $5.elements;
+ $$->nsteps = $5.nelements;
+ $$->teardownsql = $6;
}
;
diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l
index b04696f..3174372 100644
--- a/src/test/isolation/specscanner.l
+++ b/src/test/isolation/specscanner.l
@@ -71,6 +71,7 @@ self [,()*]
%}
/* Keywords (must appear before the {identifier} rule!) */
+conninfo { return CONNINFO; }
notices { return NOTICES; }
permutation { return PERMUTATION; }
session { return SESSION; }
--
1.8.3.1
v1-0002-isolationstester-example-of-pub-sub-spec.patchapplication/octet-stream; name=v1-0002-isolationstester-example-of-pub-sub-spec.patchDownload
From 53f0777e76ca78538744621487f15e25d8b43dd5 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Mon, 19 Dec 2022 16:35:09 +1100
Subject: [PATCH v1] isolationstester - example of pub-sub spec
---
src/test/isolation/Makefile | 3 +
src/test/isolation/expected/pub-sub.out | 249 ++++++++++++++++++++++++++++++++
src/test/isolation/specs/pub-sub.spec | 84 +++++++++++
3 files changed, 336 insertions(+)
create mode 100644 src/test/isolation/expected/pub-sub.out
create mode 100644 src/test/isolation/specs/pub-sub.spec
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index b8738b7..fe7e8cb 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -78,3 +78,6 @@ installcheck-prepared-txns: all temp-install
check-prepared-txns: all temp-install
$(pg_isolation_regress_check) --schedule=$(srcdir)/isolation_schedule prepared-transactions prepared-transactions-cic
+
+check-pub-sub: temp-install
+ $(pg_isolation_regress_check) pub-sub
diff --git a/src/test/isolation/expected/pub-sub.out b/src/test/isolation/expected/pub-sub.out
new file mode 100644
index 0000000..65339f8
--- /dev/null
+++ b/src/test/isolation/expected/pub-sub.out
@@ -0,0 +1,249 @@
+Parsed test spec with 3 sessions
+session 'ps1' specifies connection info 'host=localhost port=7651'
+session 'ps2' specifies connection info 'host=localhost port=7651'
+session 'sub' specifies connection info 'host=localhost port=7652'
+
+starting permutation: ps1_begin ps1_ins ps1_commit ps1_sel ps2_sel sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps1_commit: COMMIT;
+step ps1_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+step ps2_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+
+starting permutation: ps2_begin ps2_ins ps2_commit ps1_sel ps2_sel sub_sleep sub_sel
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps2_commit: COMMIT;
+step ps1_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+step ps2_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+
+starting permutation: ps1_begin ps1_ins ps1_rollback ps1_sel sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps1_rollback: ROLLBACK;
+step ps1_sel: SELECT * FROM tbl ORDER BY id;
+id
+--
+(0 rows)
+
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+id
+--
+(0 rows)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps1_rollback ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_rollback: ROLLBACK;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_rollback sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_commit: COMMIT;
+step ps2_rollback: ROLLBACK;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps2_commit: COMMIT;
+step ps1_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_commit: COMMIT;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps1_ins ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps2_commit: COMMIT;
+step ps1_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps1_ins ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_commit: COMMIT;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps2_ins ps1_ins ps2_commit ps1_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_commit: COMMIT;
+step ps1_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps2_ins ps1_ins ps1_commit ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps1_commit: COMMIT;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
diff --git a/src/test/isolation/specs/pub-sub.spec b/src/test/isolation/specs/pub-sub.spec
new file mode 100644
index 0000000..70c7f4d
--- /dev/null
+++ b/src/test/isolation/specs/pub-sub.spec
@@ -0,0 +1,84 @@
+#
+# Test assumes there is already setup so
+#
+# PG server for publisher (running on port 7651)
+# - has TABLE tbl
+# - has PUBLICATION pub1
+#
+# PG server for subscriber (running on port 7652)
+# - has TABLE tbl
+# - has SUBSCRIPTION sub1 subscribing to pub1
+#
+# ~~~
+#
+# Now the following spec tests are configured to have multiple sessions on the
+# publisher so we can interleave the WAL records to see the effect for the
+# subscription
+#
+# ~~~
+#
+# How to run
+# 1. Run . ./test_init.sh to create the PG instances, table, and publication/subscription
+# 2. Run the isolation tester make check-pub-sub (runs this spec)
+# 3. Check the logs of the PG instances
+#
+
+################
+# Publisher node
+################
+session ps1
+conninfo "host=localhost port=7651"
+setup
+{
+ TRUNCATE TABLE tbl;
+}
+step ps1_ins { INSERT INTO tbl VALUES (111); }
+step ps1_sel { SELECT * FROM tbl ORDER BY id; }
+step ps1_begin { BEGIN; }
+step ps1_commit { COMMIT; }
+step ps1_rollback { ROLLBACK; }
+
+session ps2
+conninfo "host=localhost port=7651"
+step ps2_ins { INSERT INTO tbl VALUES (222); }
+step ps2_sel { SELECT * FROM tbl ORDER BY id; }
+step ps2_begin { BEGIN; }
+step ps2_commit { COMMIT; }
+step ps2_rollback { ROLLBACK; }
+
+#################
+# Subscriber node
+#################
+session sub
+conninfo "host=localhost port=7652"
+setup
+{
+ TRUNCATE TABLE tbl;
+}
+step sub_sleep { SELECT pg_sleep(3); }
+step sub_sel { SELECT * FROM tbl ORDER BY id; }
+
+#######
+# Tests
+#######
+
+# single tx
+permutation ps1_begin ps1_ins ps1_commit ps1_sel ps2_sel sub_sleep sub_sel
+permutation ps2_begin ps2_ins ps2_commit ps1_sel ps2_sel sub_sleep sub_sel
+
+# rollback
+permutation ps1_begin ps1_ins ps1_rollback ps1_sel sub_sleep sub_sel
+
+# overlapping tx rollback and commit
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_rollback ps2_commit sub_sleep sub_sel
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_rollback sub_sleep sub_sel
+
+# overlapping tx commits
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+
+permutation ps1_begin ps2_begin ps1_ins ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+permutation ps1_begin ps2_begin ps1_ins ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+
+permutation ps1_begin ps2_begin ps2_ins ps1_ins ps2_commit ps1_commit sub_sleep sub_sel
+permutation ps1_begin ps2_begin ps2_ins ps1_ins ps1_commit ps2_commit sub_sleep sub_sel
--
1.8.3.1
Peter Smith <smithpb2250@gmail.com> writes:
My patch/idea makes a small change to the isolationtester spec
grammar. Now each session can optionally specify its own connection
string. When specified, this will override any connection string for
that session that would otherwise have been used. This is the only
change.
Surely this cannot work, because isolationtester only runs one
monitoring session. How will it detect wait conditions for
sessions connected to some other postmaster?
regards, tom lane
On Mon, Dec 19, 2022 at 5:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Peter Smith <smithpb2250@gmail.com> writes:
My patch/idea makes a small change to the isolationtester spec
grammar. Now each session can optionally specify its own connection
string. When specified, this will override any connection string for
that session that would otherwise have been used. This is the only
change.Surely this cannot work, because isolationtester only runs one
monitoring session. How will it detect wait conditions for
sessions connected to some other postmaster?
You are right - probably it can't work in a generic sense. But if the
"controller session" (internal session 0) is also configured to use
the same conninfo as all my "publisher" sessions (the current patch
can't do this but it seems only a small change) then all of the
publisher-side sessions will be monitored like they ought to be --
which is all I really needed I think.
------
Kind Regards,
Peter Smith
Fujitsu Australia
On Mon, Dec 19, 2022 at 5:35 PM Peter Smith <smithpb2250@gmail.com> wrote:
On Mon, Dec 19, 2022 at 5:04 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Peter Smith <smithpb2250@gmail.com> writes:
My patch/idea makes a small change to the isolationtester spec
grammar. Now each session can optionally specify its own connection
string. When specified, this will override any connection string for
that session that would otherwise have been used. This is the only
change.Surely this cannot work, because isolationtester only runs one
monitoring session. How will it detect wait conditions for
sessions connected to some other postmaster?You are right - probably it can't work in a generic sense. But if the
"controller session" (internal session 0) is also configured to use
the same conninfo as all my "publisher" sessions (the current patch
can't do this but it seems only a small change) then all of the
publisher-side sessions will be monitored like they ought to be --
which is all I really needed I think.
PSA v2 of this patch. Now the conninfo can be specified at the *.spec
file global scope. This will set the connection string for the
"controller", and this will be used by every other session unless they
too specify a conninfo. For example,
======
# Set the isolationtester controller's conninfo. User sessions will also use
# this unless they specify otherwise.
conninfo "host=localhost port=7651"
################
# Publisher node
################
session ps1
setup
{
TRUNCATE TABLE tbl;
}
step ps1_ins { INSERT INTO tbl VALUES (111); }
step ps1_sel { SELECT * FROM tbl ORDER BY id; }
step ps1_begin { BEGIN; }
step ps1_commit { COMMIT; }
step ps1_rollback { ROLLBACK; }
session ps2
step ps2_ins { INSERT INTO tbl VALUES (222); }
step ps2_sel { SELECT * FROM tbl ORDER BY id; }
step ps2_begin { BEGIN; }
step ps2_commit { COMMIT; }
step ps2_rollback { ROLLBACK; }
#################
# Subscriber node
#################
session sub
conninfo "host=localhost port=7652"
setup
{
TRUNCATE TABLE tbl;
}
step sub_sleep { SELECT pg_sleep(3); }
step sub_sel { SELECT * FROM tbl ORDER BY id; }
...
======
The above spec file gives:
======
Parsed test spec with 3 sessions
control connection conninfo 'host=localhost port=7651'
ps1 conninfo 'host=localhost port=7651'
ps2 conninfo 'host=localhost port=7651'
sub conninfo 'host=localhost port=7652'
WARNING: session sub is not using same connection as the controller
...
======
In this way, IIUC the isolationtester's session locking mechanism can
work OK at least for all of my "publishing" sessions.
------
Kind Regards,
Peter Smith
Fujitsu Australia
Attachments:
v2-0001-isolationtester-allow-conninfo-to-be-specified.patchapplication/octet-stream; name=v2-0001-isolationtester-allow-conninfo-to-be-specified.patchDownload
From 973b4fc4c72d23f9303dbb2832f8241c58d163e8 Mon Sep 17 00:00:00 2001
From: Peter Smith <peter.b.smith@fujitsu.com>
Date: Mon, 19 Dec 2022 18:39:53 +1100
Subject: [PATCH v2] isolationtester - allow conninfo to be specified
---
src/test/isolation/Makefile | 3 +
src/test/isolation/expected/pub-sub.out | 251 ++++++++++++++++++++++++++++++++
src/test/isolation/isolationtester.c | 36 ++++-
src/test/isolation/isolationtester.h | 2 +
src/test/isolation/specparse.y | 36 +++--
src/test/isolation/specs/pub-sub.spec | 86 +++++++++++
src/test/isolation/specscanner.l | 1 +
7 files changed, 400 insertions(+), 15 deletions(-)
create mode 100644 src/test/isolation/expected/pub-sub.out
create mode 100644 src/test/isolation/specs/pub-sub.spec
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index b8738b7..fe7e8cb 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -78,3 +78,6 @@ installcheck-prepared-txns: all temp-install
check-prepared-txns: all temp-install
$(pg_isolation_regress_check) --schedule=$(srcdir)/isolation_schedule prepared-transactions prepared-transactions-cic
+
+check-pub-sub: temp-install
+ $(pg_isolation_regress_check) pub-sub
diff --git a/src/test/isolation/expected/pub-sub.out b/src/test/isolation/expected/pub-sub.out
new file mode 100644
index 0000000..f9ee376
--- /dev/null
+++ b/src/test/isolation/expected/pub-sub.out
@@ -0,0 +1,251 @@
+Parsed test spec with 3 sessions
+control connection conninfo 'host=localhost port=7651'
+ps1 conninfo 'host=localhost port=7651'
+ps2 conninfo 'host=localhost port=7651'
+sub conninfo 'host=localhost port=7652'
+ WARNING: session sub is not using same connection as the controller
+
+starting permutation: ps1_begin ps1_ins ps1_commit ps1_sel ps2_sel sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps1_commit: COMMIT;
+step ps1_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+step ps2_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+
+starting permutation: ps2_begin ps2_ins ps2_commit ps1_sel ps2_sel sub_sleep sub_sel
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps2_commit: COMMIT;
+step ps1_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+step ps2_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+
+starting permutation: ps1_begin ps1_ins ps1_rollback ps1_sel sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps1_rollback: ROLLBACK;
+step ps1_sel: SELECT * FROM tbl ORDER BY id;
+id
+--
+(0 rows)
+
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+id
+--
+(0 rows)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps1_rollback ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_rollback: ROLLBACK;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+222
+(1 row)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_rollback sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_commit: COMMIT;
+step ps2_rollback: ROLLBACK;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+(1 row)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps2_commit: COMMIT;
+step ps1_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_commit: COMMIT;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps1_ins ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps2_commit: COMMIT;
+step ps1_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps1_ins ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_commit: COMMIT;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps2_ins ps1_ins ps2_commit ps1_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps2_commit: COMMIT;
+step ps1_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
+
+starting permutation: ps1_begin ps2_begin ps2_ins ps1_ins ps1_commit ps2_commit sub_sleep sub_sel
+step ps1_begin: BEGIN;
+step ps2_begin: BEGIN;
+step ps2_ins: INSERT INTO tbl VALUES (222);
+step ps1_ins: INSERT INTO tbl VALUES (111);
+step ps1_commit: COMMIT;
+step ps2_commit: COMMIT;
+step sub_sleep: SELECT pg_sleep(3);
+pg_sleep
+--------
+
+(1 row)
+
+step sub_sel: SELECT * FROM tbl ORDER BY id;
+ id
+---
+111
+222
+(2 rows)
+
diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index 0a66235..4bac830 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -119,6 +119,8 @@ main(int argc, char **argv)
* as the conninfo string; otherwise default to setting dbname=postgres
* and using environment variables or defaults for all other connection
* parameters.
+ *
+ * Note, this will be overridden by any session specific 'conninfo'.
*/
if (argc > optind)
conninfo = argv[optind];
@@ -153,15 +155,47 @@ main(int argc, char **argv)
for (i = 0; i < nconns; i++)
{
const char *sessionname;
+ const char *sessionconninfo;
if (i == 0)
+ {
sessionname = "control connection";
+ sessionconninfo = NULL;
+ if (testspec->controllerconninfo)
+ conninfo = testspec->controllerconninfo;
+ }
else
+ {
sessionname = testspec->sessions[i - 1]->name;
+ sessionconninfo = testspec->sessions[i - 1]->conninfo;
+ }
conns[i].sessionname = sessionname;
- conns[i].conn = PQconnectdb(conninfo);
+ /*
+ * If this spec session has specified a conninfo to use then that
+ * overrides any other conninfo (e.g. passed as an argument or
+ * the controller's conninfo)
+ *
+ * Note - the necessary instance to connect to is assumed to exist
+ * already manually setup by the user.
+ */
+ if (sessionconninfo)
+ {
+ fprintf(stderr, "%s conninfo '%s'\n", sessionname, sessionconninfo);
+
+ if (strcmp(sessionconninfo, conninfo) != 0)
+ fprintf(stderr, "\tWARNING: session %s is not using same connection as the controller\n", sessionname);
+
+ conns[i].conn = PQconnectdb(sessionconninfo);
+ }
+ else
+ {
+ if (testspec->controllerconninfo)
+ fprintf(stderr, "%s conninfo '%s'\n", sessionname, conninfo);
+
+ conns[i].conn = PQconnectdb(conninfo);
+ }
if (PQstatus(conns[i].conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection %d failed: %s",
diff --git a/src/test/isolation/isolationtester.h b/src/test/isolation/isolationtester.h
index 77134b0..8c75f6b 100644
--- a/src/test/isolation/isolationtester.h
+++ b/src/test/isolation/isolationtester.h
@@ -24,6 +24,7 @@ typedef struct Step Step;
typedef struct
{
char *name;
+ char *conninfo;
char *setupsql;
char *teardownsql;
Step **steps;
@@ -74,6 +75,7 @@ typedef struct
typedef struct
{
+ char *controllerconninfo;
char **setupsqls;
int nsetupsqls;
char *teardownsql;
diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y
index 657285c..a79a699 100644
--- a/src/test/isolation/specparse.y
+++ b/src/test/isolation/specparse.y
@@ -39,7 +39,7 @@ TestSpec parseresult; /* result of parsing is left here */
}
%type <ptr_list> setup_list
-%type <str> opt_setup opt_teardown
+%type <str> opt_conninfo opt_setup opt_teardown
%type <str> setup
%type <ptr_list> step_list session_list permutation_list opt_permutation_list
%type <ptr_list> permutation_step_list blocker_list
@@ -51,23 +51,25 @@ TestSpec parseresult; /* result of parsing is left here */
%token <str> sqlblock identifier
%token <integer> INTEGER
-%token NOTICES PERMUTATION SESSION SETUP STEP TEARDOWN TEST
+%token NOTICES PERMUTATION SESSION CONNINFO SETUP STEP TEARDOWN TEST
%%
TestSpec:
+ opt_conninfo
setup_list
opt_teardown
session_list
opt_permutation_list
{
- parseresult.setupsqls = (char **) $1.elements;
- parseresult.nsetupsqls = $1.nelements;
- parseresult.teardownsql = $2;
- parseresult.sessions = (Session **) $3.elements;
- parseresult.nsessions = $3.nelements;
- parseresult.permutations = (Permutation **) $4.elements;
- parseresult.npermutations = $4.nelements;
+ parseresult.controllerconninfo = $1;
+ parseresult.setupsqls = (char **) $2.elements;
+ parseresult.nsetupsqls = $2.nelements;
+ parseresult.teardownsql = $3;
+ parseresult.sessions = (Session **) $4.elements;
+ parseresult.nsessions = $4.nelements;
+ parseresult.permutations = (Permutation **) $5.elements;
+ parseresult.npermutations = $5.nelements;
}
;
@@ -86,6 +88,11 @@ setup_list:
}
;
+opt_conninfo:
+ /* EMPTY */ { $$ = NULL; }
+ | CONNINFO identifier { $$ = $2; }
+ ;
+
opt_setup:
/* EMPTY */ { $$ = NULL; }
| setup { $$ = $1; }
@@ -117,14 +124,15 @@ session_list:
;
session:
- SESSION identifier opt_setup step_list opt_teardown
+ SESSION identifier opt_conninfo opt_setup step_list opt_teardown
{
$$ = pg_malloc(sizeof(Session));
$$->name = $2;
- $$->setupsql = $3;
- $$->steps = (Step **) $4.elements;
- $$->nsteps = $4.nelements;
- $$->teardownsql = $5;
+ $$->conninfo = $3;
+ $$->setupsql = $4;
+ $$->steps = (Step **) $5.elements;
+ $$->nsteps = $5.nelements;
+ $$->teardownsql = $6;
}
;
diff --git a/src/test/isolation/specs/pub-sub.spec b/src/test/isolation/specs/pub-sub.spec
new file mode 100644
index 0000000..0f81d0a
--- /dev/null
+++ b/src/test/isolation/specs/pub-sub.spec
@@ -0,0 +1,86 @@
+#
+# Test assumes there is already setup so
+#
+# PG server for publisher (running on port 7651)
+# - has TABLE tbl
+# - has PUBLICATION pub1
+#
+# PG server for subscriber (running on port 7652)
+# - has TABLE tbl
+# - has SUBSCRIPTION sub1 subscribing to pub1
+#
+# ~~~
+#
+# Now the following spec tests are configured to have multiple sessions on the
+# publisher so we can interleave the WAL records to see the effect for the
+# subscription
+#
+# ~~~
+#
+# How to run
+# 1. Run . ./test_init.sh to create the PG instances, table, and publication/subscription
+# 2. Run the isolation tester make check-pub-sub (runs this spec)
+# 3. Check the logs of the PG instances
+#
+
+# Set the isolationtester controller's conninfo. User sessions will also use
+# this unless they specify otherwise.
+conninfo "host=localhost port=7651"
+
+################
+# Publisher node
+################
+session ps1
+setup
+{
+ TRUNCATE TABLE tbl;
+}
+step ps1_ins { INSERT INTO tbl VALUES (111); }
+step ps1_sel { SELECT * FROM tbl ORDER BY id; }
+step ps1_begin { BEGIN; }
+step ps1_commit { COMMIT; }
+step ps1_rollback { ROLLBACK; }
+
+session ps2
+step ps2_ins { INSERT INTO tbl VALUES (222); }
+step ps2_sel { SELECT * FROM tbl ORDER BY id; }
+step ps2_begin { BEGIN; }
+step ps2_commit { COMMIT; }
+step ps2_rollback { ROLLBACK; }
+
+#################
+# Subscriber node
+#################
+session sub
+conninfo "host=localhost port=7652"
+setup
+{
+ TRUNCATE TABLE tbl;
+}
+step sub_sleep { SELECT pg_sleep(3); }
+step sub_sel { SELECT * FROM tbl ORDER BY id; }
+
+#######
+# Tests
+#######
+
+# single tx
+permutation ps1_begin ps1_ins ps1_commit ps1_sel ps2_sel sub_sleep sub_sel
+permutation ps2_begin ps2_ins ps2_commit ps1_sel ps2_sel sub_sleep sub_sel
+
+# rollback
+permutation ps1_begin ps1_ins ps1_rollback ps1_sel sub_sleep sub_sel
+
+# overlapping tx rollback and commit
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_rollback ps2_commit sub_sleep sub_sel
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_rollback sub_sleep sub_sel
+
+# overlapping tx commits
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+permutation ps1_begin ps1_ins ps2_begin ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+
+permutation ps1_begin ps2_begin ps1_ins ps2_ins ps2_commit ps1_commit sub_sleep sub_sel
+permutation ps1_begin ps2_begin ps1_ins ps2_ins ps1_commit ps2_commit sub_sleep sub_sel
+
+permutation ps1_begin ps2_begin ps2_ins ps1_ins ps2_commit ps1_commit sub_sleep sub_sel
+permutation ps1_begin ps2_begin ps2_ins ps1_ins ps1_commit ps2_commit sub_sleep sub_sel
diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l
index b04696f..3174372 100644
--- a/src/test/isolation/specscanner.l
+++ b/src/test/isolation/specscanner.l
@@ -71,6 +71,7 @@ self [,()*]
%}
/* Keywords (must appear before the {identifier} rule!) */
+conninfo { return CONNINFO; }
notices { return NOTICES; }
permutation { return PERMUTATION; }
session { return SESSION; }
--
1.8.3.1