ssi-2pc-fix.patch
text/plain
*** 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;