OSDN Git Service

Fix bug in PreCommit_CheckForSerializationFailure. A transaction that has
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 21 Jun 2011 11:32:11 +0000 (14:32 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Tue, 21 Jun 2011 11:49:50 +0000 (14:49 +0300)
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

src/backend/storage/lmgr/predicate.c
src/test/regress/expected/prepared_xacts.out
src/test/regress/sql/prepared_xacts.sql

index 8cbca78..2293c75 100644 (file)
@@ -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;
                                }
index 1a6b4ce..328cd74 100644 (file)
@@ -88,17 +88,17 @@ SELECT gid FROM pg_prepared_xacts;
 
 BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
 INSERT INTO pxtest1 VALUES ('fff');
+-- This should fail, because the gid foo3 is already in use
+PREPARE TRANSACTION 'foo3';
+ERROR:  transaction identifier "foo3" is already in use
 SELECT * FROM pxtest1;
  foobar 
 --------
  aaa
  ddd
- fff
-(3 rows)
+(2 rows)
 
--- This should fail, because the gid foo3 is already in use
-PREPARE TRANSACTION 'foo3';
-ERROR:  transaction identifier "foo3" is already in use
+ROLLBACK PREPARED 'foo3';
 SELECT * FROM pxtest1;
  foobar 
 --------
@@ -106,7 +106,24 @@ SELECT * FROM pxtest1;
  ddd
 (2 rows)
 
-ROLLBACK PREPARED 'foo3';
+-- 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 
 --------
@@ -114,6 +131,24 @@ SELECT * FROM pxtest1;
  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
index 2bdbb0d..e06c9d4 100644 (file)
@@ -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;