Skip to content

Commit f71f952

Browse files
author
Marina Polyakova
committed
Pgbench Fix TAP tests for deadlock failures
1 parent 9d55661 commit f71f952

File tree

1 file changed

+117
-45
lines changed

1 file changed

+117
-45
lines changed
Lines changed: 117 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
use strict;
22
use warnings;
33

4+
use Config;
45
use PostgresNode;
56
use TestLib;
6-
use Test::More tests => 18;
7+
use Test::More tests => 27;
8+
9+
use constant
10+
{
11+
READ_COMMITTED => 0,
12+
REPEATABLE_READ => 1,
13+
SERIALIZABLE => 2,
14+
};
15+
16+
my @isolation_level_sql = ('read committed', 'repeatable read', 'serializable');
17+
my @isolation_level_abbreviations = ('RC', 'RR', 'S');
718

819
# Test concurrent deadlock updates in table with different default transaction
920
# isolation levels.
@@ -18,55 +29,116 @@
1829
append_to_file($script1,
1930
"\\set delta1 random(-5000, 5000)\n"
2031
. "\\set delta2 random(-5000, 5000)\n"
21-
. "BEGIN;"
22-
. "UPDATE xy SET y = y + :delta1 WHERE x = 1;"
23-
. "UPDATE xy SET y = y + :delta2 WHERE x = 2;"
32+
. "BEGIN;\n"
33+
. "UPDATE xy SET y = y + :delta1 WHERE x = 1;\n"
34+
. "SELECT pg_sleep(20);\n"
35+
. "UPDATE xy SET y = y + :delta2 WHERE x = 2;\n"
2436
. "END;");
2537

2638
my $script2 = $node->basedir . '/pgbench_script2';
2739
append_to_file($script2,
2840
"\\set delta1 random(-5000, 5000)\n"
2941
. "\\set delta2 random(-5000, 5000)\n"
30-
. "BEGIN;"
31-
. "UPDATE xy SET y = y + :delta2 WHERE x = 2;"
32-
. "UPDATE xy SET y = y + :delta1 WHERE x = 1;"
42+
. "BEGIN;\n"
43+
. "UPDATE xy SET y = y + :delta2 WHERE x = 2;\n"
44+
. "UPDATE xy SET y = y + :delta1 WHERE x = 1;\n"
3345
. "END;");
3446

35-
# Test deadlock transactions with Read committed default isolation level:
36-
$node->command_like(
37-
[ qw(pgbench --no-vacuum --client=5 --transactions=10
38-
--default-isolation-level=RC --file), $script1, qw(--file), $script2],
39-
qr{processed: 50/50},
40-
'concurrent deadlock update: Read Committed: check processed transactions');
41-
42-
$node->command_like(
43-
[ qw(pgbench --no-vacuum --client=5 --transactions=10
44-
--default-isolation-level=RC --file), $script1, qw(--file), $script2],
45-
qr{deadlock failures: [1-9]\d* \([1-9]\d*\.\d* %\)},
46-
'concurrent deadlock update: Read Committed: check deadlock failures');
47-
48-
# Test deadlock transactions with Repeatable read default isolation level:
49-
$node->command_like(
50-
[ qw(pgbench --no-vacuum --client=5 --transactions=10
51-
--default-isolation-level=RR --file), $script1, qw(--file), $script2],
52-
qr{processed: 50/50},
53-
'concurrent deadlock update: Repeatable Read: check processed transactions');
54-
55-
$node->command_like(
56-
[ qw(pgbench --no-vacuum --client=5 --transactions=10
57-
--default-isolation-level=RR --file), $script1, qw(--file), $script2],
58-
qr{deadlock failures: [1-9]\d* \([1-9]\d*\.\d* %\)},
59-
'concurrent deadlock update: Repeatable Read: check deadlock failures');
60-
61-
# Test deadlock transactions with Serializable default isolation level:
62-
$node->command_like(
63-
[ qw(pgbench --no-vacuum --client=5 --transactions=10
64-
--default-isolation-level=S --file), $script1, qw(--file), $script2],
65-
qr{processed: 50/50},
66-
'concurrent deadlock update: Serializable: check processed transactions');
67-
68-
$node->command_like(
69-
[ qw(pgbench --no-vacuum --client=5 --transactions=10
70-
--default-isolation-level=S --file), $script1, qw(--file), $script2],
71-
qr{deadlock failures: [1-9]\d* \([1-9]\d*\.\d* %\)},
72-
'concurrent deadlock update: Serializable: check deadlock failures');
47+
sub test_pgbench
48+
{
49+
my ($isolation_level) = @_;
50+
51+
my $isolation_level_sql = $isolation_level_sql[$isolation_level];
52+
my $isolation_level_abbreviation =
53+
$isolation_level_abbreviations[$isolation_level];
54+
55+
local $ENV{PGPORT} = $node->port;
56+
57+
my ($h1, $in1, $out1, $err1);
58+
my ($h2, $in2, $out2, $err2);
59+
60+
# Run first pgbench
61+
my @command1 = (
62+
qw(pgbench --no-vacuum --transactions=1 --default-isolation-level),
63+
$isolation_level_abbreviation,
64+
"--file",
65+
$script1);
66+
print "# Running: " . join(" ", @command1) . "\n";
67+
$h1 = IPC::Run::start \@command1, \$in1, \$out1, \$err1;
68+
69+
# Let pgbench run first update command in the transaction:
70+
sleep 10;
71+
72+
# Run second pgbench
73+
my @command2 = (
74+
qw(pgbench --no-vacuum --transactions=1 --default-isolation-level),
75+
$isolation_level_abbreviation,
76+
"--file",
77+
$script2);
78+
print "# Running: " . join(" ", @command2) . "\n";
79+
$h2 = IPC::Run::start \@command2, \$in2, \$out2, \$err2;
80+
81+
# Get all pgbench results
82+
$h1->pump() until length $out1;
83+
$h1->finish();
84+
85+
$h2->pump() until length $out2;
86+
$h2->finish();
87+
88+
# On Windows, the exit status of the process is returned directly as the
89+
# process's exit code, while on Unix, it's returned in the high bits
90+
# of the exit code (see WEXITSTATUS macro in the standard <sys/wait.h>
91+
# header file). IPC::Run's result function always returns exit code >> 8,
92+
# assuming the Unix convention, which will always return 0 on Windows as
93+
# long as the process was not terminated by an exception. To work around
94+
# that, use $h->full_result on Windows instead.
95+
my $result1 =
96+
($Config{osname} eq "MSWin32")
97+
? ($h1->full_results)[0]
98+
: $h1->result(0);
99+
100+
my $result2 =
101+
($Config{osname} eq "MSWin32")
102+
? ($h2->full_results)[0]
103+
: $h2->result(0);
104+
105+
# Check all pgbench results
106+
ok(!$result1, "@command1 exit code 0");
107+
ok(!$result2, "@command2 exit code 0");
108+
109+
is($err1, '', "@command1 no stderr");
110+
is($err2, '', "@command2 no stderr");
111+
112+
like($out1,
113+
qr{default transaction isolation level: $isolation_level_sql},
114+
"concurrent deadlock update: "
115+
. $isolation_level_sql
116+
. ": pgbench 1: check default isolation level");
117+
like($out2,
118+
qr{default transaction isolation level: $isolation_level_sql},
119+
"concurrent deadlock update: "
120+
. $isolation_level_sql
121+
. ": pgbench 2: check default isolation level");
122+
123+
like($out1,
124+
qr{processed: 1/1},
125+
"concurrent deadlock update: "
126+
. $isolation_level_sql
127+
. ": pgbench 1: check processed transactions");
128+
like($out2,
129+
qr{processed: 1/1},
130+
"concurrent deadlock update: "
131+
. $isolation_level_sql
132+
. ": pgbench 2: check processed transactions");
133+
134+
# First or second pgbench should get a deadlock error
135+
like($out1 . $out2,
136+
qr{deadlock failures: 1 \(100\.000 %\)},
137+
"concurrent deadlock update: "
138+
. $isolation_level_sql
139+
. ": check deadlock failures");
140+
}
141+
142+
test_pgbench(READ_COMMITTED);
143+
test_pgbench(REPEATABLE_READ);
144+
test_pgbench(SERIALIZABLE);

0 commit comments

Comments
 (0)