diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2018-05-04 15:24:44 -0300 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2018-05-04 18:23:58 -0300 |
commit | e1d634758e487fdec117ab4e1679240e48f2092c (patch) | |
tree | 25d8484ad61910f1db7dd91fb1383f6ffa67f2ab | |
parent | 56a45646d49b6c033adc42469f8e4361f82440a2 (diff) | |
download | postgresql-e1d634758e487fdec117ab4e1679240e48f2092c.tar.gz postgresql-e1d634758e487fdec117ab4e1679240e48f2092c.zip |
Don't mark pages all-visible spuriously
Dan Wood diagnosed a long-standing problem that pages containing tuples
that are locked by multixacts containing live lockers may spuriously end
up as candidates for getting their all-visible flag set. This has the
long-term effect that multixacts remain unfrozen; this may previously
pass undetected, but since commit XYZ it would be reported as
"ERROR: found multixact 134100944 from before relminmxid 192042633"
because when a later vacuum tries to freeze the page it detects that a
multixact that should have gotten frozen, wasn't.
Dan proposed a (correct) patch that simply sets a variable to its
correct value, after a bogus initialization. But, per discussion, it
seems better coding to avoid the bogus initializations altogether, since
they could give rise to more bugs later. Therefore this fix rewrites
the logic a little bit to avoid depending on the bogus initializations.
This bug was part of a family introduced in 9.6 by commit a892234f830e;
later, commit 38e9f90a227d fixed most of them, but this one was
unnoticed.
Authors: Dan Wood, Pavan Deolasee, Álvaro Herrera
Reviewed-by: Masahiko Sawada, Pavan Deolasee, Álvaro Herrera
Discussion: https://postgr.es/m/84EBAC55-F06D-4FBE-A3F3-8BDA093CE3E3@amazon.com
-rw-r--r-- | src/backend/access/heap/heapam.c | 40 |
1 files changed, 25 insertions, 15 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index fee062924a9..3d6d378c8a1 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6650,9 +6650,10 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz, bool *totally_frozen_p) { bool changed = false; - bool freeze_xmax = false; + bool xmax_already_frozen = false; + bool xmin_frozen; + bool freeze_xmax; TransactionId xid; - bool totally_frozen = true; frz->frzflags = 0; frz->t_infomask2 = tuple->t_infomask2; @@ -6661,6 +6662,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, /* Process xmin */ xid = HeapTupleHeaderGetXmin(tuple); + xmin_frozen = ((xid == FrozenTransactionId) || + HeapTupleHeaderXminFrozen(tuple)); if (TransactionIdIsNormal(xid)) { if (TransactionIdPrecedes(xid, relfrozenxid)) @@ -6679,9 +6682,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, frz->t_infomask |= HEAP_XMIN_FROZEN; changed = true; + xmin_frozen = true; } - else - totally_frozen = false; } /* @@ -6704,9 +6706,9 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, relfrozenxid, relminmxid, cutoff_xid, cutoff_multi, &flags); - if (flags & FRM_INVALIDATE_XMAX) - freeze_xmax = true; - else if (flags & FRM_RETURN_IS_XID) + freeze_xmax = (flags & FRM_INVALIDATE_XMAX); + + if (flags & FRM_RETURN_IS_XID) { /* * NB -- some of these transformations are only valid because we @@ -6720,7 +6722,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, if (flags & FRM_MARK_COMMITTED) frz->t_infomask |= HEAP_XMAX_COMMITTED; changed = true; - totally_frozen = false; } else if (flags & FRM_RETURN_IS_MULTI) { @@ -6742,11 +6743,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, frz->xmax = newxmax; changed = true; - totally_frozen = false; - } - else - { - Assert(flags & FRM_NOOP); } } else if (TransactionIdIsNormal(xid)) @@ -6774,11 +6770,24 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, freeze_xmax = true; } else - totally_frozen = false; + freeze_xmax = false; } + else if ((tuple->t_infomask & HEAP_XMAX_INVALID) || + !TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple))) + { + freeze_xmax = false; + xmax_already_frozen = true; + } + else + ereport(ERROR, + (errcode(ERRCODE_DATA_CORRUPTED), + errmsg_internal("found xmax %u (infomask 0x%04x) not frozen, not multi, not normal", + xid, tuple->t_infomask))); if (freeze_xmax) { + Assert(!xmax_already_frozen); + frz->xmax = InvalidTransactionId; /* @@ -6831,7 +6840,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, } } - *totally_frozen_p = totally_frozen; + *totally_frozen_p = (xmin_frozen && + (freeze_xmax || xmax_already_frozen)); return changed; } |