@ -6357,6 +6357,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
*/
static TransactionId
FreezeMultiXactId ( MultiXactId multi , uint16 t_infomask ,
TransactionId relfrozenxid , TransactionId relminmxid ,
TransactionId cutoff_xid , MultiXactId cutoff_multi ,
uint16 * flags )
{
@ -6383,16 +6384,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
* flags | = FRM_INVALIDATE_XMAX ;
return InvalidTransactionId ;
}
else if ( MultiXactIdPrecedes ( multi , relminmxid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " found multixact %u from before relminmxid %u " ,
multi , relminmxid ) ) ) ;
else if ( MultiXactIdPrecedes ( multi , cutoff_multi ) )
{
/*
* This old multi cannot possibly have members still running . If it
* was a locker only , it can be removed without any further
* consideration ; but if it contained an update , we might need to
* preserve it .
* This old multi cannot possibly have members still running , bu t
* verify just in case . If it was a locker only , it can be removed
* without any further consideration ; but if it contained an update , we
* might need to preserve it .
*/
Assert ( ! MultiXactIdIsRunning ( multi ,
HEAP_XMAX_IS_LOCKED_ONLY ( t_infomask ) ) ) ;
if ( MultiXactIdIsRunning ( multi ,
HEAP_XMAX_IS_LOCKED_ONLY ( t_infomask ) ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " multixact %u from before cutoff %u found to be still running " ,
multi , cutoff_multi ) ) ) ;
if ( HEAP_XMAX_IS_LOCKED_ONLY ( t_infomask ) )
{
* flags | = FRM_INVALIDATE_XMAX ;
@ -6406,13 +6417,22 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
/* wasn't only a lock, xid needs to be valid */
Assert ( TransactionIdIsValid ( xid ) ) ;
if ( TransactionIdPrecedes ( xid , relfrozenxid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " found update xid %u from before relfrozenxid %u " ,
xid , relfrozenxid ) ) ) ;
/*
* If the xid is older than the cutoff , it has to have aborted ,
* otherwise the tuple would have gotten pruned away .
*/
if ( TransactionIdPrecedes ( xid , cutoff_xid ) )
{
Assert ( ! TransactionIdDidCommit ( xid ) ) ;
if ( TransactionIdDidCommit ( xid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " cannot freeze committed update xid %u " , xid ) ) ) ;
* flags | = FRM_INVALIDATE_XMAX ;
xid = InvalidTransactionId ; /* not strictly necessary */
}
@ -6484,6 +6504,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
{
TransactionId xid = members [ i ] . xid ;
Assert ( TransactionIdIsValid ( xid ) ) ;
if ( TransactionIdPrecedes ( xid , relfrozenxid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " found update xid %u from before relfrozenxid %u " ,
xid , relfrozenxid ) ) ) ;
/*
* It ' s an update ; should we keep it ? If the transaction is known
* aborted or crashed then it ' s okay to ignore it , otherwise not .
@ -6512,18 +6539,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
update_committed = true ;
update_xid = xid ;
}
/*
* Not in progress , not committed - - must be aborted or crashed ;
* we can ignore it .
*/
else
{
/*
* Not in progress , not committed - - must be aborted or crashed ;
* we can ignore it .
*/
}
/*
* Since the tuple wasn ' t marked HEAPTUPLE_DEAD by vacuum , the
* update Xid cannot possibly be older than the xid cutoff .
* update Xid cannot possibly be older than the xid cutoff . The
* presence of such a tuple would cause corruption , so be paranoid
* and check .
*/
Assert ( ! TransactionIdIsValid ( update_xid ) | |
! TransactionIdPrecedes ( update_xid , cutoff_xid ) ) ;
if ( TransactionIdIsValid ( update_xid ) & &
TransactionIdPrecedes ( update_xid , cutoff_xid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " found update xid %u from before xid cutoff %u " ,
update_xid , cutoff_xid ) ) ) ;
/*
* If we determined that it ' s an Xid corresponding to an update
@ -6620,8 +6655,9 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
* recovery . We really need to remove old xids .
*/
bool
heap_prepare_freeze_tuple ( HeapTupleHeader tuple , TransactionId cutoff_xid ,
TransactionId cutoff_multi ,
heap_prepare_freeze_tuple ( HeapTupleHeader tuple ,
TransactionId relfrozenxid , TransactionId relminmxid ,
TransactionId cutoff_xid , TransactionId cutoff_multi ,
xl_heap_freeze_tuple * frz , bool * totally_frozen_p )
{
bool changed = false ;
@ -6638,8 +6674,20 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
xid = HeapTupleHeaderGetXmin ( tuple ) ;
if ( TransactionIdIsNormal ( xid ) )
{
if ( TransactionIdPrecedes ( xid , relfrozenxid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " found xmin %u from before relfrozenxid %u " ,
xid , relfrozenxid ) ) ) ;
if ( TransactionIdPrecedes ( xid , cutoff_xid ) )
{
if ( ! TransactionIdDidCommit ( xid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " uncommitted xmin %u from before xid cutoff %u needs to be frozen " ,
xid , cutoff_xid ) ) ) ;
frz - > t_infomask | = HEAP_XMIN_FROZEN ;
changed = true ;
}
@ -6664,6 +6712,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
uint16 flags ;
newxmax = FreezeMultiXactId ( xid , tuple - > t_infomask ,
relfrozenxid , relminmxid ,
cutoff_xid , cutoff_multi , & flags ) ;
if ( flags & FRM_INVALIDATE_XMAX )
@ -6713,8 +6762,28 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
}
else if ( TransactionIdIsNormal ( xid ) )
{
if ( TransactionIdPrecedes ( xid , relfrozenxid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " found xmax %u from before relfrozenxid %u " ,
xid , relfrozenxid ) ) ) ;
if ( TransactionIdPrecedes ( xid , cutoff_xid ) )
{
/*
* If we freeze xmax , make absolutely sure that it ' s not an XID
* that is important . ( Note , a lock - only xmax can be removed
* independent of committedness , since a committed lock holder has
* released the lock ) .
*/
if ( ! ( tuple - > t_infomask & HEAP_XMAX_LOCK_ONLY ) & &
TransactionIdDidCommit ( xid ) )
ereport ( ERROR ,
( errcode ( ERRCODE_DATA_CORRUPTED ) ,
errmsg_internal ( " cannot freeze committed xmax %u " ,
xid ) ) ) ;
freeze_xmax = true ;
}
else
totally_frozen = false ;
}
@ -6819,14 +6888,17 @@ heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
* Useful for callers like CLUSTER that perform their own WAL logging .
*/
bool
heap_freeze_tuple ( HeapTupleHeader tuple , TransactionId cutoff_xid ,
TransactionId cutoff_multi )
heap_freeze_tuple ( HeapTupleHeader tuple ,
TransactionId relfrozenxid , TransactionId relminmxid ,
TransactionId cutoff_xid , TransactionId cutoff_multi )
{
xl_heap_freeze_tuple frz ;
bool do_freeze ;
bool tuple_totally_frozen ;
do_freeze = heap_prepare_freeze_tuple ( tuple , cutoff_xid , cutoff_multi ,
do_freeze = heap_prepare_freeze_tuple ( tuple ,
relfrozenxid , relminmxid ,
cutoff_xid , cutoff_multi ,
& frz , & tuple_totally_frozen ) ;
/*