*** a/contrib/pgrowlocks/pgrowlocks.c
--- b/contrib/pgrowlocks/pgrowlocks.c
***************
*** 136,149 **** pgrowlocks(PG_FUNCTION_ARGS)
  		infomask = tuple->t_data->t_infomask;
  
  		/*
! 		 * a tuple is locked if HTSU returns BeingUpdated, and if it returns
! 		 * MayBeUpdated but the Xmax is valid and pointing at us.
  		 */
! 		if (htsu == HeapTupleBeingUpdated ||
! 			(htsu == HeapTupleMayBeUpdated &&
! 			 !(infomask & HEAP_XMAX_INVALID) &&
! 			 !(infomask & HEAP_XMAX_IS_MULTI) &&
! 			 (xmax == GetCurrentTransactionIdIfAny())))
  		{
  			char	  **values;
  
--- 136,144 ----
  		infomask = tuple->t_data->t_infomask;
  
  		/*
! 		 * A tuple is locked if HTSU returns BeingUpdated.
  		 */
! 		if (htsu == HeapTupleBeingUpdated)
  		{
  			char	  **values;
  
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 2711,2791 **** l1:
  	}
  	else if (result == HeapTupleBeingUpdated && wait)
  	{
- 		TransactionId xwait;
- 		uint16		infomask;
- 
- 		/* must copy state data before unlocking buffer */
- 		xwait = HeapTupleHeaderGetRawXmax(tp.t_data);
- 		infomask = tp.t_data->t_infomask;
- 
- 		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
- 
  		/*
! 		 * Acquire tuple lock to establish our priority for the tuple (see
! 		 * heap_lock_tuple).  LockTuple will release us when we are
! 		 * next-in-line for the tuple.
  		 *
! 		 * If we are forced to "start over" below, we keep the tuple lock;
! 		 * this arranges that we stay at the head of the line while rechecking
! 		 * tuple state.
  		 */
! 		if (!have_tuple_lock)
  		{
! 			LockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
! 			have_tuple_lock = true;
  		}
  
! 		/*
! 		 * Sleep until concurrent transaction ends.  Note that we don't care
! 		 * which lock mode the locker has, because we need the strongest one.
! 		 */
  
! 		if (infomask & HEAP_XMAX_IS_MULTI)
! 		{
! 			/* wait for multixact */
! 			MultiXactIdWait((MultiXactId) xwait, MultiXactStatusUpdate, infomask,
! 							relation, &tp.t_data->t_ctid, XLTW_Delete,
! 							NULL);
! 			LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  			/*
! 			 * If xwait had just locked the tuple then some other xact could
! 			 * update this tuple before we get to this point.  Check for xmax
! 			 * change, and start over if so.
  			 */
! 			if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
! 				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
! 									 xwait))
! 				goto l1;
  
  			/*
! 			 * You might think the multixact is necessarily done here, but not
! 			 * so: it could have surviving members, namely our own xact or
! 			 * other subxacts of this backend.  It is legal for us to delete
! 			 * the tuple in either case, however (the latter case is
! 			 * essentially a situation of upgrading our former shared lock to
! 			 * exclusive).  We don't bother changing the on-disk hint bits
! 			 * since we are about to overwrite the xmax altogether.
  			 */
- 		}
- 		else
- 		{
- 			/* wait for regular transaction to end */
- 			XactLockTableWait(xwait, relation, &tp.t_data->t_ctid, XLTW_Delete);
- 			LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
! 			/*
! 			 * xwait is done, but if xwait had just locked the tuple then some
! 			 * other xact could update this tuple before we get to this point.
! 			 * Check for xmax change, and start over if so.
! 			 */
! 			if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
! 				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
! 									 xwait))
! 				goto l1;
  
! 			/* Otherwise check if it committed or aborted */
! 			UpdateXmaxHintBits(tp.t_data, buffer, xwait);
  		}
  
  		/*
--- 2711,2814 ----
  	}
  	else if (result == HeapTupleBeingUpdated && wait)
  	{
  		/*
! 		 * Somebody is holding a lock on the tuple, or updating it; we now
! 		 * need to sleep on that transaction before we can proceed.  However,
! 		 * if the only locker is our own transaction (or any subtransaction of
! 		 * the current top transaction), then it's not necessary to do so.
! 		 * Note we only check for this case when the locker is a single xid,
! 		 * because MultiXactIdWait is prepared to deal with it.
  		 *
! 		 * This must be done before acquiring our tuple lock, to avoid
! 		 * deadlocks with other transactions that are already waiting on the
! 		 * lock we hold.
  		 */
! 		if (!(tp.t_data->t_infomask & HEAP_XMAX_IS_MULTI) &&
! 			TransactionIdIsCurrentTransactionId(
! 									   HeapTupleHeaderGetRawXmax(tp.t_data)))
  		{
! 			Assert(HEAP_XMAX_IS_LOCKED_ONLY(tp.t_data->t_infomask));
  		}
+ 		else
+ 		{
+ 			TransactionId xwait;
+ 			uint16		infomask;
  
! 			/* must copy state data before unlocking buffer */
! 			xwait = HeapTupleHeaderGetRawXmax(tp.t_data);
! 			infomask = tp.t_data->t_infomask;
  
! 			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  
  			/*
! 			 * Acquire tuple lock to establish our priority for the tuple (see
! 			 * heap_lock_tuple).  LockTuple will release us when we are
! 			 * next-in-line for the tuple.
! 			 *
! 			 * If we are forced to "start over" below, we keep the tuple lock;
! 			 * this arranges that we stay at the head of the line while
! 			 * rechecking tuple state.
  			 */
! 			if (!have_tuple_lock)
! 			{
! 				LockTupleTuplock(relation, &(tp.t_self), LockTupleExclusive);
! 				have_tuple_lock = true;
! 			}
  
  			/*
! 			 * Sleep until concurrent transaction ends.  Note that we don't
! 			 * care which lock mode the locker has, because we need the
! 			 * strongest one.
  			 */
  
! 			if (infomask & HEAP_XMAX_IS_MULTI)
! 			{
! 				/* wait for multixact */
! 				MultiXactIdWait((MultiXactId) xwait, MultiXactStatusUpdate, infomask,
! 								relation, &tp.t_data->t_ctid, XLTW_Delete,
! 								NULL);
! 				LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
! 
! 				/*
! 				 * If xwait had just locked the tuple then some other xact
! 				 * could update this tuple before we get to this point.  Check
! 				 * for xmax change, and start over if so.
! 				 */
! 				if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
! 					!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
! 										 xwait))
! 					goto l1;
! 
! 				/*
! 				 * You might think the multixact is necessarily done here, but
! 				 * not so: it could have surviving members, namely our own
! 				 * xact or other subxacts of this backend.  It is legal for us
! 				 * to delete the tuple in either case, however (the latter
! 				 * case is essentially a situation of upgrading our former
! 				 * shared lock to exclusive).  We don't bother changing the
! 				 * on-disk hint bits since we are about to overwrite the xmax
! 				 * altogether.
! 				 */
! 			}
! 			else
! 			{
! 				/* wait for regular transaction to end */
! 				XactLockTableWait(xwait, relation, &tp.t_data->t_ctid, XLTW_Delete);
! 				LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
! 				/*
! 				 * xwait is done, but if xwait had just locked the tuple then
! 				 * some other xact could update this tuple before we get to
! 				 * this point. Check for xmax change, and start over if so.
! 				 */
! 				if (xmax_infomask_changed(tp.t_data->t_infomask, infomask) ||
! 					!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
! 										 xwait))
! 					goto l1;
! 
! 				/* Otherwise check if it committed or aborted */
! 				UpdateXmaxHintBits(tp.t_data, buffer, xwait);
! 			}
  		}
  
  		/*
***************
*** 3239,3246 **** l2:
  	}
  	else if (result == HeapTupleBeingUpdated && wait)
  	{
- 		TransactionId xwait;
- 		uint16		infomask;
  		bool		can_continue = false;
  
  		checked_lockers = true;
--- 3262,3267 ----
***************
*** 3258,3396 **** l2:
  		 * heap_update directly.
  		 */
  
- 		/* must copy state data before unlocking buffer */
- 		xwait = HeapTupleHeaderGetRawXmax(oldtup.t_data);
- 		infomask = oldtup.t_data->t_infomask;
- 
- 		LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
- 
  		/*
! 		 * Acquire tuple lock to establish our priority for the tuple (see
! 		 * heap_lock_tuple).  LockTuple will release us when we are
! 		 * next-in-line for the tuple.
  		 *
! 		 * If we are forced to "start over" below, we keep the tuple lock;
! 		 * this arranges that we stay at the head of the line while rechecking
! 		 * tuple state.
  		 */
! 		if (!have_tuple_lock)
  		{
! 			LockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
! 			have_tuple_lock = true;
! 		}
  
! 		/*
! 		 * Now we have to do something about the existing locker.  If it's a
! 		 * multi, sleep on it; we might be awakened before it is completely
! 		 * gone (or even not sleep at all in some cases); we need to preserve
! 		 * it as locker, unless it is gone completely.
! 		 *
! 		 * If it's not a multi, we need to check for sleeping conditions
! 		 * before actually going to sleep.  If the update doesn't conflict
! 		 * with the locks, we just continue without sleeping (but making sure
! 		 * it is preserved).
! 		 */
! 		if (infomask & HEAP_XMAX_IS_MULTI)
  		{
! 			TransactionId update_xact;
! 			int			remain;
  
! 			/* wait for multixact */
! 			MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
! 							relation, &oldtup.t_data->t_ctid, XLTW_Update,
! 							&remain);
! 			LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
! 			/*
! 			 * If xwait had just locked the tuple then some other xact could
! 			 * update this tuple before we get to this point.  Check for xmax
! 			 * change, and start over if so.
! 			 */
! 			if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
! 				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
! 									 xwait))
! 				goto l2;
  
  			/*
! 			 * Note that the multixact may not be done by now.  It could have
! 			 * surviving members; our own xact or other subxacts of this
! 			 * backend, and also any other concurrent transaction that locked
! 			 * the tuple with KeyShare if we only got TupleLockUpdate.  If
! 			 * this is the case, we have to be careful to mark the updated
! 			 * tuple with the surviving members in Xmax.
  			 *
! 			 * Note that there could have been another update in the
! 			 * MultiXact. In that case, we need to check whether it committed
! 			 * or aborted. If it aborted we are safe to update it again;
! 			 * otherwise there is an update conflict, and we have to return
! 			 * HeapTupleUpdated below.
! 			 *
! 			 * In the LockTupleExclusive case, we still need to preserve the
! 			 * surviving members: those would include the tuple locks we had
! 			 * before this one, which are important to keep in case this
! 			 * subxact aborts.
  			 */
! 			update_xact = InvalidTransactionId;
! 			if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
! 				update_xact = HeapTupleGetUpdateXid(oldtup.t_data);
  
  			/*
! 			 * There was no UPDATE in the MultiXact; or it aborted. No
! 			 * TransactionIdIsInProgress() call needed here, since we called
! 			 * MultiXactIdWait() above.
! 			 */
! 			if (!TransactionIdIsValid(update_xact) ||
! 				TransactionIdDidAbort(update_xact))
! 				can_continue = true;
! 
! 			locker_remains = remain != 0;
! 		}
! 		else
! 		{
! 			/*
! 			 * If it's just a key-share locker, and we're not changing the key
! 			 * columns, we don't need to wait for it to end; but we need to
! 			 * preserve it as locker.
  			 */
! 			if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) && key_intact)
  			{
  				LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  				/*
! 				 * recheck the locker; if someone else changed the tuple while
! 				 * we weren't looking, start over.
  				 */
  				if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
! 					!TransactionIdEquals(
! 									HeapTupleHeaderGetRawXmax(oldtup.t_data),
! 										 xwait))
  					goto l2;
  
! 				can_continue = true;
! 				locker_remains = true;
  			}
  			else
  			{
- 				/* wait for regular transaction to end */
- 				XactLockTableWait(xwait, relation, &oldtup.t_data->t_ctid,
- 								  XLTW_Update);
- 				LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
- 
  				/*
! 				 * xwait is done, but if xwait had just locked the tuple then
! 				 * some other xact could update this tuple before we get to
! 				 * this point. Check for xmax change, and start over if so.
  				 */
! 				if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
! 					!TransactionIdEquals(
! 									HeapTupleHeaderGetRawXmax(oldtup.t_data),
! 										 xwait))
! 					goto l2;
  
- 				/* Otherwise check if it committed or aborted */
- 				UpdateXmaxHintBits(oldtup.t_data, buffer, xwait);
- 				if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)
  					can_continue = true;
  			}
  		}
  
--- 3279,3444 ----
  		 * heap_update directly.
  		 */
  
  		/*
! 		 * Somebody is holding a lock on the tuple, or updating it; we now
! 		 * need to sleep on that transaction before we can proceed.  However,
! 		 * if the only locker is our own transaction (or any subtransaction of
! 		 * the current top transaction), then it's not necessary to do so.
! 		 * Note we only check for this case when the locker is a single xid,
! 		 * because MultiXactIdWait is prepared to deal with it.
  		 *
! 		 * This must be done before acquiring our tuple lock, to avoid
! 		 * deadlocks with other transactions that are already waiting on the
! 		 * lock we hold.
  		 */
! 		if (!(oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) &&
! 			TransactionIdIsCurrentTransactionId(
! 								   HeapTupleHeaderGetRawXmax(oldtup.t_data)))
  		{
! 			Assert(HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask));
  
! 			can_continue = true;
! 			locker_remains = true;
! 		}
! 		else
  		{
! 			TransactionId xwait;
! 			uint16		infomask;
  
! 			/* must copy state data before unlocking buffer */
! 			xwait = HeapTupleHeaderGetRawXmax(oldtup.t_data);
! 			infomask = oldtup.t_data->t_infomask;
  
! 			LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
  
  			/*
! 			 * Acquire tuple lock to establish our priority for the tuple (see
! 			 * heap_lock_tuple).  LockTuple will release us when we are
! 			 * next-in-line for the tuple.
  			 *
! 			 * If we are forced to "start over" below, we keep the tuple lock;
! 			 * this arranges that we stay at the head of the line while
! 			 * rechecking tuple state.
  			 */
! 			if (!have_tuple_lock)
! 			{
! 				LockTupleTuplock(relation, &(oldtup.t_self), *lockmode);
! 				have_tuple_lock = true;
! 			}
  
  			/*
! 			 * Now we have to do something about the existing locker.  If it's
! 			 * a multi, sleep on it; we might be awakened before it is
! 			 * completely gone (or even not sleep at all in some cases); we
! 			 * need to preserve it as locker, unless it is gone completely.
! 			 *
! 			 * If it's not a multi, we need to check for sleeping conditions
! 			 * before actually going to sleep.  If the update doesn't conflict
! 			 * with the locks, we just continue without sleeping (but making
! 			 * sure it is preserved).
  			 */
! 			if (infomask & HEAP_XMAX_IS_MULTI)
  			{
+ 				TransactionId update_xact;
+ 				int			remain;
+ 
+ 				/* wait for multixact */
+ 				MultiXactIdWait((MultiXactId) xwait, mxact_status, infomask,
+ 								relation, &oldtup.t_data->t_ctid, XLTW_Update,
+ 								&remain);
  				LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
  
  				/*
! 				 * If xwait had just locked the tuple then some other xact
! 				 * could update this tuple before we get to this point.  Check
! 				 * for xmax change, and start over if so.
  				 */
  				if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
! 					!TransactionIdEquals(xwait,
! 								   HeapTupleHeaderGetRawXmax(oldtup.t_data)))
  					goto l2;
  
! 				/*
! 				 * Note that the multixact may not be done by now.  It could
! 				 * have surviving members; our own xact or other subxacts of
! 				 * this backend, and also any other concurrent transaction
! 				 * that locked the tuple with KeyShare if we only got
! 				 * TupleLockUpdate.  If this is the case, we have to be
! 				 * careful to mark the updated tuple with the surviving
! 				 * members in Xmax.
! 				 *
! 				 * Note that there could have been another update in the
! 				 * MultiXact. In that case, we need to check whether it
! 				 * committed or aborted. If it aborted we are safe to update
! 				 * it again; otherwise there is an update conflict, and we
! 				 * have to return HeapTupleUpdated below.
! 				 *
! 				 * In the LockTupleExclusive case, we still need to preserve
! 				 * the surviving members: those would include the tuple locks
! 				 * we had before this one, which are important to keep in case
! 				 * this subxact aborts.
! 				 */
! 				update_xact = InvalidTransactionId;
! 				if (!HEAP_XMAX_IS_LOCKED_ONLY(oldtup.t_data->t_infomask))
! 					update_xact = HeapTupleGetUpdateXid(oldtup.t_data);
! 
! 				/*
! 				 * There was no UPDATE in the MultiXact; or it aborted. No
! 				 * TransactionIdIsInProgress() call needed here, since we
! 				 * called MultiXactIdWait() above.
! 				 */
! 				if (!TransactionIdIsValid(update_xact) ||
! 					TransactionIdDidAbort(update_xact))
! 					can_continue = true;
! 
! 				locker_remains = remain != 0;
  			}
  			else
  			{
  				/*
! 				 * If it's just a key-share locker, and we're not changing the
! 				 * key columns, we don't need to wait for it to end; but we
! 				 * need to preserve it as locker.
  				 */
! 				if (HEAP_XMAX_IS_KEYSHR_LOCKED(infomask) && key_intact)
! 				{
! 					LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
! 
! 					/*
! 					 * recheck the locker; if someone else changed the tuple
! 					 * while we weren't looking, start over.
! 					 */
! 					if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
! 						!TransactionIdEquals(xwait,
! 								   HeapTupleHeaderGetRawXmax(oldtup.t_data)))
! 						goto l2;
  
  					can_continue = true;
+ 					locker_remains = true;
+ 				}
+ 				else
+ 				{
+ 					/* wait for regular transaction to end */
+ 					XactLockTableWait(xwait, relation, &oldtup.t_data->t_ctid,
+ 									  XLTW_Update);
+ 					LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
+ 
+ 					/*
+ 					 * xwait is done, but if xwait had just locked the tuple
+ 					 * then some other xact could update this tuple before we
+ 					 * get to this point. Check for xmax change, and start
+ 					 * over if so.
+ 					 */
+ 					if (xmax_infomask_changed(oldtup.t_data->t_infomask, infomask) ||
+ 						!TransactionIdEquals(xwait,
+ 								   HeapTupleHeaderGetRawXmax(oldtup.t_data)))
+ 						goto l2;
+ 
+ 					/* Otherwise check if it committed or aborted */
+ 					UpdateXmaxHintBits(oldtup.t_data, buffer, xwait);
+ 					if (oldtup.t_data->t_infomask & HEAP_XMAX_INVALID)
+ 						can_continue = true;
+ 				}
  			}
  		}
  
***************
*** 4167,4213 **** l3:
  
  		/*
  		 * If any subtransaction of the current top transaction already holds
! 		 * a lock as strong or stronger than what we're requesting, we
  		 * effectively hold the desired lock already.  We *must* succeed
  		 * without trying to take the tuple lock, else we will deadlock
  		 * against anyone wanting to acquire a stronger lock.
  		 */
! 		if (infomask & HEAP_XMAX_IS_MULTI)
  		{
! 			int			i;
! 			int			nmembers;
! 			MultiXactMember *members;
  
! 			/*
! 			 * We don't need to allow old multixacts here; if that had been
! 			 * the case, HeapTupleSatisfiesUpdate would have returned
! 			 * MayBeUpdated and we wouldn't be here.
! 			 */
! 			nmembers =
! 				GetMultiXactIdMembers(xwait, &members, false,
! 									  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
  
! 			for (i = 0; i < nmembers; i++)
! 			{
! 				if (TransactionIdIsCurrentTransactionId(members[i].xid))
  				{
! 					LockTupleMode membermode;
  
! 					membermode = TUPLOCK_from_mxstatus(members[i].status);
  
! 					if (membermode >= mode)
! 					{
! 						if (have_tuple_lock)
! 							UnlockTupleTuplock(relation, tid, mode);
  
! 						pfree(members);
  						return HeapTupleMayBeUpdated;
! 					}
  				}
  			}
- 
- 			if (members)
- 				pfree(members);
  		}
  
  		/*
--- 4215,4289 ----
  
  		/*
  		 * If any subtransaction of the current top transaction already holds
! 		 * a lock as strong as or stronger than what we're requesting, we
  		 * effectively hold the desired lock already.  We *must* succeed
  		 * without trying to take the tuple lock, else we will deadlock
  		 * against anyone wanting to acquire a stronger lock.
+ 		 *
+ 		 * Note we only do this the first time we loop on the HTSU result;
+ 		 * there is no point in testing in subsequent passes, because
+ 		 * evidently our own transaction cannot have acquired a new lock after
+ 		 * the first time we checked.
  		 */
! 		if (!have_tuple_lock)
  		{
! 			if (infomask & HEAP_XMAX_IS_MULTI)
! 			{
! 				int			i;
! 				int			nmembers;
! 				MultiXactMember *members;
  
! 				/*
! 				 * We don't need to allow old multixacts here; if that had
! 				 * been the case, HeapTupleSatisfiesUpdate would have returned
! 				 * MayBeUpdated and we wouldn't be here.
! 				 */
! 				nmembers =
! 					GetMultiXactIdMembers(xwait, &members, false,
! 										  HEAP_XMAX_IS_LOCKED_ONLY(infomask));
  
! 				for (i = 0; i < nmembers; i++)
  				{
! 					if (TransactionIdIsCurrentTransactionId(members[i].xid))
! 					{
! 						LockTupleMode membermode;
  
! 						membermode = TUPLOCK_from_mxstatus(members[i].status);
  
! 						if (membermode >= mode)
! 						{
! 							pfree(members);
! 							return HeapTupleMayBeUpdated;
! 						}
! 					}
! 				}
  
! 				if (members)
! 					pfree(members);
! 			}
! 			else if (TransactionIdIsCurrentTransactionId(xwait))
! 			{
! 				switch (mode)
! 				{
! 					case LockTupleKeyShare:
  						return HeapTupleMayBeUpdated;
! 						break;
! 					case LockTupleShare:
! 						if (HEAP_XMAX_IS_SHR_LOCKED(infomask) ||
! 							HEAP_XMAX_IS_EXCL_LOCKED(infomask))
! 							return HeapTupleMayBeUpdated;
! 						break;
! 					case LockTupleNoKeyExclusive:
! 						if (HEAP_XMAX_IS_EXCL_LOCKED(infomask))
! 							return HeapTupleMayBeUpdated;
! 						break;
! 					case LockTupleExclusive:
! 						if (HEAP_XMAX_IS_EXCL_LOCKED(infomask) &&
! 							infomask2 & HEAP_KEYS_UPDATED)
! 							return HeapTupleMayBeUpdated;
! 						break;
  				}
  			}
  		}
  
  		/*
***************
*** 4389,4396 **** l3:
  						 */
  						LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  						if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
! 							!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
! 												 xwait))
  						{
  							pfree(members);
  							goto l3;
--- 4465,4472 ----
  						 */
  						LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  						if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
! 							!TransactionIdEquals(xwait,
! 								   HeapTupleHeaderGetRawXmax(tuple->t_data)))
  						{
  							pfree(members);
  							goto l3;
***************
*** 4416,4421 **** l3:
--- 4492,4518 ----
  				require_sleep = false;
  			}
  		}
+ 		else if (!(infomask & HEAP_XMAX_IS_MULTI) &&
+ 				 TransactionIdIsCurrentTransactionId(xwait))
+ 		{
+ 			/*
+ 			 * If the only locker present is ourselves, but we now want a
+ 			 * stronger lock, then we need not sleep (indeed we mustn't,
+ 			 * because XactLockTableWait would error out).  Note that the
+ 			 * cases where we already hold a lock as strong or stronger than
+ 			 * what we already hold were already covered above.  Also note we
+ 			 * don't need to concern ourselves with the multixact case here,
+ 			 * because MultiXactIdWait would have that situation on hand.
+ 			 *
+ 			 * If the xmax changed in the meantime, start over.
+ 			 */
+ 			LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
+ 			if (xmax_infomask_changed(tuple->t_data->t_infomask, infomask) ||
+ 				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
+ 									 xwait))
+ 				goto l3;
+ 			require_sleep = false;
+ 		}
  
  		/*
  		 * By here, we either have already acquired the buffer exclusive lock,
***************
*** 4584,4620 **** failed:
  	old_infomask = tuple->t_data->t_infomask;
  
  	/*
- 	 * We might already hold the desired lock (or stronger), possibly under a
- 	 * different subtransaction of the current top transaction.  If so, there
- 	 * is no need to change state or issue a WAL record.  We already handled
- 	 * the case where this is true for xmax being a MultiXactId, so now check
- 	 * for cases where it is a plain TransactionId.
- 	 *
- 	 * Note in particular that this covers the case where we already hold
- 	 * exclusive lock on the tuple and the caller only wants key share or
- 	 * share lock. It would certainly not do to give up the exclusive lock.
- 	 */
- 	if (!(old_infomask & (HEAP_XMAX_INVALID |
- 						  HEAP_XMAX_COMMITTED |
- 						  HEAP_XMAX_IS_MULTI)) &&
- 		(mode == LockTupleKeyShare ?
- 		 (HEAP_XMAX_IS_KEYSHR_LOCKED(old_infomask) ||
- 		  HEAP_XMAX_IS_SHR_LOCKED(old_infomask) ||
- 		  HEAP_XMAX_IS_EXCL_LOCKED(old_infomask)) :
- 		 mode == LockTupleShare ?
- 		 (HEAP_XMAX_IS_SHR_LOCKED(old_infomask) ||
- 		  HEAP_XMAX_IS_EXCL_LOCKED(old_infomask)) :
- 		 (HEAP_XMAX_IS_EXCL_LOCKED(old_infomask))) &&
- 		TransactionIdIsCurrentTransactionId(xmax))
- 	{
- 		LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
- 		/* Probably can't hold tuple lock here, but may as well check */
- 		if (have_tuple_lock)
- 			UnlockTupleTuplock(relation, tid, mode);
- 		return HeapTupleMayBeUpdated;
- 	}
- 
- 	/*
  	 * If this is the first possibly-multixact-able operation in the current
  	 * transaction, set my per-backend OldestMemberMXactId setting. We can be
  	 * certain that the transaction will never become a member of any older
--- 4681,4686 ----
***************
*** 4842,4848 **** l5:
  		if (!MultiXactIdIsRunning(xmax, HEAP_XMAX_IS_LOCKED_ONLY(old_infomask)))
  		{
  			if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) ||
! 				TransactionIdDidAbort(MultiXactIdGetUpdateXid(xmax,
  															  old_infomask)))
  			{
  				/*
--- 4908,4914 ----
  		if (!MultiXactIdIsRunning(xmax, HEAP_XMAX_IS_LOCKED_ONLY(old_infomask)))
  		{
  			if (HEAP_XMAX_IS_LOCKED_ONLY(old_infomask) ||
! 				!TransactionIdDidCommit(MultiXactIdGetUpdateXid(xmax,
  															  old_infomask)))
  			{
  				/*
*** a/src/backend/access/transam/multixact.c
--- b/src/backend/access/transam/multixact.c
***************
*** 531,537 **** MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
  	 */
  	nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
  
! 	if (nmembers < 0)
  	{
  		debug_elog2(DEBUG2, "IsRunning: no members");
  		return false;
--- 531,537 ----
  	 */
  	nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
  
! 	if (nmembers <= 0)
  	{
  		debug_elog2(DEBUG2, "IsRunning: no members");
  		return false;
***************
*** 1342,1380 **** retry:
  }
  
  /*
-  * MultiXactHasRunningRemoteMembers
-  *		Does the given multixact have still-live members from
-  *		transactions other than our own?
-  */
- bool
- MultiXactHasRunningRemoteMembers(MultiXactId multi)
- {
- 	MultiXactMember *members;
- 	int			nmembers;
- 	int			i;
- 
- 	nmembers = GetMultiXactIdMembers(multi, &members, true, false);
- 	if (nmembers <= 0)
- 		return false;
- 
- 	for (i = 0; i < nmembers; i++)
- 	{
- 		/* not interested in our own members */
- 		if (TransactionIdIsCurrentTransactionId(members[i].xid))
- 			continue;
- 
- 		if (TransactionIdIsInProgress(members[i].xid))
- 		{
- 			pfree(members);
- 			return true;
- 		}
- 	}
- 
- 	pfree(members);
- 	return false;
- }
- 
- /*
   * mxactMemberComparator
   *		qsort comparison function for MultiXactMember
   *
--- 1342,1347 ----
*** a/src/backend/utils/time/tqual.c
--- b/src/backend/utils/time/tqual.c
***************
*** 513,532 **** HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
  
  				if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
  				{
! 					if (MultiXactHasRunningRemoteMembers(xmax))
  						return HeapTupleBeingUpdated;
  					else
  						return HeapTupleMayBeUpdated;
  				}
  
! 				/* if locker is gone, all's well */
  				if (!TransactionIdIsInProgress(xmax))
  					return HeapTupleMayBeUpdated;
! 
! 				if (!TransactionIdIsCurrentTransactionId(xmax))
! 					return HeapTupleBeingUpdated;
! 				else
! 					return HeapTupleMayBeUpdated;
  			}
  
  			if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
--- 513,532 ----
  
  				if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
  				{
! 					if (MultiXactIdIsRunning(xmax, true))
  						return HeapTupleBeingUpdated;
  					else
  						return HeapTupleMayBeUpdated;
  				}
  
! 				/*
! 				 * If the locker is gone, then there is nothing of interest
! 				 * left in this Xmax; otherwise, report the tuple as
! 				 * locked/updated.
! 				 */
  				if (!TransactionIdIsInProgress(xmax))
  					return HeapTupleMayBeUpdated;
! 				return HeapTupleBeingUpdated;
  			}
  
  			if (tuple->t_infomask & HEAP_XMAX_IS_MULTI)
***************
*** 538,547 **** HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
  				/* not LOCKED_ONLY, so it has to have an xmax */
  				Assert(TransactionIdIsValid(xmax));
  
! 				/* updating subtransaction must have aborted */
  				if (!TransactionIdIsCurrentTransactionId(xmax))
  				{
! 					if (MultiXactHasRunningRemoteMembers(HeapTupleHeaderGetRawXmax(tuple)))
  						return HeapTupleBeingUpdated;
  					return HeapTupleMayBeUpdated;
  				}
--- 538,548 ----
  				/* not LOCKED_ONLY, so it has to have an xmax */
  				Assert(TransactionIdIsValid(xmax));
  
! 				/* deleting subtransaction must have aborted */
  				if (!TransactionIdIsCurrentTransactionId(xmax))
  				{
! 					if (MultiXactIdIsRunning(HeapTupleHeaderGetRawXmax(tuple),
! 																	   false))
  						return HeapTupleBeingUpdated;
  					return HeapTupleMayBeUpdated;
  				}
***************
*** 663,669 **** HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid,
  	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
  	{
  		if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
! 			return HeapTupleMayBeUpdated;
  		if (HeapTupleHeaderGetCmax(tuple) >= curcid)
  			return HeapTupleSelfUpdated;		/* updated after scan started */
  		else
--- 664,670 ----
  	if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetRawXmax(tuple)))
  	{
  		if (HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
! 			return HeapTupleBeingUpdated;
  		if (HeapTupleHeaderGetCmax(tuple) >= curcid)
  			return HeapTupleSelfUpdated;		/* updated after scan started */
  		else
*** a/src/include/access/multixact.h
--- b/src/include/access/multixact.h
***************
*** 95,101 **** extern bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly);
  extern void MultiXactIdSetOldestMember(void);
  extern int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **xids,
  					  bool allow_old, bool isLockOnly);
- extern bool MultiXactHasRunningRemoteMembers(MultiXactId multi);
  extern bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2);
  extern bool MultiXactIdPrecedesOrEquals(MultiXactId multi1,
  							MultiXactId multi2);
--- 95,100 ----
