Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b78647a

Browse files
committed
Restrict infomask bits to set on multixacts
We must only set the bit(s) for the strongest lock held in the tuple; otherwise, a multixact containing members with exclusive lock and key-share lock will behave as though only a share lock is held. This bug was introduced in commit 0ac5ad5, somewhere along development, when we allowed a singleton FOR SHARE lock to be implemented without a MultiXact by using a multi-bit pattern. I overlooked that GetMultiXactIdHintBits() needed to be tweaked as well. Previously, we could have the bits for FOR KEY SHARE and FOR UPDATE simultaneously set and it wouldn't cause a problem. Per report from digoal@126.com
1 parent 77a3082 commit b78647a

File tree

1 file changed

+37
-9
lines changed

1 file changed

+37
-9
lines changed

src/backend/access/heap/heapam.c

+37-9
Original file line numberDiff line numberDiff line change
@@ -3269,7 +3269,13 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
32693269
&xmax_old_tuple, &infomask_old_tuple,
32703270
&infomask2_old_tuple);
32713271

3272-
/* And also prepare an Xmax value for the new copy of the tuple */
3272+
/*
3273+
* And also prepare an Xmax value for the new copy of the tuple. If there
3274+
* was no xmax previously, or there was one but all lockers are now gone,
3275+
* then use InvalidXid; otherwise, get the xmax from the old tuple. (In
3276+
* rare cases that might also be InvalidXid and yet not have the
3277+
* HEAP_XMAX_INVALID bit set; that's fine.)
3278+
*/
32733279
if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) ||
32743280
(checked_lockers && !locker_remains))
32753281
xmax_new_tuple = InvalidTransactionId;
@@ -3283,6 +3289,12 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
32833289
}
32843290
else
32853291
{
3292+
/*
3293+
* If we found a valid Xmax for the new tuple, then the infomask bits
3294+
* to use on the new tuple depend on what was there on the old one.
3295+
* Note that since we're doing an update, the only possibility is that
3296+
* the lockers had FOR KEY SHARE lock.
3297+
*/
32863298
if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI)
32873299
{
32883300
GetMultiXactIdHintBits(xmax_new_tuple, &infomask_new_tuple,
@@ -5161,6 +5173,7 @@ GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
51615173
uint16 bits = HEAP_XMAX_IS_MULTI;
51625174
uint16 bits2 = 0;
51635175
bool has_update = false;
5176+
LockTupleMode strongest = LockTupleKeyShare;
51645177

51655178
/*
51665179
* We only use this in multis we just created, so they cannot be values
@@ -5170,32 +5183,47 @@ GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask,
51705183

51715184
for (i = 0; i < nmembers; i++)
51725185
{
5186+
LockTupleMode mode;
5187+
5188+
/*
5189+
* Remember the strongest lock mode held by any member of the
5190+
* multixact.
5191+
*/
5192+
mode = TUPLOCK_from_mxstatus(members[i].status);
5193+
if (mode > strongest)
5194+
strongest = mode;
5195+
5196+
/* See what other bits we need */
51735197
switch (members[i].status)
51745198
{
51755199
case MultiXactStatusForKeyShare:
5176-
bits |= HEAP_XMAX_KEYSHR_LOCK;
5177-
break;
51785200
case MultiXactStatusForShare:
5179-
bits |= HEAP_XMAX_SHR_LOCK;
5180-
break;
51815201
case MultiXactStatusForNoKeyUpdate:
5182-
bits |= HEAP_XMAX_EXCL_LOCK;
51835202
break;
5203+
51845204
case MultiXactStatusForUpdate:
5185-
bits |= HEAP_XMAX_EXCL_LOCK;
51865205
bits2 |= HEAP_KEYS_UPDATED;
51875206
break;
5207+
51885208
case MultiXactStatusNoKeyUpdate:
5189-
bits |= HEAP_XMAX_EXCL_LOCK;
51905209
has_update = true;
51915210
break;
5211+
51925212
case MultiXactStatusUpdate:
5193-
bits |= HEAP_XMAX_EXCL_LOCK;
51945213
bits2 |= HEAP_KEYS_UPDATED;
51955214
has_update = true;
51965215
break;
51975216
}
51985217
}
5218+
5219+
if (strongest == LockTupleExclusive ||
5220+
strongest == LockTupleNoKeyExclusive)
5221+
bits |= HEAP_XMAX_EXCL_LOCK;
5222+
else if (strongest == LockTupleShare)
5223+
bits |= HEAP_XMAX_SHR_LOCK;
5224+
else if (strongest == LockTupleKeyShare)
5225+
bits |= HEAP_XMAX_KEYSHR_LOCK;
5226+
51995227
if (!has_update)
52005228
bits |= HEAP_XMAX_LOCK_ONLY;
52015229

0 commit comments

Comments
 (0)