| From: | Alvaro Herrera <alvherre(at)alvh(dot)no-ip(dot)org> | 
|---|---|
| To: | Peter Geoghegan <pg(at)bowt(dot)ie> | 
| Cc: | pgsql-committers <pgsql-committers(at)postgresql(dot)org> | 
| Subject: | Re: pgsql: Fix traversal of half-frozen update chains | 
| Date: | 2017-10-17 10:40:59 | 
| Message-ID: | 20171017104059.sq76kgd42ld55npp@alvherre.pgsql | 
| Views: | Whole Thread | Raw Message | Download mbox | Resend email | 
| Thread: | |
| Lists: | pgsql-committers pgsql-hackers | 
Peter Geoghegan wrote:
> Wouldn't this last "if" test, to cover the pg_upgrade case, be better
> targeted by comparing *raw* xmin to FrozenTransactionId? You're using
> the potentially distinct xmin value returned by
> HeapTupleHeaderGetXmin() for the test here. I think we should be
> directly targeting tuples frozen on or before 9.4 (prior to
> pg_upgrade) instead.
I also realized we can stop checking (i.e. don't compare xmin to
frozenxid) if the XMIN_FROZEN bits are set -- because in that case the
tuple cannot possibly come from 9.3 frozen.  So I think this should do
it.
/*
 * 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	rawxmin = HeapTupleHeaderGetRawXmin(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;
	/*
	 * If the HEAP_XMIN_FROZEN flag is set, then we know it can only be a match
	 * if the Xmin before the freezing is identical to the Xmax -- we can skip
	 * the fuzzy pg_upgraded check below.
	 */
	if (HeapTupleHeaderXminFrozen(htup))
	{
		if (TransactionIdEquals(rawxmin, xmax))
			return true;
		else
			return false;
	}
	/*
	 * 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.
	 *
	 * We no longer freeze tuples this way, but we must keep this in order to
	 * interpret pre-pg_upgrade pages correctly.
	 */
	if (TransactionIdEquals(rawxmin, FrozenTransactionId) &&
		TransactionIdIsValid(xmax))
		return true;
	return false;
}
-- 
Álvaro Herrera                https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Tom Lane | 2017-10-17 16:15:25 | pgsql: Fix misparsing of non-newline-terminated pg_hba.conf files. | 
| Previous Message | Alvaro Herrera | 2017-10-17 10:02:00 | Re: [COMMITTERS] pgsql: Fix traversal of half-frozen update chains | 
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Alvaro Herrera | 2017-10-17 10:59:16 | Re: SIGSEGV in BRIN autosummarize | 
| Previous Message | Alvaro Herrera | 2017-10-17 10:02:00 | Re: [COMMITTERS] pgsql: Fix traversal of half-frozen update chains |