Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit928408d

Browse files
committed
Fix a bug with SSI and prepared transactions:
If there's a dangerous structure T0 ---> T1 ---> T2, and T2 commits first,we need to abort something. If T2 commits before both conflicts appear,then it should be caught by OnConflict_CheckForSerializationFailure. Ifboth conflicts appear before T2 commits, it should be caught byPreCommit_CheckForSerializationFailure. But that is actually run whenT2 *prepares*. Fix that in OnConflict_CheckForSerializationFailure, bytreating a prepared T2 as if it committed already.This is mostly a problem for prepared transactions, which are in preparedstate for some time, but also for regular transactions because they also gothrough the prepared state in the SSI code for a short moment when they'recommitted.Kevin Grittner and Dan Ports
1 parentb2e3be4 commit928408d

File tree

4 files changed

+40
-8
lines changed

4 files changed

+40
-8
lines changed

‎src/backend/storage/lmgr/predicate.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,14 @@
244244

245245
#defineSxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
246246

247+
/*
248+
* Note that a sxact is marked "prepared" once it has passed
249+
* PreCommit_CheckForSerializationFailure, even if it isn't using
250+
* 2PC. This is the point at which it can no longer be aborted.
251+
*
252+
* The PREPARED flag remains set after commit, so SxactIsCommitted
253+
* implies SxactIsPrepared.
254+
*/
247255
#defineSxactIsCommitted(sxact) (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
248256
#defineSxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
249257
#defineSxactIsRolledBack(sxact) (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
@@ -3165,6 +3173,13 @@ ReleasePredicateLocks(bool isCommit)
31653173
*/
31663174
MySerializableXact->flags |=SXACT_FLAG_DOOMED;
31673175
MySerializableXact->flags |=SXACT_FLAG_ROLLED_BACK;
3176+
/*
3177+
* If the transaction was previously prepared, but is now failing due
3178+
* to a ROLLBACK PREPARED or (hopefully very rare) error after the
3179+
* prepare, clear the prepared flag. This simplifies conflict
3180+
* checking.
3181+
*/
3182+
MySerializableXact->flags &= ~SXACT_FLAG_PREPARED;
31683183
}
31693184

31703185
if (!topLevelIsDeclaredReadOnly)
@@ -4363,6 +4378,11 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
43634378
* - the writer committed before T2
43644379
* - the reader is a READ ONLY transaction and the reader was concurrent
43654380
* with T2 (= reader acquired its snapshot before T2 committed)
4381+
*
4382+
* We also handle the case that T2 is prepared but not yet committed
4383+
* here. In that case T2 has already checked for conflicts, so if it
4384+
* commits first, making the above conflict real, it's too late for it
4385+
* to abort.
43664386
*------------------------------------------------------------------------
43674387
*/
43684388
if (!failure)
@@ -4381,7 +4401,12 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
43814401
{
43824402
SERIALIZABLEXACT*t2=conflict->sxactIn;
43834403

4384-
if (SxactIsCommitted(t2)
4404+
/*
4405+
* Note that if T2 is merely prepared but not yet committed, we
4406+
* rely on t->commitSeqNo being InvalidSerCommitSeqNo, which is
4407+
* larger than any valid commit sequence number.
4408+
*/
4409+
if (SxactIsPrepared(t2)
43854410
&& (!SxactIsCommitted(reader)
43864411
||t2->commitSeqNo <=reader->commitSeqNo)
43874412
&& (!SxactIsCommitted(writer)
@@ -4400,7 +4425,8 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
44004425
}
44014426

44024427
/*------------------------------------------------------------------------
4403-
* Check whether the reader has become a pivot with a committed writer:
4428+
* Check whether the reader has become a pivot with a writer
4429+
* that's committed (or prepared):
44044430
*
44054431
*T0 ------> R ------> W
44064432
* rw rw
@@ -4411,7 +4437,7 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
44114437
* - T0 is READ ONLY, and overlaps the writer
44124438
*------------------------------------------------------------------------
44134439
*/
4414-
if (!failure&&SxactIsCommitted(writer)&& !SxactIsReadOnly(reader))
4440+
if (!failure&&SxactIsPrepared(writer)&& !SxactIsReadOnly(reader))
44154441
{
44164442
if (SxactHasSummaryConflictIn(reader))
44174443
{
@@ -4427,6 +4453,12 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
44274453
{
44284454
SERIALIZABLEXACT*t0=conflict->sxactOut;
44294455

4456+
/*
4457+
* Note that if the writer is merely prepared but not yet
4458+
* committed, we rely on writer->commitSeqNo being
4459+
* InvalidSerCommitSeqNo, which is larger than any valid commit
4460+
* sequence number.
4461+
*/
44304462
if (!SxactIsDoomed(t0)
44314463
&& (!SxactIsCommitted(t0)
44324464
||t0->commitSeqNo >=writer->commitSeqNo)

‎src/test/regress/expected/prepared_xacts.out

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,12 +131,12 @@ SELECT * FROM pxtest1;
131131
ddd
132132
(2 rows)
133133

134-
INSERT INTO pxtest1 VALUES ('fff');
135134
-- This should fail, because the two transactions have a write-skew anomaly
136-
PREPARE TRANSACTION 'foo5';
135+
INSERT INTO pxtest1 VALUES ('fff');
137136
ERROR: could not serialize access due to read/write dependencies among transactions
138-
DETAIL: Canceled oncommit attempt with conflict in from prepared pivot.
137+
DETAIL: Canceled onidentification as a pivot, during write.
139138
HINT: The transaction might succeed if retried.
139+
PREPARE TRANSACTION 'foo5';
140140
SELECT gid FROM pg_prepared_xacts;
141141
gid
142142
------

‎src/test/regress/expected/prepared_xacts_1.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ SELECT * FROM pxtest1;
134134
aaa
135135
(1 row)
136136

137-
INSERT INTO pxtest1 VALUES ('fff');
138137
-- This should fail, because the two transactions have a write-skew anomaly
138+
INSERT INTO pxtest1 VALUES ('fff');
139139
PREPARE TRANSACTION 'foo5';
140140
ERROR: prepared transactions are disabled
141141
HINT: Set max_prepared_transactions to a nonzero value.

‎src/test/regress/sql/prepared_xacts.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ SELECT gid FROM pg_prepared_xacts;
7474

7575
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
7676
SELECT*FROM pxtest1;
77-
INSERT INTO pxtest1VALUES ('fff');
7877

7978
-- This should fail, because the two transactions have a write-skew anomaly
79+
INSERT INTO pxtest1VALUES ('fff');
8080
PREPARE TRANSACTION'foo5';
8181

8282
SELECT gidFROM pg_prepared_xacts;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp