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

Commit406d618

Browse files
committed
SSI has a race condition, where the order of commit sequence numbers of
transactions might not match the order the work done in those transactionsbecome visible to others. The logic in SSI, however, assumed that it does.Fix that by having two sequence numbers for each serializable transaction,one taken before a transaction becomes visible to others, and one after it.This is easier than trying to make the the transition totally atomic, whichwould require holding ProcArrayLock and SerializableXactHashLock at the sametime. By using prepareSeqNo instead of commitSeqNo in a few places wherecommit sequence numbers are compared, we can make those comparisons err onthe safe side when we don't know for sure which committed first.Per analysis by Kevin Grittner and Dan Ports, but this approach to fix itis different from the original patch.
1 parentd7fb493 commit406d618

File tree

2 files changed

+30
-20
lines changed

2 files changed

+30
-20
lines changed

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

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ InitPredicateLocks(void)
11901190
}
11911191
PredXact->OldCommittedSxact=CreatePredXact();
11921192
SetInvalidVirtualTransactionId(PredXact->OldCommittedSxact->vxid);
1193+
PredXact->OldCommittedSxact->prepareSeqNo=0;
11931194
PredXact->OldCommittedSxact->commitSeqNo=0;
11941195
PredXact->OldCommittedSxact->SeqNo.lastCommitBeforeSnapshot=0;
11951196
SHMQueueInit(&PredXact->OldCommittedSxact->outConflicts);
@@ -1650,6 +1651,7 @@ RegisterSerializableTransactionInt(Snapshot snapshot)
16501651
/* Initialize the structure. */
16511652
sxact->vxid=vxid;
16521653
sxact->SeqNo.lastCommitBeforeSnapshot=PredXact->LastSxactCommitSeqNo;
1654+
sxact->prepareSeqNo=InvalidSerCommitSeqNo;
16531655
sxact->commitSeqNo=InvalidSerCommitSeqNo;
16541656
SHMQueueInit(&(sxact->outConflicts));
16551657
SHMQueueInit(&(sxact->inConflicts));
@@ -3267,8 +3269,8 @@ ReleasePredicateLocks(bool isCommit)
32673269
&&SxactIsCommitted(conflict->sxactIn))
32683270
{
32693271
if ((MySerializableXact->flags&SXACT_FLAG_CONFLICT_OUT)==0
3270-
||conflict->sxactIn->commitSeqNo<MySerializableXact->SeqNo.earliestOutConflictCommit)
3271-
MySerializableXact->SeqNo.earliestOutConflictCommit=conflict->sxactIn->commitSeqNo;
3272+
||conflict->sxactIn->prepareSeqNo<MySerializableXact->SeqNo.earliestOutConflictCommit)
3273+
MySerializableXact->SeqNo.earliestOutConflictCommit=conflict->sxactIn->prepareSeqNo;
32723274
MySerializableXact->flags |=SXACT_FLAG_CONFLICT_OUT;
32733275
}
32743276

@@ -4407,18 +4409,13 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
44074409
{
44084410
SERIALIZABLEXACT*t2=conflict->sxactIn;
44094411

4410-
/*
4411-
* Note that if T2 is merely prepared but not yet committed, we
4412-
* rely on t->commitSeqNo being InvalidSerCommitSeqNo, which is
4413-
* larger than any valid commit sequence number.
4414-
*/
44154412
if (SxactIsPrepared(t2)
44164413
&& (!SxactIsCommitted(reader)
4417-
||t2->commitSeqNo <=reader->commitSeqNo)
4414+
||t2->prepareSeqNo <=reader->commitSeqNo)
44184415
&& (!SxactIsCommitted(writer)
4419-
||t2->commitSeqNo <=writer->commitSeqNo)
4416+
||t2->prepareSeqNo <=writer->commitSeqNo)
44204417
&& (!SxactIsReadOnly(reader)
4421-
||t2->commitSeqNo <=reader->SeqNo.lastCommitBeforeSnapshot))
4418+
||t2->prepareSeqNo <=reader->SeqNo.lastCommitBeforeSnapshot))
44224419
{
44234420
failure= true;
44244421
break;
@@ -4459,17 +4456,11 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
44594456
{
44604457
SERIALIZABLEXACT*t0=conflict->sxactOut;
44614458

4462-
/*
4463-
* Note that if the writer is merely prepared but not yet
4464-
* committed, we rely on writer->commitSeqNo being
4465-
* InvalidSerCommitSeqNo, which is larger than any valid commit
4466-
* sequence number.
4467-
*/
44684459
if (!SxactIsDoomed(t0)
44694460
&& (!SxactIsCommitted(t0)
4470-
||t0->commitSeqNo >=writer->commitSeqNo)
4461+
||t0->commitSeqNo >=writer->prepareSeqNo)
44714462
&& (!SxactIsReadOnly(t0)
4472-
||t0->SeqNo.lastCommitBeforeSnapshot >=writer->commitSeqNo))
4463+
||t0->SeqNo.lastCommitBeforeSnapshot >=writer->prepareSeqNo))
44734464
{
44744465
failure= true;
44754466
break;
@@ -4608,6 +4599,7 @@ PreCommit_CheckForSerializationFailure(void)
46084599
offsetof(RWConflictData,inLink));
46094600
}
46104601

4602+
MySerializableXact->prepareSeqNo=++(PredXact->LastSxactCommitSeqNo);
46114603
MySerializableXact->flags |=SXACT_FLAG_PREPARED;
46124604

46134605
LWLockRelease(SerializableXactHashLock);
@@ -4782,6 +4774,7 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
47824774
sxact->pid=0;
47834775

47844776
/* a prepared xact hasn't committed yet */
4777+
sxact->prepareSeqNo=RecoverySerCommitSeqNo;
47854778
sxact->commitSeqNo=InvalidSerCommitSeqNo;
47864779
sxact->finishedBefore=InvalidTransactionId;
47874780

‎src/include/storage/predicate_internals.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,26 @@ typedef struct SERIALIZABLEXACT
5757
{
5858
VirtualTransactionIdvxid;/* The executing process always has one of
5959
* these. */
60+
61+
/*
62+
* We use two numbers to track the order that transactions commit. Before
63+
* commit, a transaction is marked as prepared, and prepareSeqNo is set.
64+
* Shortly after commit, it's marked as committed, and commitSeqNo is set.
65+
* This doesn't give a strict commit order, but these two values together
66+
* are good enough for us, as we can always err on the safe side and
67+
* assume that there's a conflict, if we can't be sure of the exact
68+
* ordering of two commits.
69+
*
70+
* Note that a transaction is marked as prepared for a short period during
71+
* commit processing, even if two-phase commit is not used. But with
72+
* two-phase commit, a transaction can stay in prepared state for some
73+
* time.
74+
*/
75+
SerCommitSeqNoprepareSeqNo;
6076
SerCommitSeqNocommitSeqNo;
61-
union/* these values are not both interesting at
62-
* the same time */
77+
78+
/* these values are not both interesting at the same time */
79+
union
6380
{
6481
SerCommitSeqNoearliestOutConflictCommit;/* when committed with
6582
* conflict out */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp