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

Commit3082098

Browse files
committed
Add tests for two-phase commit
There's some ongoing performance work on this area, so let's make surewe don't break things.Extracted from a larger patch originally by Stas Kelvich.Authors: Stas Kelvich, Nikhil Sontakke, Michael PaquierDiscussion:https://postgr.es/m/CAMGcDxfsuLLOg=h5cTg3g77Jjk-UGnt=RW7zK57zBSoFsapiWA@mail.gmail.com
1 parent74321d8 commit3082098

File tree

1 file changed

+322
-0
lines changed

1 file changed

+322
-0
lines changed

‎src/test/recovery/t/009_twophase.pl

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
# Tests dedicated to two-phase commit in recovery
2+
use strict;
3+
use warnings;
4+
5+
use PostgresNode;
6+
use TestLib;
7+
use Test::Moretests=> 13;
8+
9+
# Setup master node
10+
my$node_master = get_new_node("master");
11+
$node_master->init(allows_streaming=> 1);
12+
$node_master->append_conf('postgresql.conf',qq(
13+
max_prepared_transactions = 10
14+
log_checkpoints = true
15+
));
16+
$node_master->start;
17+
$node_master->backup('master_backup');
18+
$node_master->psql('postgres',"CREATE TABLE t_009_tbl (id int)");
19+
20+
# Setup slave node
21+
my$node_slave = get_new_node('slave');
22+
$node_slave->init_from_backup($node_master,'master_backup',has_streaming=> 1);
23+
$node_slave->start;
24+
25+
# Switch to synchronous replication
26+
$node_master->append_conf('postgresql.conf',qq(
27+
synchronous_standby_names = '*'
28+
));
29+
$node_master->psql('postgres',"SELECT pg_reload_conf()");
30+
31+
my$psql_out ='';
32+
my$psql_rc ='';
33+
34+
###############################################################################
35+
# Check that we can commit and abort transaction after soft restart.
36+
# Here checkpoint happens before shutdown and no WAL replay will occur at next
37+
# startup. In this case postgres re-creates shared-memory state from twophase
38+
# files.
39+
###############################################################################
40+
41+
$node_master->psql('postgres',"
42+
BEGIN;
43+
INSERT INTO t_009_tbl VALUES (42);
44+
SAVEPOINT s1;
45+
INSERT INTO t_009_tbl VALUES (43);
46+
PREPARE TRANSACTION 'xact_009_1';
47+
BEGIN;
48+
INSERT INTO t_009_tbl VALUES (142);
49+
SAVEPOINT s1;
50+
INSERT INTO t_009_tbl VALUES (143);
51+
PREPARE TRANSACTION 'xact_009_2';");
52+
$node_master->stop;
53+
$node_master->start;
54+
55+
$psql_rc =$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
56+
is($psql_rc,'0','Commit prepared transaction after restart');
57+
58+
$psql_rc =$node_master->psql('postgres',"ROLLBACK PREPARED 'xact_009_2'");
59+
is($psql_rc,'0','Rollback prepared transaction after restart');
60+
61+
###############################################################################
62+
# Check that we can commit and abort after a hard restart.
63+
# At next startup, WAL replay will re-create shared memory state for prepared
64+
# transaction using dedicated WAL records.
65+
###############################################################################
66+
67+
$node_master->psql('postgres',"
68+
CHECKPOINT;
69+
BEGIN;
70+
INSERT INTO t_009_tbl VALUES (42);
71+
SAVEPOINT s1;
72+
INSERT INTO t_009_tbl VALUES (43);
73+
PREPARE TRANSACTION 'xact_009_1';
74+
BEGIN;
75+
INSERT INTO t_009_tbl VALUES (142);
76+
SAVEPOINT s1;
77+
INSERT INTO t_009_tbl VALUES (143);
78+
PREPARE TRANSACTION 'xact_009_2';");
79+
$node_master->teardown_node;
80+
$node_master->start;
81+
82+
$psql_rc =$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
83+
is($psql_rc,'0','Commit prepared transaction after teardown');
84+
85+
$psql_rc =$node_master->psql('postgres',"ROLLBACK PREPARED 'xact_009_2'");
86+
is($psql_rc,'0','Rollback prepared transaction after teardown');
87+
88+
###############################################################################
89+
# Check that WAL replay can handle several transactions with same GID name.
90+
###############################################################################
91+
92+
$node_master->psql('postgres',"
93+
CHECKPOINT;
94+
BEGIN;
95+
INSERT INTO t_009_tbl VALUES (42);
96+
SAVEPOINT s1;
97+
INSERT INTO t_009_tbl VALUES (43);
98+
PREPARE TRANSACTION 'xact_009_1';
99+
COMMIT PREPARED 'xact_009_1';
100+
BEGIN;
101+
INSERT INTO t_009_tbl VALUES (42);
102+
SAVEPOINT s1;
103+
INSERT INTO t_009_tbl VALUES (43);
104+
PREPARE TRANSACTION 'xact_009_1';");
105+
$node_master->teardown_node;
106+
$node_master->start;
107+
108+
$psql_rc =$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
109+
is($psql_rc,'0','Replay several transactions with same GID');
110+
111+
###############################################################################
112+
# Check that WAL replay cleans up its shared memory state and releases locks
113+
# while replaying transaction commits.
114+
###############################################################################
115+
116+
$node_master->psql('postgres',"
117+
BEGIN;
118+
INSERT INTO t_009_tbl VALUES (42);
119+
SAVEPOINT s1;
120+
INSERT INTO t_009_tbl VALUES (43);
121+
PREPARE TRANSACTION 'xact_009_1';
122+
COMMIT PREPARED 'xact_009_1';");
123+
$node_master->teardown_node;
124+
$node_master->start;
125+
$psql_rc =$node_master->psql('postgres',"
126+
BEGIN;
127+
INSERT INTO t_009_tbl VALUES (42);
128+
SAVEPOINT s1;
129+
INSERT INTO t_009_tbl VALUES (43);
130+
-- This prepare can fail due to conflicting GID or locks conflicts if
131+
-- replay did not fully cleanup its state on previous commit.
132+
PREPARE TRANSACTION 'xact_009_1';");
133+
is($psql_rc,'0',"Cleanup of shared memory state for 2PC commit");
134+
135+
$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
136+
137+
###############################################################################
138+
# Check that WAL replay will cleanup its shared memory state on running slave.
139+
###############################################################################
140+
141+
$node_master->psql('postgres',"
142+
BEGIN;
143+
INSERT INTO t_009_tbl VALUES (42);
144+
SAVEPOINT s1;
145+
INSERT INTO t_009_tbl VALUES (43);
146+
PREPARE TRANSACTION 'xact_009_1';
147+
COMMIT PREPARED 'xact_009_1';");
148+
$node_slave->psql('postgres',"SELECT count(*) FROM pg_prepared_xacts",
149+
stdout=> \$psql_out);
150+
is($psql_out,'0',
151+
"Cleanup of shared memory state on running standby without checkpoint");
152+
153+
###############################################################################
154+
# Same as in previous case, but let's force checkpoint on slave between
155+
# prepare and commit to use on-disk twophase files.
156+
###############################################################################
157+
158+
$node_master->psql('postgres',"
159+
BEGIN;
160+
INSERT INTO t_009_tbl VALUES (42);
161+
SAVEPOINT s1;
162+
INSERT INTO t_009_tbl VALUES (43);
163+
PREPARE TRANSACTION 'xact_009_1';");
164+
$node_slave->psql('postgres',"CHECKPOINT");
165+
$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
166+
$node_slave->psql('postgres',"SELECT count(*) FROM pg_prepared_xacts",
167+
stdout=> \$psql_out);
168+
is($psql_out,'0',
169+
"Cleanup of shared memory state on running standby after checkpoint");
170+
171+
###############################################################################
172+
# Check that prepared transactions can be committed on promoted slave.
173+
###############################################################################
174+
175+
$node_master->psql('postgres',"
176+
BEGIN;
177+
INSERT INTO t_009_tbl VALUES (42);
178+
SAVEPOINT s1;
179+
INSERT INTO t_009_tbl VALUES (43);
180+
PREPARE TRANSACTION 'xact_009_1';");
181+
$node_master->teardown_node;
182+
$node_slave->promote;
183+
$node_slave->poll_query_until('postgres',
184+
"SELECT NOT pg_is_in_recovery()")
185+
ordie"Timed out while waiting for promotion of standby";
186+
187+
$psql_rc =$node_slave->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
188+
is($psql_rc,'0',"Restore of prepared transaction on promoted slave");
189+
190+
# change roles
191+
($node_master,$node_slave) = ($node_slave,$node_master);
192+
$node_slave->enable_streaming($node_master);
193+
$node_slave->append_conf('recovery.conf',qq(
194+
recovery_target_timeline='latest'
195+
));
196+
$node_slave->start;
197+
198+
###############################################################################
199+
# Check that prepared transactions are replayed after soft restart of standby
200+
# while master is down. Since standby knows that master is down it uses a
201+
# different code path on startup to ensure that the status of transactions is
202+
# consistent.
203+
###############################################################################
204+
205+
$node_master->psql('postgres',"
206+
BEGIN;
207+
INSERT INTO t_009_tbl VALUES (42);
208+
SAVEPOINT s1;
209+
INSERT INTO t_009_tbl VALUES (43);
210+
PREPARE TRANSACTION 'xact_009_1';");
211+
$node_master->stop;
212+
$node_slave->restart;
213+
$node_slave->promote;
214+
$node_slave->poll_query_until('postgres',
215+
"SELECT NOT pg_is_in_recovery()")
216+
ordie"Timed out while waiting for promotion of standby";
217+
218+
$node_slave->psql('postgres',"SELECT count(*) FROM pg_prepared_xacts",
219+
stdout=> \$psql_out);
220+
is($psql_out,'1',
221+
"Restore prepared transactions from files with master down");
222+
223+
# restore state
224+
($node_master,$node_slave) = ($node_slave,$node_master);
225+
$node_slave->enable_streaming($node_master);
226+
$node_slave->append_conf('recovery.conf',qq(
227+
recovery_target_timeline='latest'
228+
));
229+
$node_slave->start;
230+
$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
231+
232+
###############################################################################
233+
# Check that prepared transactions are correctly replayed after slave hard
234+
# restart while master is down.
235+
###############################################################################
236+
237+
$node_master->psql('postgres',"
238+
BEGIN;
239+
INSERT INTO t_009_tbl VALUES (242);
240+
SAVEPOINT s1;
241+
INSERT INTO t_009_tbl VALUES (243);
242+
PREPARE TRANSACTION 'xact_009_1';
243+
");
244+
$node_master->stop;
245+
$node_slave->teardown_node;
246+
$node_slave->start;
247+
$node_slave->promote;
248+
$node_slave->poll_query_until('postgres',
249+
"SELECT NOT pg_is_in_recovery()")
250+
ordie"Timed out while waiting for promotion of standby";
251+
252+
$node_slave->psql('postgres',"SELECT count(*) FROM pg_prepared_xacts",
253+
stdout=> \$psql_out);
254+
is($psql_out,'1',
255+
"Restore prepared transactions from records with master down");
256+
257+
# restore state
258+
($node_master,$node_slave) = ($node_slave,$node_master);
259+
$node_slave->enable_streaming($node_master);
260+
$node_slave->append_conf('recovery.conf',qq(
261+
recovery_target_timeline='latest'
262+
));
263+
$node_slave->start;
264+
$node_master->psql('postgres',"COMMIT PREPARED 'xact_009_1'");
265+
266+
267+
###############################################################################
268+
# Check for a lock conflict between prepared transaction with DDL inside and replay of
269+
# XLOG_STANDBY_LOCK wal record.
270+
###############################################################################
271+
272+
$node_master->psql('postgres',"
273+
BEGIN;
274+
CREATE TABLE t_009_tbl2 (id int);
275+
SAVEPOINT s1;
276+
INSERT INTO t_009_tbl2 VALUES (42);
277+
PREPARE TRANSACTION 'xact_009_1';
278+
-- checkpoint will issue XLOG_STANDBY_LOCK that can conflict with lock
279+
-- held by 'create table' statement
280+
CHECKPOINT;
281+
COMMIT PREPARED 'xact_009_1';");
282+
283+
$node_slave->psql('postgres',"SELECT count(*) FROM pg_prepared_xacts",
284+
stdout=> \$psql_out);
285+
is($psql_out,'0',"Replay prepared transaction with DDL");
286+
287+
288+
###############################################################################
289+
# Check that replay will correctly set SUBTRANS and properly advance nextXid
290+
# so that it won't conflict with savepoint xids.
291+
###############################################################################
292+
293+
$node_master->psql('postgres',"
294+
BEGIN;
295+
DELETE FROM t_009_tbl;
296+
INSERT INTO t_009_tbl VALUES (43);
297+
SAVEPOINT s1;
298+
INSERT INTO t_009_tbl VALUES (43);
299+
SAVEPOINT s2;
300+
INSERT INTO t_009_tbl VALUES (43);
301+
SAVEPOINT s3;
302+
INSERT INTO t_009_tbl VALUES (43);
303+
SAVEPOINT s4;
304+
INSERT INTO t_009_tbl VALUES (43);
305+
SAVEPOINT s5;
306+
INSERT INTO t_009_tbl VALUES (43);
307+
PREPARE TRANSACTION 'xact_009_1';
308+
CHECKPOINT;");
309+
310+
$node_master->stop;
311+
$node_master->start;
312+
$node_master->psql('postgres',"
313+
-- here we can get xid of previous savepoint if nextXid
314+
-- wasn't properly advanced
315+
BEGIN;
316+
INSERT INTO t_009_tbl VALUES (142);
317+
ROLLBACK;
318+
COMMIT PREPARED 'xact_009_1';");
319+
320+
$node_master->psql('postgres',"SELECT count(*) FROM t_009_tbl",
321+
stdout=> \$psql_out);
322+
is($psql_out,'6',"Check nextXid handling for prepared subtransactions");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp