diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 57d47e8601443d592982e6faffb7855391790b95..945684333198f16e535ee0e94b6ae851e71194af 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -3269,7 +3269,13 @@ l2: &xmax_old_tuple, &infomask_old_tuple, &infomask2_old_tuple); - /* And also prepare an Xmax value for the new copy of the tuple */ + /* + * And also prepare an Xmax value for the new copy of the tuple. If there + * was no xmax previously, or there was one but all lockers are now gone, + * then use InvalidXid; otherwise, get the xmax from the old tuple. (In + * rare cases that might also be InvalidXid and yet not have the + * HEAP_XMAX_INVALID bit set; that's fine.) + */ if ((oldtup.t_data->t_infomask & HEAP_XMAX_INVALID) || (checked_lockers && !locker_remains)) xmax_new_tuple = InvalidTransactionId; @@ -3283,6 +3289,12 @@ l2: } else { + /* + * If we found a valid Xmax for the new tuple, then the infomask bits + * to use on the new tuple depend on what was there on the old one. + * Note that since we're doing an update, the only possibility is that + * the lockers had FOR KEY SHARE lock. + */ if (oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) { GetMultiXactIdHintBits(xmax_new_tuple, &infomask_new_tuple, @@ -5161,6 +5173,7 @@ GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask, uint16 bits = HEAP_XMAX_IS_MULTI; uint16 bits2 = 0; bool has_update = false; + LockTupleMode strongest = LockTupleKeyShare; /* * We only use this in multis we just created, so they cannot be values @@ -5170,32 +5183,47 @@ GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask, for (i = 0; i < nmembers; i++) { + LockTupleMode mode; + + /* + * Remember the strongest lock mode held by any member of the + * multixact. + */ + mode = TUPLOCK_from_mxstatus(members[i].status); + if (mode > strongest) + strongest = mode; + + /* See what other bits we need */ switch (members[i].status) { case MultiXactStatusForKeyShare: - bits |= HEAP_XMAX_KEYSHR_LOCK; - break; case MultiXactStatusForShare: - bits |= HEAP_XMAX_SHR_LOCK; - break; case MultiXactStatusForNoKeyUpdate: - bits |= HEAP_XMAX_EXCL_LOCK; break; + case MultiXactStatusForUpdate: - bits |= HEAP_XMAX_EXCL_LOCK; bits2 |= HEAP_KEYS_UPDATED; break; + case MultiXactStatusNoKeyUpdate: - bits |= HEAP_XMAX_EXCL_LOCK; has_update = true; break; + case MultiXactStatusUpdate: - bits |= HEAP_XMAX_EXCL_LOCK; bits2 |= HEAP_KEYS_UPDATED; has_update = true; break; } } + + if (strongest == LockTupleExclusive || + strongest == LockTupleNoKeyExclusive) + bits |= HEAP_XMAX_EXCL_LOCK; + else if (strongest == LockTupleShare) + bits |= HEAP_XMAX_SHR_LOCK; + else if (strongest == LockTupleKeyShare) + bits |= HEAP_XMAX_KEYSHR_LOCK; + if (!has_update) bits |= HEAP_XMAX_LOCK_ONLY;