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

Commitef5bb79

Browse files
Nikhil Sontakkearssher
Nikhil Sontakke
authored andcommitted
Teach test_decoding plugin to work with 2PC
Implement all callbacks required for decoding 2PC in this test_decodingplugin. Includes relevant test cases as well.Additionally, includes a new option "check-xid". If this option pointsto a valid xid, then the pg_decode_change() API will wait for it tobe aborted externally. This allows us to test concurrent rollback ofa prepared transaction while it's being actually decoded simultaneously.
1 parent7dce5ca commitef5bb79

File tree

5 files changed

+532
-33
lines changed

5 files changed

+532
-33
lines changed

‎contrib/test_decoding/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ installcheck:;
2626
# installation, allow to do so, but only if requested explicitly.
2727
installcheck-force: regresscheck-install-force isolationcheck-install-force
2828

29-
check: regresscheck isolationcheck
29+
check: regresscheck isolationcheck 2pc-check
3030

3131
submake-regress:
3232
$(MAKE) -C$(top_builddir)/src/test/regress all
@@ -67,3 +67,6 @@ isolationcheck-install-force: all | submake-isolation submake-test_decoding temp
6767
isolationcheck isolationcheck-install-force
6868

6969
temp-install: EXTRA_INSTALL=contrib/test_decoding
70+
71+
2pc-check: temp-install
72+
$(prove_check)

‎contrib/test_decoding/expected/prepared.out

Lines changed: 160 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,65 +6,200 @@ SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_d
66
init
77
(1 row)
88

9-
CREATE TABLE test_prepared1(idint);
10-
CREATE TABLE test_prepared2(idint);
9+
CREATE TABLE test_prepared1(idinteger primary key);
10+
CREATE TABLE test_prepared2(idinteger primary key);
1111
-- test simple successful use of a prepared xact
1212
BEGIN;
1313
INSERT INTO test_prepared1 VALUES (1);
1414
PREPARE TRANSACTION 'test_prepared#1';
15+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
16+
data
17+
----------------------------------------------------
18+
BEGIN
19+
table public.test_prepared1: INSERT: id[integer]:1
20+
PREPARE TRANSACTION 'test_prepared#1'
21+
(3 rows)
22+
1523
COMMIT PREPARED 'test_prepared#1';
24+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
25+
data
26+
-----------------------------------
27+
COMMIT PREPARED 'test_prepared#1'
28+
(1 row)
29+
1630
INSERT INTO test_prepared1 VALUES (2);
1731
-- test abort of a prepared xact
1832
BEGIN;
1933
INSERT INTO test_prepared1 VALUES (3);
2034
PREPARE TRANSACTION 'test_prepared#2';
35+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
36+
data
37+
----------------------------------------------------
38+
BEGIN
39+
table public.test_prepared1: INSERT: id[integer]:2
40+
COMMIT
41+
BEGIN
42+
table public.test_prepared1: INSERT: id[integer]:3
43+
PREPARE TRANSACTION 'test_prepared#2'
44+
(6 rows)
45+
2146
ROLLBACK PREPARED 'test_prepared#2';
47+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
48+
data
49+
-------------------------------------
50+
ROLLBACK PREPARED 'test_prepared#2'
51+
(1 row)
52+
2253
INSERT INTO test_prepared1 VALUES (4);
2354
-- test prepared xact containing ddl
2455
BEGIN;
2556
INSERT INTO test_prepared1 VALUES (5);
2657
ALTER TABLE test_prepared1 ADD COLUMN data text;
2758
INSERT INTO test_prepared1 VALUES (6, 'frakbar');
2859
PREPARE TRANSACTION 'test_prepared#3';
29-
-- test that we decode correctly while an uncommitted prepared xact
30-
-- with ddl exists.
31-
-- separate table because of the lock from the ALTER
32-
-- this will come before the '5' row above, as this commits before it.
33-
INSERT INTO test_prepared2 VALUES (7);
34-
COMMIT PREPARED 'test_prepared#3';
35-
-- make sure stuff still works
36-
INSERT INTO test_prepared1 VALUES (8);
37-
INSERT INTO test_prepared2 VALUES (9);
38-
-- cleanup
39-
DROP TABLE test_prepared1;
40-
DROP TABLE test_prepared2;
41-
-- show results
60+
SELECT 'test_prepared_1' AS relation, locktype, mode
61+
FROM pg_locks
62+
WHERE locktype = 'relation'
63+
AND relation = 'test_prepared1'::regclass;
64+
relation | locktype | mode
65+
-----------------+----------+---------------------
66+
test_prepared_1 | relation | RowExclusiveLock
67+
test_prepared_1 | relation | AccessExclusiveLock
68+
(2 rows)
69+
4270
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
4371
data
4472
-------------------------------------------------------------------------
45-
BEGIN
46-
table public.test_prepared1: INSERT: id[integer]:1
47-
COMMIT
48-
BEGIN
49-
table public.test_prepared1: INSERT: id[integer]:2
50-
COMMIT
5173
BEGIN
5274
table public.test_prepared1: INSERT: id[integer]:4
5375
COMMIT
5476
BEGIN
55-
table public.test_prepared2: INSERT: id[integer]:7
56-
COMMIT
57-
BEGIN
5877
table public.test_prepared1: INSERT: id[integer]:5
5978
table public.test_prepared1: INSERT: id[integer]:6 data[text]:'frakbar'
79+
PREPARE TRANSACTION 'test_prepared#3'
80+
(7 rows)
81+
82+
-- Test that we decode correctly while an uncommitted prepared xact
83+
-- with ddl exists.
84+
--
85+
-- Use a separate table for the concurrent transaction because the lock from
86+
-- the ALTER will stop us inserting into the other one.
87+
--
88+
-- We should see '7' before '5' in our results since it commits first.
89+
--
90+
INSERT INTO test_prepared2 VALUES (7);
91+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
92+
data
93+
----------------------------------------------------
94+
BEGIN
95+
table public.test_prepared2: INSERT: id[integer]:7
6096
COMMIT
97+
(3 rows)
98+
99+
COMMIT PREPARED 'test_prepared#3';
100+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
101+
data
102+
-----------------------------------
103+
COMMIT PREPARED 'test_prepared#3'
104+
(1 row)
105+
106+
-- make sure stuff still works
107+
INSERT INTO test_prepared1 VALUES (8);
108+
INSERT INTO test_prepared2 VALUES (9);
109+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
110+
data
111+
--------------------------------------------------------------------
61112
BEGIN
62113
table public.test_prepared1: INSERT: id[integer]:8 data[text]:null
63114
COMMIT
64115
BEGIN
65116
table public.test_prepared2: INSERT: id[integer]:9
66117
COMMIT
67-
(22 rows)
118+
(6 rows)
119+
120+
-- Check `CLUSTER` (as operation that hold exclusive lock) doesn't block
121+
-- logical decoding.
122+
BEGIN;
123+
INSERT INTO test_prepared1 VALUES (10, 'othercol');
124+
CLUSTER test_prepared1 USING test_prepared1_pkey;
125+
INSERT INTO test_prepared1 VALUES (11, 'othercol2');
126+
PREPARE TRANSACTION 'test_prepared_lock';
127+
BEGIN;
128+
insert into test_prepared2 values (12);
129+
PREPARE TRANSACTION 'test_prepared_lock2';
130+
COMMIT PREPARED 'test_prepared_lock2';
131+
SELECT 'pg_class' AS relation, locktype, mode
132+
FROM pg_locks
133+
WHERE locktype = 'relation'
134+
AND relation = 'pg_class'::regclass;
135+
relation | locktype | mode
136+
----------+----------+------
137+
(0 rows)
138+
139+
-- Shouldn't timeout on 2pc decoding.
140+
SET statement_timeout = '1s';
141+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
142+
data
143+
----------------------------------------------------------------------------
144+
BEGIN
145+
table public.test_prepared1: INSERT: id[integer]:10 data[text]:'othercol'
146+
table public.test_prepared1: INSERT: id[integer]:11 data[text]:'othercol2'
147+
PREPARE TRANSACTION 'test_prepared_lock'
148+
BEGIN
149+
table public.test_prepared2: INSERT: id[integer]:12
150+
PREPARE TRANSACTION 'test_prepared_lock2'
151+
COMMIT PREPARED 'test_prepared_lock2'
152+
(8 rows)
153+
154+
RESET statement_timeout;
155+
COMMIT PREPARED 'test_prepared_lock';
156+
-- will work normally after we commit
157+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
158+
data
159+
--------------------------------------
160+
COMMIT PREPARED 'test_prepared_lock'
161+
(1 row)
162+
163+
-- test savepoints
164+
BEGIN;
165+
SAVEPOINT test_savepoint;
166+
CREATE TABLE test_prepared_savepoint (a int);
167+
PREPARE TRANSACTION 'test_prepared_savepoint';
168+
COMMIT PREPARED 'test_prepared_savepoint';
169+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
170+
data
171+
-------------------------------------------
172+
COMMIT PREPARED 'test_prepared_savepoint'
173+
(1 row)
174+
175+
-- test that a GID containing "nodecode" gets decoded at commit prepared time
176+
BEGIN;
177+
INSERT INTO test_prepared1 VALUES (20);
178+
PREPARE TRANSACTION 'test_prepared_nodecode';
179+
-- should show nothing
180+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
181+
data
182+
------
183+
(0 rows)
184+
185+
COMMIT PREPARED 'test_prepared_nodecode';
186+
-- should be decoded now
187+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
188+
data
189+
---------------------------------------------------------------------
190+
BEGIN
191+
table public.test_prepared1: INSERT: id[integer]:20 data[text]:null
192+
COMMIT
193+
(3 rows)
194+
195+
-- cleanup
196+
DROP TABLE test_prepared1;
197+
DROP TABLE test_prepared2;
198+
-- show results. There should be nothing to show
199+
SELECT data FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
200+
data
201+
------
202+
(0 rows)
68203

69204
SELECT pg_drop_replication_slot('regression_slot');
70205
pg_drop_replication_slot

‎contrib/test_decoding/sql/prepared.sql

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,25 @@
22
SET synchronous_commit=on;
33
SELECT'init'FROM pg_create_logical_replication_slot('regression_slot','test_decoding');
44

5-
CREATETABLEtest_prepared1(idint);
6-
CREATETABLEtest_prepared2(idint);
5+
CREATETABLEtest_prepared1(idintegerprimary key);
6+
CREATETABLEtest_prepared2(idintegerprimary key);
77

88
-- test simple successful use of a prepared xact
99
BEGIN;
1010
INSERT INTO test_prepared1VALUES (1);
1111
PREPARE TRANSACTION'test_prepared#1';
12+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
1213
COMMIT PREPARED'test_prepared#1';
14+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
1315
INSERT INTO test_prepared1VALUES (2);
1416

1517
-- test abort of a prepared xact
1618
BEGIN;
1719
INSERT INTO test_prepared1VALUES (3);
1820
PREPARE TRANSACTION'test_prepared#2';
21+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
1922
ROLLBACK PREPARED'test_prepared#2';
23+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
2024

2125
INSERT INTO test_prepared1VALUES (4);
2226

@@ -27,24 +31,83 @@ ALTER TABLE test_prepared1 ADD COLUMN data text;
2731
INSERT INTO test_prepared1VALUES (6,'frakbar');
2832
PREPARE TRANSACTION'test_prepared#3';
2933

30-
-- test that we decode correctly while an uncommitted prepared xact
31-
-- with ddl exists.
34+
SELECT'test_prepared_1'AS relation, locktype, mode
35+
FROM pg_locks
36+
WHERE locktype='relation'
37+
AND relation='test_prepared1'::regclass;
38+
39+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
3240

33-
-- separate table because of the lock from the ALTER
34-
-- this will come before the '5' row above, as this commits before it.
41+
-- Test that we decode correctly while an uncommitted prepared xact
42+
-- with ddl exists.
43+
--
44+
-- Use a separate table for the concurrent transaction because the lock from
45+
-- the ALTER will stop us inserting into the other one.
46+
--
47+
-- We should see '7' before '5' in our results since it commits first.
48+
--
3549
INSERT INTO test_prepared2VALUES (7);
50+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
3651

3752
COMMIT PREPARED'test_prepared#3';
53+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
3854

3955
-- make sure stuff still works
4056
INSERT INTO test_prepared1VALUES (8);
4157
INSERT INTO test_prepared2VALUES (9);
58+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
59+
60+
-- Check `CLUSTER` (as operation that hold exclusive lock) doesn't block
61+
-- logical decoding.
62+
BEGIN;
63+
INSERT INTO test_prepared1VALUES (10,'othercol');
64+
CLUSTER test_prepared1 USING test_prepared1_pkey;
65+
INSERT INTO test_prepared1VALUES (11,'othercol2');
66+
PREPARE TRANSACTION'test_prepared_lock';
67+
68+
BEGIN;
69+
insert into test_prepared2values (12);
70+
PREPARE TRANSACTION'test_prepared_lock2';
71+
COMMIT PREPARED'test_prepared_lock2';
72+
73+
SELECT'pg_class'AS relation, locktype, mode
74+
FROM pg_locks
75+
WHERE locktype='relation'
76+
AND relation='pg_class'::regclass;
77+
78+
-- Shouldn't timeout on 2pc decoding.
79+
SET statement_timeout='1s';
80+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
81+
RESET statement_timeout;
82+
83+
COMMIT PREPARED'test_prepared_lock';
84+
85+
-- will work normally after we commit
86+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
87+
88+
-- test savepoints
89+
BEGIN;
90+
SAVEPOINT test_savepoint;
91+
CREATETABLEtest_prepared_savepoint (aint);
92+
PREPARE TRANSACTION'test_prepared_savepoint';
93+
COMMIT PREPARED'test_prepared_savepoint';
94+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
95+
96+
-- test that a GID containing "nodecode" gets decoded at commit prepared time
97+
BEGIN;
98+
INSERT INTO test_prepared1VALUES (20);
99+
PREPARE TRANSACTION'test_prepared_nodecode';
100+
-- should show nothing
101+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
102+
COMMIT PREPARED'test_prepared_nodecode';
103+
-- should be decoded now
104+
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
42105

43106
-- cleanup
44107
DROPTABLE test_prepared1;
45108
DROPTABLE test_prepared2;
46109

47-
-- show results
110+
-- show results. There should be nothing to show
48111
SELECT dataFROM pg_logical_slot_get_changes('regression_slot',NULL,NULL,'include-xids','0','skip-empty-xacts','1');
49112

50113
SELECT pg_drop_replication_slot('regression_slot');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp