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

Commit21e1844

Browse files
committed
Add tests for recovery deadlock conflicts.
The recovery conflict tests added in9f8a050 surfaced a bug in theinteraction between buffer pin and deadlock recovery conflicts. To make surethat the bugfix won't break deadlock conflict detection, add a test for thatscenario.031_recovery_conflict.pl will later be backpatched, with this included.Discussion:https://postgr.es/m/20220413002626.udl7lll7f3o7nre7@alap3.anarazel.de
1 parent7307988 commit21e1844

File tree

1 file changed

+79
-7
lines changed

1 file changed

+79
-7
lines changed

‎src/test/recovery/t/031_recovery_conflict.pl

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
# recovery conflict is detected Also, test that statistics in
55
# pg_stat_database_conflicts are populated correctly
66

7-
# TODO: add a test for deadlock recovery conflicts.
8-
97
use strict;
108
use warnings;
119
use PostgreSQL::Test::Cluster;
@@ -24,6 +22,9 @@
2422
allow_in_place_tablespaces = on
2523
log_temp_files = 0
2624
25+
# for deadlock test
26+
max_prepared_transactions = 10
27+
2728
# wait some to test the wait paths as well, but not long for obvious reasons
2829
max_standby_streaming_delay = 50ms
2930
@@ -55,9 +56,13 @@
5556

5657
# test schema / data
5758
my$table1 ="test_recovery_conflict_table1";
58-
$node_primary->safe_psql($test_db,qq[CREATE TABLE${table1}(a int, b int);]);
59-
$node_primary->safe_psql($test_db,
60-
qq[INSERT INTO$table1 SELECT i % 3, 0 FROM generate_series(1,20) i]);
59+
my$table2 ="test_recovery_conflict_table2";
60+
$node_primary->safe_psql(
61+
$test_db,qq[
62+
CREATE TABLE${table1}(a int, b int);
63+
INSERT INTO$table1 SELECT i % 3, 0 FROM generate_series(1,20) i;
64+
CREATE TABLE${table2}(a int, b int);
65+
]);
6166
my$primary_lsn =$node_primary->lsn('flush');
6267
$node_primary->wait_for_catchup($node_standby,'replay',$primary_lsn);
6368

@@ -217,6 +222,67 @@
217222
check_conflict_stat("tablespace");
218223

219224

225+
## RECOVERY CONFLICT 5: Deadlock
226+
$sect ="startup deadlock";
227+
$expected_conflicts++;
228+
229+
# Generate a few dead rows, to later be cleaned up by vacuum. Then acquire a
230+
# lock on another relation in a prepared xact, so it's held continuously by
231+
# the startup process. The standby psql will block acquiring that lock while
232+
# holding a pin that vacuum needs, triggering the deadlock.
233+
$node_primary->safe_psql(
234+
$test_db,
235+
qq[
236+
CREATE TABLE$table1(a int, b int);
237+
INSERT INTO$table1 VALUES (1);
238+
BEGIN;
239+
INSERT INTO$table1(a) SELECT generate_series(1, 100) i;
240+
ROLLBACK;
241+
BEGIN;
242+
LOCK TABLE$table2;
243+
PREPARE TRANSACTION 'lock';
244+
INSERT INTO$table1(a) VALUES (170);
245+
SELECT txid_current();
246+
]);
247+
248+
$primary_lsn =$node_primary->lsn('flush');
249+
$node_primary->wait_for_catchup($node_standby,'replay',$primary_lsn);
250+
251+
$psql_standby{stdin} .=qq[
252+
BEGIN;
253+
-- hold pin
254+
DECLARE$cursor1 CURSOR FOR SELECT a FROM$table1;
255+
FETCH FORWARD FROM$cursor1;
256+
-- wait for lock held by prepared transaction
257+
SELECT * FROM$table2;
258+
];
259+
ok( pump_until(
260+
$psql_standby{run},$psql_timeout,
261+
\$psql_standby{stdout},qr/^1$/m,),
262+
"$sect: cursor holding conflicting pin, also waiting for lock, established"
263+
);
264+
265+
# just to make sure we're waiting for lock already
266+
ok($node_standby->poll_query_until(
267+
'postgres',qq[
268+
SELECT 'waiting' FROM pg_locks WHERE locktype = 'relation' AND NOT granted;
269+
],'waiting'),
270+
"$sect: lock acquisition is waiting");
271+
272+
# VACUUM will prune away rows, causing a buffer pin conflict, while standby
273+
# psql is waiting on lock
274+
$node_primary->safe_psql($test_db,qq[VACUUM$table1;]);
275+
$primary_lsn =$node_primary->lsn('flush');
276+
$node_primary->wait_for_catchup($node_standby,'replay',$primary_lsn);
277+
278+
check_conflict_log("User transaction caused buffer deadlock with recovery.");
279+
reconnect_and_clear();
280+
check_conflict_stat("deadlock");
281+
282+
# clean up for next tests
283+
$node_primary->safe_psql($test_db,qq[ROLLBACK PREPARED 'lock';]);
284+
285+
220286
# Check that expected number of conflicts show in pg_stat_database. Needs to
221287
# be tested before database is dropped, for obvious reasons.
222288
is($node_standby->safe_psql(
@@ -226,7 +292,7 @@
226292
qq[$expected_conflicts recovery conflicts shown in pg_stat_database]);
227293

228294

229-
## RECOVERY CONFLICT5: Database conflict
295+
## RECOVERY CONFLICT6: Database conflict
230296
$sect ="database conflict";
231297

232298
$node_primary->safe_psql('postgres',qq[DROP DATABASE$test_db;]);
@@ -259,7 +325,13 @@ sub pump_until_standby
259325

260326
subreconnect_and_clear
261327
{
262-
$psql_standby{stdin} .="\\q\n";
328+
# If psql isn't dead already, tell it to quit as \q, when already dead,
329+
# causes IPC::Run to unhelpfully error out with "ack Broken pipe:".
330+
$psql_standby{run}->pump_nb();
331+
if ($psql_standby{run}->pumpable())
332+
{
333+
$psql_standby{stdin} .="\\q\n";
334+
}
263335
$psql_standby{run}->finish;
264336

265337
# restart

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp