Skip to content

Commit e1d6347

Browse files
committed
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 a892234; later, commit 38e9f90 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
1 parent 56a4564 commit e1d6347

File tree

1 file changed

+25
-15
lines changed

1 file changed

+25
-15
lines changed

src/backend/access/heap/heapam.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6650,9 +6650,10 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
66506650
xl_heap_freeze_tuple *frz, bool *totally_frozen_p)
66516651
{
66526652
bool changed = false;
6653-
bool freeze_xmax = false;
6653+
bool xmax_already_frozen = false;
6654+
bool xmin_frozen;
6655+
bool freeze_xmax;
66546656
TransactionId xid;
6655-
bool totally_frozen = true;
66566657

66576658
frz->frzflags = 0;
66586659
frz->t_infomask2 = tuple->t_infomask2;
@@ -6661,6 +6662,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
66616662

66626663
/* Process xmin */
66636664
xid = HeapTupleHeaderGetXmin(tuple);
6665+
xmin_frozen = ((xid == FrozenTransactionId) ||
6666+
HeapTupleHeaderXminFrozen(tuple));
66646667
if (TransactionIdIsNormal(xid))
66656668
{
66666669
if (TransactionIdPrecedes(xid, relfrozenxid))
@@ -6679,9 +6682,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
66796682

66806683
frz->t_infomask |= HEAP_XMIN_FROZEN;
66816684
changed = true;
6685+
xmin_frozen = true;
66826686
}
6683-
else
6684-
totally_frozen = false;
66856687
}
66866688

66876689
/*
@@ -6704,9 +6706,9 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
67046706
relfrozenxid, relminmxid,
67056707
cutoff_xid, cutoff_multi, &flags);
67066708

6707-
if (flags & FRM_INVALIDATE_XMAX)
6708-
freeze_xmax = true;
6709-
else if (flags & FRM_RETURN_IS_XID)
6709+
freeze_xmax = (flags & FRM_INVALIDATE_XMAX);
6710+
6711+
if (flags & FRM_RETURN_IS_XID)
67106712
{
67116713
/*
67126714
* NB -- some of these transformations are only valid because we
@@ -6720,7 +6722,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
67206722
if (flags & FRM_MARK_COMMITTED)
67216723
frz->t_infomask |= HEAP_XMAX_COMMITTED;
67226724
changed = true;
6723-
totally_frozen = false;
67246725
}
67256726
else if (flags & FRM_RETURN_IS_MULTI)
67266727
{
@@ -6742,11 +6743,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
67426743
frz->xmax = newxmax;
67436744

67446745
changed = true;
6745-
totally_frozen = false;
6746-
}
6747-
else
6748-
{
6749-
Assert(flags & FRM_NOOP);
67506746
}
67516747
}
67526748
else if (TransactionIdIsNormal(xid))
@@ -6774,11 +6770,24 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
67746770
freeze_xmax = true;
67756771
}
67766772
else
6777-
totally_frozen = false;
6773+
freeze_xmax = false;
67786774
}
6775+
else if ((tuple->t_infomask & HEAP_XMAX_INVALID) ||
6776+
!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
6777+
{
6778+
freeze_xmax = false;
6779+
xmax_already_frozen = true;
6780+
}
6781+
else
6782+
ereport(ERROR,
6783+
(errcode(ERRCODE_DATA_CORRUPTED),
6784+
errmsg_internal("found xmax %u (infomask 0x%04x) not frozen, not multi, not normal",
6785+
xid, tuple->t_infomask)));
67796786

67806787
if (freeze_xmax)
67816788
{
6789+
Assert(!xmax_already_frozen);
6790+
67826791
frz->xmax = InvalidTransactionId;
67836792

67846793
/*
@@ -6831,7 +6840,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68316840
}
68326841
}
68336842

6834-
*totally_frozen_p = totally_frozen;
6843+
*totally_frozen_p = (xmin_frozen &&
6844+
(freeze_xmax || xmax_already_frozen));
68356845
return changed;
68366846
}
68376847

0 commit comments

Comments
 (0)