Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1eea8e8

Browse files
committed
Fix bug in PreCommit_CheckForSerializationFailure. A transaction that has
already been marked as PREPARED cannot be killed. Kill the current transaction instead. One of the prepared_xacts regression tests actually hits this bug. I removed the anomaly from the duplicate-gids test so that it fails in the intended way, and added a new test to check serialization failures with a prepared transaction. Dan Ports
1 parent 7cb2ff9 commit 1eea8e8

File tree

3 files changed

+77
-7
lines changed

3 files changed

+77
-7
lines changed

src/backend/storage/lmgr/predicate.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4542,6 +4542,21 @@ PreCommit_CheckForSerializationFailure(void)
45424542
&& !SxactIsReadOnly(farConflict->sxactOut)
45434543
&& !SxactIsDoomed(farConflict->sxactOut)))
45444544
{
4545+
/*
4546+
* Normally, we kill the pivot transaction to make sure we
4547+
* make progress if the failing transaction is retried.
4548+
* However, we can't kill it if it's already prepared, so
4549+
* in that case we commit suicide instead.
4550+
*/
4551+
if (SxactIsPrepared(nearConflict->sxactOut))
4552+
{
4553+
LWLockRelease(SerializableXactHashLock);
4554+
ereport(ERROR,
4555+
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
4556+
errmsg("could not serialize access due to read/write dependencies among transactions"),
4557+
errdetail("Cancelled on commit attempt with conflict in from prepared pivot."),
4558+
errhint("The transaction might succeed if retried.")));
4559+
}
45454560
nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
45464561
break;
45474562
}

src/test/regress/expected/prepared_xacts.out

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,32 +88,67 @@ SELECT gid FROM pg_prepared_xacts;
8888

8989
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
9090
INSERT INTO pxtest1 VALUES ('fff');
91+
-- This should fail, because the gid foo3 is already in use
92+
PREPARE TRANSACTION 'foo3';
93+
ERROR: transaction identifier "foo3" is already in use
9194
SELECT * FROM pxtest1;
9295
foobar
9396
--------
9497
aaa
9598
ddd
96-
fff
97-
(3 rows)
99+
(2 rows)
98100

99-
-- This should fail, because the gid foo3 is already in use
100-
PREPARE TRANSACTION 'foo3';
101-
ERROR: transaction identifier "foo3" is already in use
101+
ROLLBACK PREPARED 'foo3';
102102
SELECT * FROM pxtest1;
103103
foobar
104104
--------
105105
aaa
106106
ddd
107107
(2 rows)
108108

109-
ROLLBACK PREPARED 'foo3';
109+
-- Test serialization failure (SSI)
110+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
111+
UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
112+
SELECT * FROM pxtest1;
113+
foobar
114+
--------
115+
aaa
116+
eee
117+
(2 rows)
118+
119+
PREPARE TRANSACTION 'foo4';
120+
SELECT gid FROM pg_prepared_xacts;
121+
gid
122+
------
123+
foo4
124+
(1 row)
125+
126+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
110127
SELECT * FROM pxtest1;
111128
foobar
112129
--------
113130
aaa
114131
ddd
115132
(2 rows)
116133

134+
INSERT INTO pxtest1 VALUES ('fff');
135+
-- This should fail, because the two transactions have a write-skew anomaly
136+
PREPARE TRANSACTION 'foo5';
137+
ERROR: could not serialize access due to read/write dependencies among transactions
138+
DETAIL: Cancelled on commit attempt with conflict in from prepared pivot.
139+
HINT: The transaction might succeed if retried.
140+
SELECT gid FROM pg_prepared_xacts;
141+
gid
142+
------
143+
foo4
144+
(1 row)
145+
146+
ROLLBACK PREPARED 'foo4';
147+
SELECT gid FROM pg_prepared_xacts;
148+
gid
149+
-----
150+
(0 rows)
151+
117152
-- Clean up
118153
DROP TABLE pxtest1;
119154
-- Test subtransactions

src/test/regress/sql/prepared_xacts.sql

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ SELECT gid FROM pg_prepared_xacts;
5454

5555
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
5656
INSERT INTO pxtest1 VALUES ('fff');
57-
SELECT * FROM pxtest1;
5857

5958
-- This should fail, because the gid foo3 is already in use
6059
PREPARE TRANSACTION 'foo3';
@@ -65,6 +64,27 @@ ROLLBACK PREPARED 'foo3';
6564

6665
SELECT * FROM pxtest1;
6766

67+
-- Test serialization failure (SSI)
68+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
69+
UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
70+
SELECT * FROM pxtest1;
71+
PREPARE TRANSACTION 'foo4';
72+
73+
SELECT gid FROM pg_prepared_xacts;
74+
75+
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
76+
SELECT * FROM pxtest1;
77+
INSERT INTO pxtest1 VALUES ('fff');
78+
79+
-- This should fail, because the two transactions have a write-skew anomaly
80+
PREPARE TRANSACTION 'foo5';
81+
82+
SELECT gid FROM pg_prepared_xacts;
83+
84+
ROLLBACK PREPARED 'foo4';
85+
86+
SELECT gid FROM pg_prepared_xacts;
87+
6888
-- Clean up
6989
DROP TABLE pxtest1;
7090

0 commit comments

Comments
 (0)