@ -6208,10 +6208,10 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
* been pruned away instead , since updater XID is < OldestXmin ) .
* been pruned away instead , since updater XID is < OldestXmin ) .
* Just remove xmax .
* Just remove xmax .
*/
*/
if ( TransactionIdDidCommi t( update_xact ) )
if ( ! TransactionIdDidAbor t( update_xact ) )
ereport ( ERROR ,
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " multixact %u contains commit ted update XID %u from before removable cutoff %u " ,
errmsg_internal ( " multixact %u contains non-abor ted update XID %u from before removable cutoff %u " ,
multi , update_xact ,
multi , update_xact ,
cutoffs - > OldestXmin ) ) ) ;
cutoffs - > OldestXmin ) ) ) ;
* flags | = FRM_INVALIDATE_XMAX ;
* flags | = FRM_INVALIDATE_XMAX ;
@ -6500,10 +6500,11 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
freeze_xmax = false ;
freeze_xmax = false ;
TransactionId xid ;
TransactionId xid ;
frz - > frzflags = 0 ;
frz - > xmax = HeapTupleHeaderGetRawXmax ( tuple ) ;
frz - > t_infomask2 = tuple - > t_infomask2 ;
frz - > t_infomask2 = tuple - > t_infomask2 ;
frz - > t_infomask = tuple - > t_infomask ;
frz - > t_infomask = tuple - > t_infomask ;
frz - > xmax = HeapTupleHeaderGetRawXmax ( tuple ) ;
frz - > frzflags = 0 ;
frz - > checkflags = 0 ;
/*
/*
* Process xmin , while keeping track of whether it ' s already frozen , or
* Process xmin , while keeping track of whether it ' s already frozen , or
@ -6521,14 +6522,12 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
errmsg_internal ( " found xmin %u from before relfrozenxid %u " ,
errmsg_internal ( " found xmin %u from before relfrozenxid %u " ,
xid , cutoffs - > relfrozenxid ) ) ) ;
xid , cutoffs - > relfrozenxid ) ) ) ;
/* Will set freeze_xmin flags in freeze plan below */
freeze_xmin = TransactionIdPrecedes ( xid , cutoffs - > OldestXmin ) ;
freeze_xmin = TransactionIdPrecedes ( xid , cutoffs - > OldestXmin ) ;
if ( freeze_xmin & & ! TransactionIdDidCommit ( xid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " uncommitted xmin %u from before xid cutoff %u needs to be frozen " ,
xid , cutoffs - > OldestXmin ) ) ) ;
/* Will set freeze_xmin flags in freeze plan below */
/* Verify that xmin committed if and when freeze plan is executed */
if ( freeze_xmin )
frz - > checkflags | = HEAP_FREEZE_CHECK_XMIN_COMMITTED ;
}
}
/*
/*
@ -6551,7 +6550,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
}
}
/* Now process xmax */
/* Now process xmax */
xid = HeapTupleHeaderGetRawXmax ( tuple ) ;
xid = frz - > xmax ;
if ( tuple - > t_infomask & HEAP_XMAX_IS_MULTI )
if ( tuple - > t_infomask & HEAP_XMAX_IS_MULTI )
{
{
/* Raw xmax is a MultiXactId */
/* Raw xmax is a MultiXactId */
@ -6662,21 +6661,16 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple,
errmsg_internal ( " found xmax %u from before relfrozenxid %u " ,
errmsg_internal ( " found xmax %u from before relfrozenxid %u " ,
xid , cutoffs - > relfrozenxid ) ) ) ;
xid , cutoffs - > relfrozenxid ) ) ) ;
if ( TransactionIdPrecedes ( xid , cutoffs - > OldestXmin ) )
/* Will set freeze_xmax flags in freeze plan below */
freeze_xmax = true ;
freeze_xmax = Transac tionIdP recedes ( xid , c utoffs - > Old estXmin ) ;
/*
/*
* If we freeze xmax , make absolutely sure that it ' s not an XID that
* Verify that xmax aborted if and when freeze plan is executed ,
* is important . ( Note , a lock - only xmax can be removed independent
* provided it ' s from an update . ( A lock - only xmax can be removed
* of committedness , since a committed lock holder has released the
* independent of this , since the lock is released at xact end . )
* lock ) .
*/
*/
if ( freeze_xmax & & ! HEAP_XMAX_IS_LOCKED_ONLY ( tuple - > t_infomask ) & &
if ( freeze_xmax & & ! HEAP_XMAX_IS_LOCKED_ONLY ( tuple - > t_infomask ) )
TransactionIdDidCommit ( xid ) )
frz - > checkflags | = HEAP_FREEZE_CHECK_XMAX_ABORTED ;
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " cannot freeze committed xmax %u " ,
xid ) ) ) ;
}
}
else if ( ! TransactionIdIsValid ( xid ) )
else if ( ! TransactionIdIsValid ( xid ) )
{
{
@ -6804,19 +6798,60 @@ heap_freeze_execute_prepared(Relation rel, Buffer buffer,
Assert ( ntuples > 0 ) ;
Assert ( ntuples > 0 ) ;
START_CRIT_SECTION ( ) ;
/*
* Perform xmin / xmax XID status sanity checks before critical section .
*
* heap_prepare_freeze_tuple doesn ' t perform these checks directly because
* pg_xact lookups are relatively expensive . They shouldn ' t be repeated
* by successive VACUUMs that each decide against freezing the same page .
*/
for ( int i = 0 ; i < ntuples ; i + + )
{
HeapTupleFreeze * frz = tuples + i ;
ItemId itemid = PageGetItemId ( page , frz - > offset ) ;
HeapTupleHeader htup ;
MarkBufferDirty ( buffer ) ;
htup = ( HeapTupleHeader ) PageGetItem ( page , itemid ) ;
/* Deliberately avoid relying on tuple hint bits here */
if ( frz - > checkflags & HEAP_FREEZE_CHECK_XMIN_COMMITTED )
{
TransactionId xmin = HeapTupleHeaderGetRawXmin ( htup ) ;
Assert ( ! HeapTupleHeaderXminFrozen ( htup ) ) ;
if ( unlikely ( ! TransactionIdDidCommit ( xmin ) ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " uncommitted xmin %u needs to be frozen " ,
xmin ) ) ) ;
}
if ( frz - > checkflags & HEAP_FREEZE_CHECK_XMAX_ABORTED )
{
TransactionId xmax = HeapTupleHeaderGetRawXmax ( htup ) ;
Assert ( TransactionIdIsNormal ( xmax ) ) ;
if ( unlikely ( ! TransactionIdDidAbort ( xmax ) ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " cannot freeze non-aborted xmax %u " ,
xmax ) ) ) ;
}
}
START_CRIT_SECTION ( ) ;
for ( int i = 0 ; i < ntuples ; i + + )
for ( int i = 0 ; i < ntuples ; i + + )
{
{
HeapTupleFreeze * frz = tuples + i ;
ItemId itemid = PageGetItemId ( page , frz - > offset ) ;
HeapTupleHeader htup ;
HeapTupleHeader htup ;
ItemId itemid = PageGetItemId ( page , tuples [ i ] . offset ) ;
htup = ( HeapTupleHeader ) PageGetItem ( page , itemid ) ;
htup = ( HeapTupleHeader ) PageGetItem ( page , itemid ) ;
heap_execute_freeze_tuple ( htup , & tuples [ i ] ) ;
heap_execute_freeze_tuple ( htup , frz ) ;
}
}
MarkBufferDirty ( buffer ) ;
/* Now WAL-log freezing if necessary */
/* Now WAL-log freezing if necessary */
if ( RelationNeedsWAL ( rel ) )
if ( RelationNeedsWAL ( rel ) )
{
{