mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
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
This commit is contained in:
parent
7cb2ff9621
commit
1eea8e8a06
@ -4542,6 +4542,21 @@ PreCommit_CheckForSerializationFailure(void)
|
|||||||
&& !SxactIsReadOnly(farConflict->sxactOut)
|
&& !SxactIsReadOnly(farConflict->sxactOut)
|
||||||
&& !SxactIsDoomed(farConflict->sxactOut)))
|
&& !SxactIsDoomed(farConflict->sxactOut)))
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* Normally, we kill the pivot transaction to make sure we
|
||||||
|
* make progress if the failing transaction is retried.
|
||||||
|
* However, we can't kill it if it's already prepared, so
|
||||||
|
* in that case we commit suicide instead.
|
||||||
|
*/
|
||||||
|
if (SxactIsPrepared(nearConflict->sxactOut))
|
||||||
|
{
|
||||||
|
LWLockRelease(SerializableXactHashLock);
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
|
||||||
|
errmsg("could not serialize access due to read/write dependencies among transactions"),
|
||||||
|
errdetail("Cancelled on commit attempt with conflict in from prepared pivot."),
|
||||||
|
errhint("The transaction might succeed if retried.")));
|
||||||
|
}
|
||||||
nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
|
nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -88,14 +88,6 @@ SELECT gid FROM pg_prepared_xacts;
|
|||||||
|
|
||||||
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
INSERT INTO pxtest1 VALUES ('fff');
|
INSERT INTO pxtest1 VALUES ('fff');
|
||||||
SELECT * FROM pxtest1;
|
|
||||||
foobar
|
|
||||||
--------
|
|
||||||
aaa
|
|
||||||
ddd
|
|
||||||
fff
|
|
||||||
(3 rows)
|
|
||||||
|
|
||||||
-- This should fail, because the gid foo3 is already in use
|
-- This should fail, because the gid foo3 is already in use
|
||||||
PREPARE TRANSACTION 'foo3';
|
PREPARE TRANSACTION 'foo3';
|
||||||
ERROR: transaction identifier "foo3" is already in use
|
ERROR: transaction identifier "foo3" is already in use
|
||||||
@ -114,6 +106,49 @@ SELECT * FROM pxtest1;
|
|||||||
ddd
|
ddd
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
|
-- Test serialization failure (SSI)
|
||||||
|
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
|
UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
|
||||||
|
SELECT * FROM pxtest1;
|
||||||
|
foobar
|
||||||
|
--------
|
||||||
|
aaa
|
||||||
|
eee
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
PREPARE TRANSACTION 'foo4';
|
||||||
|
SELECT gid FROM pg_prepared_xacts;
|
||||||
|
gid
|
||||||
|
------
|
||||||
|
foo4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
|
SELECT * FROM pxtest1;
|
||||||
|
foobar
|
||||||
|
--------
|
||||||
|
aaa
|
||||||
|
ddd
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
INSERT INTO pxtest1 VALUES ('fff');
|
||||||
|
-- This should fail, because the two transactions have a write-skew anomaly
|
||||||
|
PREPARE TRANSACTION 'foo5';
|
||||||
|
ERROR: could not serialize access due to read/write dependencies among transactions
|
||||||
|
DETAIL: Cancelled on commit attempt with conflict in from prepared pivot.
|
||||||
|
HINT: The transaction might succeed if retried.
|
||||||
|
SELECT gid FROM pg_prepared_xacts;
|
||||||
|
gid
|
||||||
|
------
|
||||||
|
foo4
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ROLLBACK PREPARED 'foo4';
|
||||||
|
SELECT gid FROM pg_prepared_xacts;
|
||||||
|
gid
|
||||||
|
-----
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
-- Clean up
|
-- Clean up
|
||||||
DROP TABLE pxtest1;
|
DROP TABLE pxtest1;
|
||||||
-- Test subtransactions
|
-- Test subtransactions
|
||||||
|
@ -54,7 +54,6 @@ SELECT gid FROM pg_prepared_xacts;
|
|||||||
|
|
||||||
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
INSERT INTO pxtest1 VALUES ('fff');
|
INSERT INTO pxtest1 VALUES ('fff');
|
||||||
SELECT * FROM pxtest1;
|
|
||||||
|
|
||||||
-- This should fail, because the gid foo3 is already in use
|
-- This should fail, because the gid foo3 is already in use
|
||||||
PREPARE TRANSACTION 'foo3';
|
PREPARE TRANSACTION 'foo3';
|
||||||
@ -65,6 +64,27 @@ ROLLBACK PREPARED 'foo3';
|
|||||||
|
|
||||||
SELECT * FROM pxtest1;
|
SELECT * FROM pxtest1;
|
||||||
|
|
||||||
|
-- Test serialization failure (SSI)
|
||||||
|
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
|
UPDATE pxtest1 SET foobar = 'eee' WHERE foobar = 'ddd';
|
||||||
|
SELECT * FROM pxtest1;
|
||||||
|
PREPARE TRANSACTION 'foo4';
|
||||||
|
|
||||||
|
SELECT gid FROM pg_prepared_xacts;
|
||||||
|
|
||||||
|
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
|
||||||
|
SELECT * FROM pxtest1;
|
||||||
|
INSERT INTO pxtest1 VALUES ('fff');
|
||||||
|
|
||||||
|
-- This should fail, because the two transactions have a write-skew anomaly
|
||||||
|
PREPARE TRANSACTION 'foo5';
|
||||||
|
|
||||||
|
SELECT gid FROM pg_prepared_xacts;
|
||||||
|
|
||||||
|
ROLLBACK PREPARED 'foo4';
|
||||||
|
|
||||||
|
SELECT gid FROM pg_prepared_xacts;
|
||||||
|
|
||||||
-- Clean up
|
-- Clean up
|
||||||
DROP TABLE pxtest1;
|
DROP TABLE pxtest1;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user