Skip to content

Commit c6764eb

Browse files
committed
Revert bogus fixes of HOT-freezing bug
It turns out we misdiagnosed what the real problem was. Revert the previous changes, because they may have worse consequences going forward. A better fix is forthcoming. The simplistic test case is kept, though disabled. Discussion: https://postgr.es/m/20171102112019.33wb7g5wp4zpjelu@alap3.anarazel.de
1 parent d8c435e commit c6764eb

File tree

6 files changed

+38
-105
lines changed

6 files changed

+38
-105
lines changed

src/backend/access/heap/heapam.c

Lines changed: 22 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,8 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
20742074
* broken.
20752075
*/
20762076
if (TransactionIdIsValid(prev_xmax) &&
2077-
!HeapTupleUpdateXmaxMatchesXmin(prev_xmax, heapTuple->t_data))
2077+
!TransactionIdEquals(prev_xmax,
2078+
HeapTupleHeaderGetXmin(heapTuple->t_data)))
20782079
break;
20792080

20802081
/*
@@ -2260,7 +2261,7 @@ heap_get_latest_tid(Relation relation,
22602261
* tuple. Check for XMIN match.
22612262
*/
22622263
if (TransactionIdIsValid(priorXmax) &&
2263-
!HeapTupleUpdateXmaxMatchesXmin(priorXmax, tp.t_data))
2264+
!TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(tp.t_data)))
22642265
{
22652266
UnlockReleaseBuffer(buffer);
22662267
break;
@@ -2292,50 +2293,6 @@ heap_get_latest_tid(Relation relation,
22922293
} /* end of loop */
22932294
}
22942295

2295-
/*
2296-
* HeapTupleUpdateXmaxMatchesXmin - verify update chain xmax/xmin lineage
2297-
*
2298-
* Given the new version of a tuple after some update, verify whether the
2299-
* given Xmax (corresponding to the previous version) matches the tuple's
2300-
* Xmin, taking into account that the Xmin might have been frozen after the
2301-
* update.
2302-
*/
2303-
bool
2304-
HeapTupleUpdateXmaxMatchesXmin(TransactionId xmax, HeapTupleHeader htup)
2305-
{
2306-
TransactionId xmin = HeapTupleHeaderGetXmin(htup);
2307-
2308-
/*
2309-
* If the xmax of the old tuple is identical to the xmin of the new one,
2310-
* it's a match.
2311-
*/
2312-
if (TransactionIdEquals(xmax, xmin))
2313-
return true;
2314-
2315-
/*
2316-
* If the Xmin that was in effect prior to a freeze matches the Xmax,
2317-
* it's good too.
2318-
*/
2319-
if (HeapTupleHeaderXminFrozen(htup) &&
2320-
TransactionIdEquals(HeapTupleHeaderGetRawXmin(htup), xmax))
2321-
return true;
2322-
2323-
/*
2324-
* When a tuple is frozen, the original Xmin is lost, but we know it's a
2325-
* committed transaction. So unless the Xmax is InvalidXid, we don't know
2326-
* for certain that there is a match, but there may be one; and we must
2327-
* return true so that a HOT chain that is half-frozen can be walked
2328-
* correctly.
2329-
*
2330-
* We no longer freeze tuples this way, but we must keep this in order to
2331-
* interpret pre-pg_upgrade pages correctly.
2332-
*/
2333-
if (TransactionIdEquals(xmin, FrozenTransactionId) &&
2334-
TransactionIdIsValid(xmax))
2335-
return true;
2336-
2337-
return false;
2338-
}
23392296

23402297
/*
23412298
* UpdateXmaxHintBits - update tuple hint bits after xmax transaction ends
@@ -5755,7 +5712,8 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
57555712
* end of the chain, we're done, so return success.
57565713
*/
57575714
if (TransactionIdIsValid(priorXmax) &&
5758-
!HeapTupleUpdateXmaxMatchesXmin(priorXmax, mytup.t_data))
5715+
!TransactionIdEquals(HeapTupleHeaderGetXmin(mytup.t_data),
5716+
priorXmax))
57595717
{
57605718
result = HeapTupleMayBeUpdated;
57615719
goto out_locked;
@@ -6449,23 +6407,14 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64496407
Assert(TransactionIdIsValid(xid));
64506408

64516409
/*
6452-
* The updating transaction cannot possibly be still running, but
6453-
* verify whether it has committed, and request to set the
6454-
* COMMITTED flag if so. (We normally don't see any tuples in
6455-
* this state, because they are removed by page pruning before we
6456-
* try to freeze the page; but this can happen if the updating
6457-
* transaction commits after the page is pruned but before
6458-
* HeapTupleSatisfiesVacuum).
6410+
* If the xid is older than the cutoff, it has to have aborted,
6411+
* otherwise the tuple would have gotten pruned away.
64596412
*/
64606413
if (TransactionIdPrecedes(xid, cutoff_xid))
64616414
{
6462-
if (TransactionIdDidCommit(xid))
6463-
*flags = FRM_MARK_COMMITTED | FRM_RETURN_IS_XID;
6464-
else
6465-
{
6466-
*flags |= FRM_INVALIDATE_XMAX;
6467-
xid = InvalidTransactionId; /* not strictly necessary */
6468-
}
6415+
Assert(!TransactionIdDidCommit(xid));
6416+
*flags |= FRM_INVALIDATE_XMAX;
6417+
xid = InvalidTransactionId; /* not strictly necessary */
64696418
}
64706419
else
64716420
{
@@ -6538,16 +6487,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
65386487
/*
65396488
* It's an update; should we keep it? If the transaction is known
65406489
* aborted or crashed then it's okay to ignore it, otherwise not.
6490+
* Note that an updater older than cutoff_xid cannot possibly be
6491+
* committed, because HeapTupleSatisfiesVacuum would have returned
6492+
* HEAPTUPLE_DEAD and we would not be trying to freeze the tuple.
65416493
*
65426494
* As with all tuple visibility routines, it's critical to test
65436495
* TransactionIdIsInProgress before TransactionIdDidCommit,
65446496
* because of race conditions explained in detail in tqual.c.
6545-
*
6546-
* We normally don't see committed updating transactions earlier
6547-
* than the cutoff xid, because they are removed by page pruning
6548-
* before we try to freeze the page; but it can happen if the
6549-
* updating transaction commits after the page is pruned but
6550-
* before HeapTupleSatisfiesVacuum.
65516497
*/
65526498
if (TransactionIdIsCurrentTransactionId(xid) ||
65536499
TransactionIdIsInProgress(xid))
@@ -6572,6 +6518,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
65726518
* we can ignore it.
65736519
*/
65746520

6521+
/*
6522+
* Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6523+
* update Xid cannot possibly be older than the xid cutoff.
6524+
*/
6525+
Assert(!TransactionIdIsValid(update_xid) ||
6526+
!TransactionIdPrecedes(update_xid, cutoff_xid));
6527+
65756528
/*
65766529
* If we determined that it's an Xid corresponding to an update
65776530
* that must be retained, additionally add it to the list of
@@ -6650,10 +6603,7 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
66506603
*
66516604
* It is assumed that the caller has checked the tuple with
66526605
* HeapTupleSatisfiesVacuum() and determined that it is not HEAPTUPLE_DEAD
6653-
* (else we should be removing the tuple, not freezing it). However, note
6654-
* that we don't remove HOT tuples even if they are dead, and it'd be incorrect
6655-
* to freeze them (because that would make them visible), so we mark them as
6656-
* update-committed, and needing further freezing later on.
6606+
* (else we should be removing the tuple, not freezing it).
66576607
*
66586608
* NB: cutoff_xid *must* be <= the current global xmin, to ensure that any
66596609
* XID older than it could neither be running nor seen as running by any
@@ -6764,22 +6714,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
67646714
else if (TransactionIdIsNormal(xid))
67656715
{
67666716
if (TransactionIdPrecedes(xid, cutoff_xid))
6767-
{
6768-
/*
6769-
* Must freeze regular XIDs older than the cutoff. We must not
6770-
* freeze a HOT-updated tuple, though; doing so would bring it
6771-
* back to life.
6772-
*/
6773-
if (HeapTupleHeaderIsHotUpdated(tuple))
6774-
{
6775-
frz->t_infomask |= HEAP_XMAX_COMMITTED;
6776-
totally_frozen = false;
6777-
changed = true;
6778-
/* must not freeze */
6779-
}
6780-
else
6781-
freeze_xmax = true;
6782-
}
6717+
freeze_xmax = true;
67836718
else
67846719
totally_frozen = false;
67856720
}

src/backend/access/heap/pruneheap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ heap_prune_chain(Relation relation, Buffer buffer, OffsetNumber rootoffnum,
473473
* Check the tuple XMIN against prior XMAX, if any
474474
*/
475475
if (TransactionIdIsValid(priorXmax) &&
476-
!HeapTupleUpdateXmaxMatchesXmin(priorXmax, htup))
476+
!TransactionIdEquals(HeapTupleHeaderGetXmin(htup), priorXmax))
477477
break;
478478

479479
/*
@@ -813,7 +813,7 @@ heap_get_root_tuples(Page page, OffsetNumber *root_offsets)
813813
htup = (HeapTupleHeader) PageGetItem(page, lp);
814814

815815
if (TransactionIdIsValid(priorXmax) &&
816-
!HeapTupleUpdateXmaxMatchesXmin(priorXmax, htup))
816+
!TransactionIdEquals(priorXmax, HeapTupleHeaderGetXmin(htup)))
817817
break;
818818

819819
/* Remember the root line pointer for this item */

src/backend/commands/vacuumlazy.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,17 +2029,17 @@ lazy_record_dead_tuple(LVRelStats *vacrelstats,
20292029
ItemPointer itemptr)
20302030
{
20312031
/*
2032-
* The array must never overflow, since we rely on all deletable tuples
2033-
* being removed; inability to remove a tuple might cause an old XID to
2034-
* persist beyond the freeze limit, which could be disastrous later on.
2032+
* The array shouldn't overflow under normal behavior, but perhaps it
2033+
* could if we are given a really small maintenance_work_mem. In that
2034+
* case, just forget the last few tuples (we'll get 'em next time).
20352035
*/
2036-
if (vacrelstats->num_dead_tuples >= vacrelstats->max_dead_tuples)
2037-
elog(ERROR, "dead tuple array overflow");
2038-
2039-
vacrelstats->dead_tuples[vacrelstats->num_dead_tuples] = *itemptr;
2040-
vacrelstats->num_dead_tuples++;
2041-
pgstat_progress_update_param(PROGRESS_VACUUM_NUM_DEAD_TUPLES,
2042-
vacrelstats->num_dead_tuples);
2036+
if (vacrelstats->num_dead_tuples < vacrelstats->max_dead_tuples)
2037+
{
2038+
vacrelstats->dead_tuples[vacrelstats->num_dead_tuples] = *itemptr;
2039+
vacrelstats->num_dead_tuples++;
2040+
pgstat_progress_update_param(PROGRESS_VACUUM_NUM_DEAD_TUPLES,
2041+
vacrelstats->num_dead_tuples);
2042+
}
20432043
}
20442044

20452045
/*

src/backend/executor/execMain.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,7 +2595,8 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
25952595
* atomic, and Xmin never changes in an existing tuple, except to
25962596
* invalid or frozen, and neither of those can match priorXmax.)
25972597
*/
2598-
if (!HeapTupleUpdateXmaxMatchesXmin(priorXmax, tuple.t_data))
2598+
if (!TransactionIdEquals(HeapTupleHeaderGetXmin(tuple.t_data),
2599+
priorXmax))
25992600
{
26002601
ReleaseBuffer(buffer);
26012602
return NULL;
@@ -2742,7 +2743,8 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
27422743
/*
27432744
* As above, if xmin isn't what we're expecting, do nothing.
27442745
*/
2745-
if (!HeapTupleUpdateXmaxMatchesXmin(priorXmax, tuple.t_data))
2746+
if (!TransactionIdEquals(HeapTupleHeaderGetXmin(tuple.t_data),
2747+
priorXmax))
27462748
{
27472749
ReleaseBuffer(buffer);
27482750
return NULL;

src/include/access/heapam.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@ extern void heap_get_latest_tid(Relation relation, Snapshot snapshot,
146146
ItemPointer tid);
147147
extern void setLastTid(const ItemPointer tid);
148148

149-
extern bool HeapTupleUpdateXmaxMatchesXmin(TransactionId xmax,
150-
HeapTupleHeader htup);
151-
152149
extern BulkInsertState GetBulkInsertState(void);
153150
extern void FreeBulkInsertState(BulkInsertState);
154151
extern void ReleaseBulkInsertStatePin(BulkInsertState bistate);

src/test/isolation/isolation_schedule

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ test: update-locked-tuple
4444
test: propagate-lock-delete
4545
test: tuplelock-conflict
4646
test: tuplelock-update
47-
test: freeze-the-dead
4847
test: nowait
4948
test: nowait-2
5049
test: nowait-3

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy