Skip to content

Commit c6cd27e

Browse files
committed
Avoid resetting Xmax when it's a multi with an aborted update
HeapTupleSatisfiesUpdate can very easily "forget" tuple locks while checking the contents of a multixact and finding it contains an aborted update, by setting the HEAP_XMAX_INVALID bit. This would lead to concurrent transactions not noticing any previous locks held by transactions that might still be running, and thus being able to acquire subsequent locks they wouldn't be normally able to acquire. This bug was introduced in commit 1ce150b; backpatch this fix to 9.3, like that commit. This change reverts the change to the delete-abort-savept isolation test in 1ce150b, because that behavior change was caused by this bug. Noticed by Andres Freund while investigating a different issue reported by Noah Misch.
1 parent 8fd04cb commit c6cd27e

File tree

2 files changed

+22
-12
lines changed

2 files changed

+22
-12
lines changed

src/backend/utils/time/tqual.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -789,13 +789,26 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
789789
if (TransactionIdDidCommit(xmax))
790790
return HeapTupleUpdated;
791791

792-
/* no member, even just a locker, alive anymore */
792+
/*
793+
* By here, the update in the Xmax is either aborted or crashed, but
794+
* what about the other members?
795+
*/
796+
793797
if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
798+
{
799+
/*
800+
* There's no member, even just a locker, alive anymore, so we can
801+
* mark the Xmax as invalid.
802+
*/
794803
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
795804
InvalidTransactionId);
796-
797-
/* it must have aborted or crashed */
798-
return HeapTupleMayBeUpdated;
805+
return HeapTupleMayBeUpdated;
806+
}
807+
else
808+
{
809+
/* There are lockers running */
810+
return HeapTupleBeingUpdated;
811+
}
799812
}
800813

801814
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))

src/test/isolation/expected/delete-abort-savept.out

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ key value
2323
step s1svp: SAVEPOINT f;
2424
step s1d: DELETE FROM foo;
2525
step s1r: ROLLBACK TO f;
26-
step s2l: SELECT * FROM foo FOR UPDATE;
26+
step s2l: SELECT * FROM foo FOR UPDATE; <waiting ...>
27+
step s1c: COMMIT;
28+
step s2l: <... completed>
2729
key value
2830

2931
1 1
30-
step s1c: COMMIT;
3132
step s2c: COMMIT;
3233

3334
starting permutation: s1l s1svp s1d s1r s2l s2c s1c
@@ -38,12 +39,8 @@ key value
3839
step s1svp: SAVEPOINT f;
3940
step s1d: DELETE FROM foo;
4041
step s1r: ROLLBACK TO f;
41-
step s2l: SELECT * FROM foo FOR UPDATE;
42-
key value
43-
44-
1 1
45-
step s2c: COMMIT;
46-
step s1c: COMMIT;
42+
step s2l: SELECT * FROM foo FOR UPDATE; <waiting ...>
43+
invalid permutation detected
4744

4845
starting permutation: s1l s1svp s1d s2l s1r s1c s2c
4946
step s1l: SELECT * FROM foo FOR KEY SHARE;

0 commit comments

Comments
 (0)