Re: [COMMITTERS] pgsql: Fix freezing of a dead HOT-updated tuple

Alvaro Herrera <alvherre@alvh.no-ip.org>

From: Alvaro Herrera <alvherre@alvh.no-ip.org>
To: Michael Paquier <michael.paquier@gmail.com>
Cc: Peter Geoghegan <pg@bowt.ie>, "Wong, Yi Wen" <yiwong@amazon.com>, "Wood, Dan" <hexpert@amazon.com>, PostgreSQL Hackers <pgsql-hackers@postgresql.org>
Date: 2017-10-06T10:57:18Z
Lists: pgsql-hackers
Michael Paquier wrote:
> On Fri, Oct 6, 2017 at 1:24 AM, Alvaro Herrera <alvherre@alvh.no-ip.org> wrote:

> +   /*
> +    * If the xmax of the old tuple is identical to the xmin of the new one,
> +    * it's a match.
> +    */
> +   if (xmax == xmin)
> +       return true;
> I would use TransactionIdEquals() here, to remember once you switch
> that to a macro.

I've had second thoughts about the macro thing -- for now I'm keeping it
a function, actually.

> +/*
> + * Given a tuple, verify whether the given Xmax matches the tuple's Xmin,
> + * taking into account that the Xmin might have been frozen.
> + */
> [...]
> +   /*
> +    * We actually don't know if there's a match, but if the previous tuple
> +    * was frozen, we cannot really rely on a perfect match.
> +    */

I don't know what you had in mind here, but I tweaked the 9.3 version so
that it now looks like this:

/*
 * HeapTupleUpdateXmaxMatchesXmin - verify update chain xmax/xmin lineage
 *
 * Given the new version of a tuple after some update, verify whether the
 * given Xmax (corresponding to the previous version) matches the tuple's
 * Xmin, taking into account that the Xmin might have been frozen after the
 * update.
 */
bool
HeapTupleUpdateXmaxMatchesXmin(TransactionId xmax, HeapTupleHeader htup)
{
	TransactionId	xmin = HeapTupleHeaderGetXmin(htup);

	/*
	 * If the xmax of the old tuple is identical to the xmin of the new one,
	 * it's a match.
	 */
	if (TransactionIdEquals(xmax, xmin))
		return true;

	/*
	 * When a tuple is frozen, the original Xmin is lost, but we know it's a
	 * committed transaction.  So unless the Xmax is InvalidXid, we don't
	 * know for certain that there is a match, but there may be one; and we
	 * must return true so that a HOT chain that is half-frozen can be walked
	 * correctly.
	 */
	if (TransactionIdEquals(xmin, FrozenTransactionId) &&
		TransactionIdIsValid(xmax))
		return true;

	return false;
}


-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services


Commits

  1. Backport addition of rs_old_rel to rewriteheap's state.

  2. Perform a lot more sanity checks when freezing tuples.

  3. Revert bogus fixes of HOT-freezing bug

  4. Fix traversal of half-frozen update chains

  5. Fix freezing of a dead HOT-updated tuple

  6. During index build, check and elog (not just Assert) for broken HOT chain.

  7. Fix WAL replay of locking an updated tuple

  8. Change the way we mark tuples as frozen.