Skip to content

Commit d2599ec

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/[email protected]
1 parent 966268c commit d2599ec

File tree

1 file changed

+25
-15
lines changed

1 file changed

+25
-15
lines changed

src/backend/access/heap/heapam.c

+25-15
Original file line numberDiff line numberDiff line change
@@ -6803,9 +6803,10 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68036803
xl_heap_freeze_tuple *frz, bool *totally_frozen_p)
68046804
{
68056805
bool changed = false;
6806-
bool freeze_xmax = false;
6806+
bool xmax_already_frozen = false;
6807+
bool xmin_frozen;
6808+
bool freeze_xmax;
68076809
TransactionId xid;
6808-
bool totally_frozen = true;
68096810

68106811
frz->frzflags = 0;
68116812
frz->t_infomask2 = tuple->t_infomask2;
@@ -6814,6 +6815,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68146815

68156816
/* Process xmin */
68166817
xid = HeapTupleHeaderGetXmin(tuple);
6818+
xmin_frozen = ((xid == FrozenTransactionId) ||
6819+
HeapTupleHeaderXminFrozen(tuple));
68176820
if (TransactionIdIsNormal(xid))
68186821
{
68196822
if (TransactionIdPrecedes(xid, relfrozenxid))
@@ -6832,9 +6835,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68326835

68336836
frz->t_infomask |= HEAP_XMIN_FROZEN;
68346837
changed = true;
6838+
xmin_frozen = true;
68356839
}
6836-
else
6837-
totally_frozen = false;
68386840
}
68396841

68406842
/*
@@ -6857,9 +6859,9 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68576859
relfrozenxid, relminmxid,
68586860
cutoff_xid, cutoff_multi, &flags);
68596861

6860-
if (flags & FRM_INVALIDATE_XMAX)
6861-
freeze_xmax = true;
6862-
else if (flags & FRM_RETURN_IS_XID)
6862+
freeze_xmax = (flags & FRM_INVALIDATE_XMAX);
6863+
6864+
if (flags & FRM_RETURN_IS_XID)
68636865
{
68646866
/*
68656867
* NB -- some of these transformations are only valid because we
@@ -6873,7 +6875,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68736875
if (flags & FRM_MARK_COMMITTED)
68746876
frz->t_infomask |= HEAP_XMAX_COMMITTED;
68756877
changed = true;
6876-
totally_frozen = false;
68776878
}
68786879
else if (flags & FRM_RETURN_IS_MULTI)
68796880
{
@@ -6895,11 +6896,6 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
68956896
frz->xmax = newxmax;
68966897

68976898
changed = true;
6898-
totally_frozen = false;
6899-
}
6900-
else
6901-
{
6902-
Assert(flags & FRM_NOOP);
69036899
}
69046900
}
69056901
else if (TransactionIdIsNormal(xid))
@@ -6927,11 +6923,24 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
69276923
freeze_xmax = true;
69286924
}
69296925
else
6930-
totally_frozen = false;
6926+
freeze_xmax = false;
69316927
}
6928+
else if ((tuple->t_infomask & HEAP_XMAX_INVALID) ||
6929+
!TransactionIdIsValid(HeapTupleHeaderGetRawXmax(tuple)))
6930+
{
6931+
freeze_xmax = false;
6932+
xmax_already_frozen = true;
6933+
}
6934+
else
6935+
ereport(ERROR,
6936+
(errcode(ERRCODE_DATA_CORRUPTED),
6937+
errmsg_internal("found xmax %u (infomask 0x%04x) not frozen, not multi, not normal",
6938+
xid, tuple->t_infomask)));
69326939

69336940
if (freeze_xmax)
69346941
{
6942+
Assert(!xmax_already_frozen);
6943+
69356944
frz->xmax = InvalidTransactionId;
69366945

69376946
/*
@@ -6984,7 +6993,8 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
69846993
}
69856994
}
69866995

6987-
*totally_frozen_p = totally_frozen;
6996+
*totally_frozen_p = (xmin_frozen &&
6997+
(freeze_xmax || xmax_already_frozen));
69886998
return changed;
69896999
}
69907000

0 commit comments

Comments
 (0)