mirror of
				https://github.com/postgres/postgres.git
				synced 2025-11-03 09:13:20 +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:
		@@ -4542,6 +4542,21 @@ PreCommit_CheckForSerializationFailure(void)
 | 
			
		||||
						&& !SxactIsReadOnly(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;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -88,14 +88,6 @@ SELECT gid FROM pg_prepared_xacts;
 | 
			
		||||
 | 
			
		||||
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
 | 
			
		||||
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
 | 
			
		||||
PREPARE TRANSACTION 'foo3';
 | 
			
		||||
ERROR:  transaction identifier "foo3" is already in use
 | 
			
		||||
@@ -114,6 +106,49 @@ SELECT * FROM pxtest1;
 | 
			
		||||
 ddd
 | 
			
		||||
(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
 | 
			
		||||
DROP TABLE pxtest1;
 | 
			
		||||
-- Test subtransactions
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,6 @@ SELECT gid FROM pg_prepared_xacts;
 | 
			
		||||
 | 
			
		||||
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
 | 
			
		||||
INSERT INTO pxtest1 VALUES ('fff');
 | 
			
		||||
SELECT * FROM pxtest1;
 | 
			
		||||
 | 
			
		||||
-- This should fail, because the gid foo3 is already in use
 | 
			
		||||
PREPARE TRANSACTION 'foo3';
 | 
			
		||||
@@ -65,6 +64,27 @@ ROLLBACK PREPARED 'foo3';
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
DROP TABLE pxtest1;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user