Thread

  1. Re: problems with table corruption continued

    Vadim Mikheev <vmikheev@sectorbase.com> — 2001-12-18T19:49:24Z

    > > Looks like we have to add checks for the case
    > > TransactionIdIsCurrentTransactionId(tuple->t_cmin) when
    > > there is HEAP_MOVED_OFF or HEAP_MOVED_IN in t_infomask to
    > > all HeapTupleSatisfies* in tqual.c as we do in
    > > HeapTupleSatisfiesDirty - note comments about uniq btree-s there.
    > 
    > Sounds like a plan. Do you want to work on this, or shall I?
    
    Sorry, I'm not able to do this fast enough for current pre-release stage -:(
    
    Vadim
    
    
  2. Re: problems with table corruption continued

    Tom Lane <tgl@sss.pgh.pa.us> — 2001-12-18T19:53:53Z

    "Mikheev, Vadim" <vmikheev@SECTORBASE.COM> writes:
    >> Sounds like a plan. Do you want to work on this, or shall I?
    
    > Sorry, I'm not able to do this fast enough for current pre-release stage -:(
    
    Okay.  I'll work on a patch and send it to you for review, if you like.
    
    			regards, tom lane
    
    
  3. Re: problems with table corruption continued

    Tom Lane <tgl@sss.pgh.pa.us> — 2001-12-19T17:23:15Z

    Okay, I've applied the attached patch to tqual.c.  This brings all the
    variants of HeapTupleSatisfies up to speed: I have compared them
    carefully and they now all make equivalent series of tests on the tuple
    status (though they may interpret the results differently).
    
    I decided that Hiroshi had a good point about testing
    TransactionIdIsInProgress, so the code now does that before risking
    a change to t_infomask, even in the VACUUM cases.
    
    			regards, tom lane
    
    
    *** src/backend/utils/time/tqual.c.orig	Mon Oct 29 15:31:08 2001
    --- src/backend/utils/time/tqual.c	Wed Dec 19 12:09:32 2001
    ***************
    *** 31,37 ****
      /*
       * HeapTupleSatisfiesItself
       *		True iff heap tuple is valid for "itself."
    !  *		"{it}self" means valid as of everything that's happened
       *		in the current transaction, _including_ the current command.
       *
       * Note:
    --- 31,37 ----
      /*
       * HeapTupleSatisfiesItself
       *		True iff heap tuple is valid for "itself."
    !  *		"itself" means valid as of everything that's happened
       *		in the current transaction, _including_ the current command.
       *
       * Note:
    ***************
    *** 53,59 ****
      bool
      HeapTupleSatisfiesItself(HeapTupleHeader tuple)
      {
    - 
      	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
      	{
      		if (tuple->t_infomask & HEAP_XMIN_INVALID)
    --- 53,58 ----
    ***************
    *** 61,86 ****
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return false;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 				return false;
      			}
      		}
      		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
      		{
      			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
      				return true;
      			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
      				return true;
      			return false;
      		}
      		else if (!TransactionIdDidCommit(tuple->t_xmin))
    --- 60,102 ----
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      				return false;
    + 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    + 			{
    + 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    + 				{
    + 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    + 					return false;
    + 				}
    + 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      			{
    ! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    ! 					return false;
    ! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
    ! 				else
    ! 				{
    ! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 					return false;
    ! 				}
      			}
      		}
      		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
      		{
      			if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid */
      				return true;
    + 
    + 			Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
    + 
      			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
      				return true;
    + 
      			return false;
      		}
      		else if (!TransactionIdDidCommit(tuple->t_xmin))
    ***************
    *** 89,97 ****
      				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
      			return false;
      		}
    ! 		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
    ! 	/* the tuple was inserted validly */
      
      	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
      		return true;
    --- 105,115 ----
      				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
      			return false;
      		}
    ! 		else
    ! 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
    ! 
    ! 	/* by here, the inserting transaction has committed */
      
      	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
      		return true;
    ***************
    *** 117,123 ****
      		return true;
      	}
      
    ! 	/* by here, deleting transaction has committed */
      	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
      
      	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
    --- 135,141 ----
      		return true;
      	}
      
    ! 	/* xmax transaction committed */
      	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
      
      	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
    ***************
    *** 177,194 ****
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return false;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 				return false;
      			}
      		}
      		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
    --- 195,225 ----
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      				return false;
    + 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    + 			{
    + 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    + 				{
    + 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    + 					return false;
    + 				}
    + 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      			{
    ! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    ! 					return false;
    ! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
    ! 				else
    ! 				{
    ! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 					return false;
    ! 				}
      			}
      		}
      		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
    ***************
    *** 215,221 ****
      				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
      			return false;
      		}
    ! 		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
      
      	/* by here, the inserting transaction has committed */
    --- 246,253 ----
      				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
      			return false;
      		}
    ! 		else
    ! 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
      
      	/* by here, the inserting transaction has committed */
    ***************
    *** 257,348 ****
      }
      
      int
    ! HeapTupleSatisfiesUpdate(HeapTuple tuple)
      {
    ! 	HeapTupleHeader th = tuple->t_data;
      
      	if (AMI_OVERRIDE)
      		return HeapTupleMayBeUpdated;
      
    ! 	if (!(th->t_infomask & HEAP_XMIN_COMMITTED))
      	{
    ! 		if (th->t_infomask & HEAP_XMIN_INVALID) /* xid invalid or aborted */
      			return HeapTupleInvisible;
      
    ! 		if (th->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdDidCommit((TransactionId) th->t_cmin))
    ! 			{
    ! 				th->t_infomask |= HEAP_XMIN_INVALID;
      				return HeapTupleInvisible;
      			}
      		}
    ! 		else if (th->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdDidCommit((TransactionId) th->t_cmin))
      			{
    ! 				th->t_infomask |= HEAP_XMIN_INVALID;
    ! 				return HeapTupleInvisible;
      			}
      		}
    ! 		else if (TransactionIdIsCurrentTransactionId(th->t_xmin))
      		{
    ! 			if (CommandIdGEScanCommandId(th->t_cmin))
      				return HeapTupleInvisible;		/* inserted after scan
      												 * started */
      
    ! 			if (th->t_infomask & HEAP_XMAX_INVALID)		/* xid invalid */
      				return HeapTupleMayBeUpdated;
      
    ! 			Assert(TransactionIdIsCurrentTransactionId(th->t_xmax));
      
    ! 			if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
      				return HeapTupleMayBeUpdated;
      
    ! 			if (CommandIdGEScanCommandId(th->t_cmax))
      				return HeapTupleSelfUpdated;	/* updated after scan
      												 * started */
      			else
      				return HeapTupleInvisible;		/* updated before scan
      												 * started */
      		}
    ! 		else if (!TransactionIdDidCommit(th->t_xmin))
      		{
    ! 			if (TransactionIdDidAbort(th->t_xmin))
    ! 				th->t_infomask |= HEAP_XMIN_INVALID;	/* aborted */
      			return HeapTupleInvisible;
      		}
    ! 		th->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
      
      	/* by here, the inserting transaction has committed */
      
    ! 	if (th->t_infomask & HEAP_XMAX_INVALID)		/* xid invalid or aborted */
      		return HeapTupleMayBeUpdated;
      
    ! 	if (th->t_infomask & HEAP_XMAX_COMMITTED)
      	{
    ! 		if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
      			return HeapTupleMayBeUpdated;
      		return HeapTupleUpdated;	/* updated by other */
      	}
      
    ! 	if (TransactionIdIsCurrentTransactionId(th->t_xmax))
      	{
    ! 		if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
      			return HeapTupleMayBeUpdated;
    ! 		if (CommandIdGEScanCommandId(th->t_cmax))
      			return HeapTupleSelfUpdated;		/* updated after scan
      												 * started */
      		else
      			return HeapTupleInvisible;	/* updated before scan started */
      	}
      
    ! 	if (!TransactionIdDidCommit(th->t_xmax))
      	{
    ! 		if (TransactionIdDidAbort(th->t_xmax))
      		{
    ! 			th->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */
      			return HeapTupleMayBeUpdated;
      		}
      		/* running xact */
    --- 289,394 ----
      }
      
      int
    ! HeapTupleSatisfiesUpdate(HeapTuple htuple)
      {
    ! 	HeapTupleHeader tuple = htuple->t_data;
      
      	if (AMI_OVERRIDE)
      		return HeapTupleMayBeUpdated;
      
    ! 	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
      	{
    ! 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
      			return HeapTupleInvisible;
      
    ! 		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      				return HeapTupleInvisible;
    + 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    + 			{
    + 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    + 				{
    + 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    + 					return HeapTupleInvisible;
    + 				}
    + 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      			}
      		}
    ! 		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      			{
    ! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    ! 					return HeapTupleInvisible;
    ! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
    ! 				else
    ! 				{
    ! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 					return HeapTupleInvisible;
    ! 				}
      			}
      		}
    ! 		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
      		{
    ! 			if (CommandIdGEScanCommandId(tuple->t_cmin))
      				return HeapTupleInvisible;		/* inserted after scan
      												 * started */
      
    ! 			if (tuple->t_infomask & HEAP_XMAX_INVALID)		/* xid invalid */
      				return HeapTupleMayBeUpdated;
      
    ! 			Assert(TransactionIdIsCurrentTransactionId(tuple->t_xmax));
      
    ! 			if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
      				return HeapTupleMayBeUpdated;
      
    ! 			if (CommandIdGEScanCommandId(tuple->t_cmax))
      				return HeapTupleSelfUpdated;	/* updated after scan
      												 * started */
      			else
      				return HeapTupleInvisible;		/* updated before scan
      												 * started */
      		}
    ! 		else if (!TransactionIdDidCommit(tuple->t_xmin))
      		{
    ! 			if (TransactionIdDidAbort(tuple->t_xmin))
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;	/* aborted */
      			return HeapTupleInvisible;
      		}
    ! 		else
    ! 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
      
      	/* by here, the inserting transaction has committed */
      
    ! 	if (tuple->t_infomask & HEAP_XMAX_INVALID)		/* xid invalid or aborted */
      		return HeapTupleMayBeUpdated;
      
    ! 	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
      	{
    ! 		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
      			return HeapTupleMayBeUpdated;
      		return HeapTupleUpdated;	/* updated by other */
      	}
      
    ! 	if (TransactionIdIsCurrentTransactionId(tuple->t_xmax))
      	{
    ! 		if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
      			return HeapTupleMayBeUpdated;
    ! 		if (CommandIdGEScanCommandId(tuple->t_cmax))
      			return HeapTupleSelfUpdated;		/* updated after scan
      												 * started */
      		else
      			return HeapTupleInvisible;	/* updated before scan started */
      	}
      
    ! 	if (!TransactionIdDidCommit(tuple->t_xmax))
      	{
    ! 		if (TransactionIdDidAbort(tuple->t_xmax))
      		{
    ! 			tuple->t_infomask |= HEAP_XMAX_INVALID;		/* aborted */
      			return HeapTupleMayBeUpdated;
      		}
      		/* running xact */
    ***************
    *** 350,358 ****
      	}
      
      	/* xmax transaction committed */
    ! 	th->t_infomask |= HEAP_XMAX_COMMITTED;
      
    ! 	if (th->t_infomask & HEAP_MARKED_FOR_UPDATE)
      		return HeapTupleMayBeUpdated;
      
      	return HeapTupleUpdated;	/* updated by other */
    --- 396,404 ----
      	}
      
      	/* xmax transaction committed */
    ! 	tuple->t_infomask |= HEAP_XMAX_COMMITTED;
      
    ! 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
      		return HeapTupleMayBeUpdated;
      
      	return HeapTupleUpdated;	/* updated by other */
    ***************
    *** 374,396 ****
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    - 			/*
    - 			 * HeapTupleSatisfiesDirty is used by unique btree-s and so
    - 			 * may be used while vacuuming.
    - 			 */
      			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      				return false;
    ! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 				return false;
      			}
    - 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
      			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      			{
      				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      				else
    --- 420,443 ----
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
      			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      				return false;
    ! 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
      			{
    ! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 				{
    ! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 					return false;
    ! 				}
    ! 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
      			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      			{
    + 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    + 					return false;
      				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      				else
    ***************
    *** 416,425 ****
      		{
      			if (TransactionIdDidAbort(tuple->t_xmin))
      			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
      				return false;
      			}
      			SnapshotDirty->xmin = tuple->t_xmin;
      			return true;		/* in insertion by other */
      		}
      		else
    --- 463,473 ----
      		{
      			if (TransactionIdDidAbort(tuple->t_xmin))
      			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return false;
      			}
      			SnapshotDirty->xmin = tuple->t_xmin;
    + 			/* XXX shouldn't we fall through to look at xmax? */
      			return true;		/* in insertion by other */
      		}
      		else
    ***************
    *** 474,479 ****
    --- 522,528 ----
      	if (AMI_OVERRIDE)
      		return true;
      
    + 	/* XXX this is horribly ugly: */
      	if (ReferentialIntegritySnapshotOverride)
      		return HeapTupleSatisfiesNow(tuple);
      
    ***************
    *** 484,501 ****
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return false;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 				return false;
      			}
      		}
      		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
    --- 533,563 ----
      
      		if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    ! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      				return false;
    + 			if (!TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    + 			{
    + 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    + 				{
    + 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    + 					return false;
    + 				}
    + 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      			}
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
      			{
    ! 				if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    ! 					return false;
    ! 				if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 					tuple->t_infomask |= HEAP_XMIN_COMMITTED;
    ! 				else
    ! 				{
    ! 					tuple->t_infomask |= HEAP_XMIN_INVALID;
    ! 					return false;
    ! 				}
      			}
      		}
      		else if (TransactionIdIsCurrentTransactionId(tuple->t_xmin))
    ***************
    *** 519,528 ****
      		else if (!TransactionIdDidCommit(tuple->t_xmin))
      		{
      			if (TransactionIdDidAbort(tuple->t_xmin))
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID; /* aborted */
      			return false;
      		}
    ! 		tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
      
      	/*
    --- 581,591 ----
      		else if (!TransactionIdDidCommit(tuple->t_xmin))
      		{
      			if (TransactionIdDidAbort(tuple->t_xmin))
    ! 				tuple->t_infomask |= HEAP_XMIN_INVALID;
      			return false;
      		}
    ! 		else
    ! 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      	}
      
      	/*
    ***************
    *** 623,646 ****
      			return HEAPTUPLE_DEAD;
      		else if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
      			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
      				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return HEAPTUPLE_DEAD;
      			}
    - 			/* Assume we can only get here if previous VACUUM aborted, */
    - 			/* ie, it couldn't still be in progress */
      			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (!TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
    - 				/* Assume we can only get here if previous VACUUM aborted */
      				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return HEAPTUPLE_DEAD;
      			}
    - 			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      		}
      		else if (TransactionIdIsInProgress(tuple->t_xmin))
      			return HEAPTUPLE_INSERT_IN_PROGRESS;
    --- 686,715 ----
      			return HEAPTUPLE_DEAD;
      		else if (tuple->t_infomask & HEAP_MOVED_OFF)
      		{
    + 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
    + 				return HEAPTUPLE_DELETE_IN_PROGRESS;
    + 			if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    + 				return HEAPTUPLE_DELETE_IN_PROGRESS;
      			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
      			{
      				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return HEAPTUPLE_DEAD;
      			}
      			tuple->t_infomask |= HEAP_XMIN_COMMITTED;
      		}
      		else if (tuple->t_infomask & HEAP_MOVED_IN)
      		{
    ! 			if (TransactionIdIsCurrentTransactionId((TransactionId) tuple->t_cmin))
    ! 				return HEAPTUPLE_INSERT_IN_PROGRESS;
    ! 			if (TransactionIdIsInProgress((TransactionId) tuple->t_cmin))
    ! 				return HEAPTUPLE_INSERT_IN_PROGRESS;
    ! 			if (TransactionIdDidCommit((TransactionId) tuple->t_cmin))
    ! 				tuple->t_infomask |= HEAP_XMIN_COMMITTED;
    ! 			else
      			{
      				tuple->t_infomask |= HEAP_XMIN_INVALID;
      				return HEAPTUPLE_DEAD;
      			}
      		}
      		else if (TransactionIdIsInProgress(tuple->t_xmin))
      			return HEAPTUPLE_INSERT_IN_PROGRESS;
    ***************
    *** 671,676 ****
    --- 740,751 ----
      	if (tuple->t_infomask & HEAP_XMAX_INVALID)
      		return HEAPTUPLE_LIVE;
      
    + 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
    + 	{
    + 		/* "deleting" xact really only marked it for update */
    + 		return HEAPTUPLE_LIVE;
    + 	}
    + 
      	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
      	{
      		if (TransactionIdIsInProgress(tuple->t_xmax))
    ***************
    *** 698,709 ****
      	/*
      	 * Deleter committed, but check special cases.
      	 */
    - 
    - 	if (tuple->t_infomask & HEAP_MARKED_FOR_UPDATE)
    - 	{
    - 		/* "deleting" xact really only marked it for update */
    - 		return HEAPTUPLE_LIVE;
    - 	}
      
      	if (TransactionIdEquals(tuple->t_xmin, tuple->t_xmax))
      	{
    --- 773,778 ----