ssi-2pc-fix.patch

text/plain

Filename: ssi-2pc-fix.patch
Type: text/plain
Part: 1
Message: SSI 2PC coverage
*** a/src/backend/storage/lmgr/predicate.c
--- b/src/backend/storage/lmgr/predicate.c
***************
*** 244,249 ****
--- 244,257 ----
  
  #define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
  
+ /*
+  * Note that a sxact is marked "prepared" once it has passed
+  * PreCommit_CheckForSerializationFailure, even if it isn't using
+  * 2PC. This is the point at which it can no longer be aborted.
+  *
+  * The PREPARED flag remains set after commit, so SxactIsCommitted
+  * implies SxactIsPrepared.
+  */
  #define SxactIsCommitted(sxact) (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
  #define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
  #define SxactIsRolledBack(sxact) (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
***************
*** 3165,3170 **** ReleasePredicateLocks(bool isCommit)
--- 3173,3185 ----
  		 */
  		MySerializableXact->flags |= SXACT_FLAG_DOOMED;
  		MySerializableXact->flags |= SXACT_FLAG_ROLLED_BACK;
+ 		/*
+ 		 * If the transaction was previously prepared, but is now failing due
+ 		 * to a ROLLBACK PREPARED or (hopefully very rare) error after the
+ 		 * prepare, clear the prepared flag.  This simplifies conflict
+ 		 * checking,
+ 		 */
+ 		MySerializableXact->flags &= ~SXACT_FLAG_PREPARED;
  	}
  
  	if (!topLevelIsDeclaredReadOnly)
***************
*** 4381,4387 **** OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
  		{
  			SERIALIZABLEXACT *t2 = conflict->sxactIn;
  
! 			if (SxactIsCommitted(t2)
  				&& (!SxactIsCommitted(reader)
  					|| t2->commitSeqNo <= reader->commitSeqNo)
  				&& (!SxactIsCommitted(writer)
--- 4396,4402 ----
  		{
  			SERIALIZABLEXACT *t2 = conflict->sxactIn;
  
! 			if (SxactIsPrepared(t2)
  				&& (!SxactIsCommitted(reader)
  					|| t2->commitSeqNo <= reader->commitSeqNo)
  				&& (!SxactIsCommitted(writer)
***************
*** 4400,4406 **** OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
  	}
  
  	/*------------------------------------------------------------------------
! 	 * Check whether the reader has become a pivot with a committed writer:
  	 *
  	 *		T0 ------> R ------> W
  	 *			 rw		   rw
--- 4415,4422 ----
  	}
  
  	/*------------------------------------------------------------------------
! 	 * Check whether the reader has become a pivot with a writer
! 	 * that's committed or prepared:
  	 *
  	 *		T0 ------> R ------> W
  	 *			 rw		   rw
***************
*** 4411,4417 **** OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
  	 * - T0 is READ ONLY, and overlaps the writer
  	 *------------------------------------------------------------------------
  	 */
! 	if (!failure && SxactIsCommitted(writer) && !SxactIsReadOnly(reader))
  	{
  		if (SxactHasSummaryConflictIn(reader))
  		{
--- 4427,4433 ----
  	 * - T0 is READ ONLY, and overlaps the writer
  	 *------------------------------------------------------------------------
  	 */
! 	if (!failure && SxactIsPrepared(writer) && !SxactIsReadOnly(reader))
  	{
  		if (SxactHasSummaryConflictIn(reader))
  		{
*** a/src/test/regress/expected/prepared_xacts.out
--- b/src/test/regress/expected/prepared_xacts.out
***************
*** 131,142 **** 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:  Canceled on commit attempt with conflict in from prepared pivot.
  HINT:  The transaction might succeed if retried.
  SELECT gid FROM pg_prepared_xacts;
   gid  
  ------
--- 131,142 ----
   ddd
  (2 rows)
  
  -- This should fail, because the two transactions have a write-skew anomaly
! INSERT INTO pxtest1 VALUES ('fff');
  ERROR:  could not serialize access due to read/write dependencies among transactions
! DETAIL:  Cancelled on identification as a pivot, during write.
  HINT:  The transaction might succeed if retried.
+ PREPARE TRANSACTION 'foo5';
  SELECT gid FROM pg_prepared_xacts;
   gid  
  ------
*** a/src/test/regress/expected/prepared_xacts_1.out
--- b/src/test/regress/expected/prepared_xacts_1.out
***************
*** 134,141 **** SELECT * FROM pxtest1;
   aaa
  (1 row)
  
- INSERT INTO pxtest1 VALUES ('fff');
  -- This should fail, because the two transactions have a write-skew anomaly
  PREPARE TRANSACTION 'foo5';
  ERROR:  prepared transactions are disabled
  HINT:  Set max_prepared_transactions to a nonzero value.
--- 134,141 ----
   aaa
  (1 row)
  
  -- This should fail, because the two transactions have a write-skew anomaly
+ INSERT INTO pxtest1 VALUES ('fff');
  PREPARE TRANSACTION 'foo5';
  ERROR:  prepared transactions are disabled
  HINT:  Set max_prepared_transactions to a nonzero value.
*** a/src/test/regress/sql/prepared_xacts.sql
--- b/src/test/regress/sql/prepared_xacts.sql
***************
*** 74,82 **** 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;
--- 74,82 ----
  
  BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  SELECT * FROM pxtest1;
  
  -- This should fail, because the two transactions have a write-skew anomaly
+ INSERT INTO pxtest1 VALUES ('fff');
  PREPARE TRANSACTION 'foo5';
  
  SELECT gid FROM pg_prepared_xacts;