Alvaro Herrera wrote:

> I'm thinking about the comparison of full infomask as you propose
> instead of just the bits that we actually care about.   I think the only
> thing that could cause a spurious failure (causing an extra execution of
> the HeapTupleSatisfiesUpdate call and the stuff below) is somebody
> setting HEAP_XMIN_COMMITTED concurrently; but that seems infrequent
> enough that it should pretty harmless.  However, should we worry about
> possible future infomask bit changes that could negatively affect this
> behavior?

Here's a complete patch illustrating what I mean.  This is slightly more
expensive than straight infomask comparison in terms of machine
instructions, but that seems okay to me.

-- 
Álvaro Herrera                http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
*** a/src/backend/access/heap/heapam.c
--- b/src/backend/access/heap/heapam.c
***************
*** 2586,2591 **** compute_infobits(uint16 infomask, uint16 infomask2)
--- 2586,2612 ----
  }
  
  /*
+  * Given two versions of the same t_infomask for a tuple, compare them and
+  * return whether the relevant status for a tuple Xmax has changed.  This is
+  * used after a buffer lock has been released and reacquired: we want to ensure
+  * that the tuple state continues to be the same it was when we previously
+  * examined it.
+  *
+  * Note the Xmax field itself must be compared separately.
+  */
+ static inline bool
+ xmax_infomsk_changed(uint16 infomask1, uint16 infomask2)
+ {
+ 	const uint16	interesting =
+ 		HEAP_XMAX_IS_MULTI | HEAP_XMAX_LOCK_ONLY | HEAP_LOCK_MASK;
+ 
+ 	if ((infomask1 & interesting) != (infomask2 & interesting))
+ 		return true;
+ 
+ 	return false;
+ }
+ 
+ /*
   *	heap_delete - delete a tuple
   *
   * NB: do not call this directly unless you are prepared to deal with
***************
*** 2722,2728 **** l1:
  			 * update this tuple before we get to this point.  Check for xmax
  			 * change, and start over if so.
  			 */
! 			if (!(tp.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
  									 xwait))
  				goto l1;
--- 2743,2749 ----
  			 * update this tuple before we get to this point.  Check for xmax
  			 * change, and start over if so.
  			 */
! 			if (xmax_infomsk_changed(tp.t_data->t_infomask, infomask) ||
  				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
  									 xwait))
  				goto l1;
***************
*** 2748,2754 **** l1:
  			 * other xact could update this tuple before we get to this point.
  			 * Check for xmax change, and start over if so.
  			 */
! 			if ((tp.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
  									 xwait))
  				goto l1;
--- 2769,2775 ----
  			 * other xact could update this tuple before we get to this point.
  			 * Check for xmax change, and start over if so.
  			 */
! 			if (xmax_infomsk_changed(tp.t_data->t_infomask, infomask) ||
  				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tp.t_data),
  									 xwait))
  				goto l1;
***************
*** 3275,3281 **** l2:
  			 * update this tuple before we get to this point.  Check for xmax
  			 * change, and start over if so.
  			 */
! 			if (!(oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
  									 xwait))
  				goto l2;
--- 3296,3302 ----
  			 * update this tuple before we get to this point.  Check for xmax
  			 * change, and start over if so.
  			 */
! 			if (xmax_infomsk_changed(oldtup.t_data->t_infomask, infomask) ||
  				!TransactionIdEquals(HeapTupleHeaderGetRawXmax(oldtup.t_data),
  									 xwait))
  				goto l2;
***************
*** 3324,3335 **** l2:
  			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 ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(oldtup.t_data),
  										 xwait))
--- 3345,3355 ----
  			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_infomsk_changed(oldtup.t_data->t_infomask, infomask) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(oldtup.t_data),
  										 xwait))
***************
*** 3350,3356 **** l2:
  				 * some other xact could update this tuple before we get to
  				 * this point. Check for xmax change, and start over if so.
  				 */
! 				if ((oldtup.t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(oldtup.t_data),
  										 xwait))
--- 3370,3376 ----
  				 * some other xact could update this tuple before we get to
  				 * this point. Check for xmax change, and start over if so.
  				 */
! 				if (xmax_infomsk_changed(oldtup.t_data->t_infomask, infomask) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(oldtup.t_data),
  										 xwait))
***************
*** 4354,4360 **** l3:
  						 * over.
  						 */
  						LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
! 						if (!(tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  							!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
  												 xwait))
  						{
--- 4374,4380 ----
  						 * over.
  						 */
  						LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
! 						if (xmax_infomsk_changed(tuple->t_data->t_infomask, infomask) ||
  							!TransactionIdEquals(HeapTupleHeaderGetRawXmax(tuple->t_data),
  												 xwait))
  						{
***************
*** 4373,4379 **** l3:
  				LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  
  				/* if the xmax changed in the meantime, start over */
! 				if ((tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(tuple->t_data),
  										 xwait))
--- 4393,4399 ----
  				LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
  
  				/* if the xmax changed in the meantime, start over */
! 				if (xmax_infomsk_changed(tuple->t_data->t_infomask, infomask) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(tuple->t_data),
  										 xwait))
***************
*** 4441,4447 **** l3:
  				 * could update this tuple before we get to this point. Check
  				 * for xmax change, and start over if so.
  				 */
! 				if (!(tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(tuple->t_data),
  										 xwait))
--- 4461,4467 ----
  				 * could update this tuple before we get to this point. Check
  				 * for xmax change, and start over if so.
  				 */
! 				if (xmax_infomsk_changed(tuple->t_data->t_infomask, infomask) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(tuple->t_data),
  										 xwait))
***************
*** 4497,4503 **** l3:
  				 * some other xact could update this tuple before we get to
  				 * this point.	Check for xmax change, and start over if so.
  				 */
! 				if ((tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(tuple->t_data),
  										 xwait))
--- 4517,4523 ----
  				 * some other xact could update this tuple before we get to
  				 * this point.	Check for xmax change, and start over if so.
  				 */
! 				if (xmax_infomsk_changed(tuple->t_data->t_infomask, infomask) ||
  					!TransactionIdEquals(
  									HeapTupleHeaderGetRawXmax(tuple->t_data),
  										 xwait))
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to