Skip to content

Commit 07aeb1f

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 86ef479 commit 07aeb1f

File tree

2 files changed

+22
-12
lines changed

2 files changed

+22
-12
lines changed

src/backend/utils/time/tqual.c

+17-4
Original file line numberDiff line numberDiff line change
@@ -596,13 +596,26 @@ HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
596596
if (TransactionIdDidCommit(xmax))
597597
return HeapTupleUpdated;
598598

599-
/* no member, even just a locker, alive anymore */
599+
/*
600+
* By here, the update in the Xmax is either aborted or crashed, but
601+
* what about the other members?
602+
*/
603+
600604
if (!MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple)))
605+
{
606+
/*
607+
* There's no member, even just a locker, alive anymore, so we can
608+
* mark the Xmax as invalid.
609+
*/
601610
SetHintBits(tuple, buffer, HEAP_XMAX_INVALID,
602611
InvalidTransactionId);
603-
604-
/* it must have aborted or crashed */
605-
return HeapTupleMayBeUpdated;
612+
return HeapTupleMayBeUpdated;
613+
}
614+
else
615+
{
616+
/* There are lockers running */
617+
return HeapTupleBeingUpdated;
618+
}
606619
}
607620

608621
if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))

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

+5-8
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)