@ -956,24 +956,25 @@ get_all_vacuum_rels(int options)
bool
bool
vacuum_set_xid_limits ( Relation rel ,
vacuum_set_xid_limits ( Relation rel ,
int freeze_min_age ,
int freeze_min_age ,
int freeze_table_age ,
int multixact_freeze_min_age ,
int multixact_freeze_min_age ,
int freeze_table_age ,
int multixact_freeze_table_age ,
int multixact_freeze_table_age ,
TransactionId * oldestXmin ,
TransactionId * oldestXmin ,
MultiXactId * oldestMxact ,
MultiXactId * oldestMxact ,
TransactionId * freezeLimit ,
TransactionId * freezeLimit ,
MultiXactId * multiXactCutoff )
MultiXactId * multiXactCutoff )
{
{
int freezemin ;
TransactionId nextXID ,
int mxid_freezemin ;
safeOldestXmin ,
aggressiveXIDCutoff ;
MultiXactId nextMXID ,
safeOldestMxact ,
aggressiveMXIDCutoff ;
int effective_multixact_freeze_max_age ;
int effective_multixact_freeze_max_age ;
TransactionId limit ;
TransactionId safeLimit ;
MultiXactId mxactLimit ;
MultiXactId safeMxactLimit ;
int freezetable ;
/*
/*
* Acquire oldestXmin .
*
* We can always ignore processes running lazy vacuum . This is because we
* We can always ignore processes running lazy vacuum . This is because we
* use these values only for deciding which tuples we must keep in the
* use these values only for deciding which tuples we must keep in the
* tables . Since lazy vacuum doesn ' t write its XID anywhere ( usually no
* tables . Since lazy vacuum doesn ' t write its XID anywhere ( usually no
@ -1005,44 +1006,32 @@ vacuum_set_xid_limits(Relation rel,
Assert ( TransactionIdIsNormal ( * oldestXmin ) ) ;
Assert ( TransactionIdIsNormal ( * oldestXmin ) ) ;
/* Acquire oldestMxact */
* oldestMxact = GetOldestMultiXactId ( ) ;
Assert ( MultiXactIdIsValid ( * oldestMxact ) ) ;
/* Acquire next XID/next MXID values used to apply age-based settings */
nextXID = ReadNextTransactionId ( ) ;
nextMXID = ReadNextMultiXactId ( ) ;
/*
/*
* Determine the minimum freeze age to use : as specified by the caller , or
* Determine the minimum freeze age to use : as specified by the caller , or
* vacuum_freeze_min_age , but in any case not more than half
* vacuum_freeze_min_age , but in any case not more than half
* autovacuum_freeze_max_age , so that autovacuums to prevent XID
* autovacuum_freeze_max_age , so that autovacuums to prevent XID
* wraparound won ' t occur too frequently .
* wraparound won ' t occur too frequently .
*/
*/
freezemin = freeze_min_age ;
if ( freeze_min_age < 0 )
if ( freezemin < 0 )
freeze_min_age = vacuum_freeze_min_age ;
freezemin = vacuum_freeze_min_age ;
freeze_min_age = Min ( freeze_min_age , autovacuum_freeze_max_age / 2 ) ;
freezemin = Min ( freezemin , autovacuum_freeze_max_age / 2 ) ;
Assert ( freeze_min_age > = 0 ) ;
Assert ( freezemin > = 0 ) ;
/*
* Compute the cutoff XID , being careful not to generate a " permanent " XID
*/
limit = * oldestXmin - freezemin ;
if ( ! TransactionIdIsNormal ( limit ) )
limit = FirstNormalTransactionId ;
/*
* If oldestXmin is very far back ( in practice , more than
* autovacuum_freeze_max_age / 2 XIDs old ) , complain and force a minimum
* freeze age of zero .
*/
safeLimit = ReadNextTransactionId ( ) - autovacuum_freeze_max_age ;
if ( ! TransactionIdIsNormal ( safeLimit ) )
safeLimit = FirstNormalTransactionId ;
if ( TransactionIdPrecedes ( limit , safeLimit ) )
{
ereport ( WARNING ,
( errmsg ( " oldest xmin is far in the past " ) ,
errhint ( " Close open transactions soon to avoid wraparound problems. \n "
" You might also need to commit or roll back old prepared transactions, or drop stale replication slots. " ) ) ) ;
limit = * oldestXmin ;
}
* freezeLimit = limit ;
/* Compute freezeLimit, being careful to generate a normal XID */
* freezeLimit = nextXID - freeze_min_age ;
if ( ! TransactionIdIsNormal ( * freezeLimit ) )
* freezeLimit = FirstNormalTransactionId ;
/* freezeLimit must always be <= oldestXmin */
if ( TransactionIdPrecedes ( * oldestXmin , * freezeLimit ) )
* freezeLimit = * oldestXmin ;
/*
/*
* Compute the multixact age for which freezing is urgent . This is
* Compute the multixact age for which freezing is urgent . This is
@ -1057,93 +1046,83 @@ vacuum_set_xid_limits(Relation rel,
* than half effective_multixact_freeze_max_age , so that autovacuums to
* than half effective_multixact_freeze_max_age , so that autovacuums to
* prevent MultiXact wraparound won ' t occur too frequently .
* prevent MultiXact wraparound won ' t occur too frequently .
*/
*/
mxid_freezemin = multixact_freeze_min_age ;
if ( multixact_freeze_min_age < 0 )
if ( mxid_freezemin < 0 )
multixact_freeze_min_age = vacuum_multixact_freeze_min_age ;
mxid_freezemin = vacuum_multixact_freeze_min_age ;
multixact_freeze_min_age = Min ( multixact_freeze_min_age ,
mxid_freezemin = Min ( mxid_freezemin ,
effective_multixact_freeze_max_age / 2 ) ;
effective_multixact_freeze_max_age / 2 ) ;
Assert ( mxid_freezemin > = 0 ) ;
Assert ( multixact_freeze_min_age > = 0 ) ;
/* Remember for caller */
/* Compute multiXactCutoff, being careful to generate a valid value */
* oldestMxact = GetOldestMultiXactId ( ) ;
* multiXactCutoff = nextMXID - multixact_freeze_min_age ;
if ( * multiXactCutoff < FirstMultiXactId )
/* compute the cutoff multi, being careful to generate a valid value */
* multiXactCutoff = FirstMultiXactId ;
mxactLimit = * oldestMxact - mxid_freezemin ;
/* multiXactCutoff must always be <= oldestMxact */
if ( mxactLimit < FirstMultiXactId )
if ( MultiXactIdPrecedes ( * oldestMxact , * multiXactCutoff ) )
mxactLimit = FirstMultiXactId ;
* multiXactCutoff = * oldestMxact ;
safeMxactLimit =
/*
ReadNextMultiXactId ( ) - effective_multixact_freeze_max_age ;
* Done setting output parameters ; check if oldestXmin or oldestMxact are
if ( safeMxactLimit < FirstMultiXactId )
* held back to an unsafe degree in passing
safeMxactLimit = FirstMultiXactId ;
*/
safeOldestXmin = nextXID - autovacuum_freeze_max_age ;
if ( MultiXactIdPrecedes ( mxactLimit , safeMxactLimit ) )
if ( ! TransactionIdIsNormal ( safeOldestXmin ) )
{
safeOldestXmin = FirstNormalTransactionId ;
safeOldestMxact = nextMXID - effective_multixact_freeze_max_age ;
if ( safeOldestMxact < FirstMultiXactId )
safeOldestMxact = FirstMultiXactId ;
if ( TransactionIdPrecedes ( * oldestXmin , safeOldestXmin ) )
ereport ( WARNING ,
ereport ( WARNING ,
( errmsg ( " oldest multixact is far in the past " ) ,
( errmsg ( " cutoff for removing and freezing tuples is far in the past " ) ,
errhint ( " Close open transactions with multixacts soon to avoid wraparound problems. " ) ) ) ;
errhint ( " Close open transactions soon to avoid wraparound problems. \n "
/* Use the safe limit, unless an older mxact is still running */
" You might also need to commit or roll back old prepared transactions, or drop stale replication slots. " ) ) ) ;
if ( MultiXactIdPrecedes ( * oldestMxact , safeMxactLimit ) )
if ( MultiXactIdPrecedes ( * oldestMxact , safeOldestMxact ) )
mxactLimit = * oldestMxact ;
ereport ( WARNING ,
else
( errmsg ( " cutoff for freezing multixacts is far in the past " ) ,
mxactLimit = safeMxactLimit ;
errhint ( " Close open transactions soon to avoid wraparound problems. \n "
}
" You might also need to commit or roll back old prepared transactions, or drop stale replication slots. " ) ) ) ;
* multiXactCutoff = mxactLimit ;
/*
/*
* Done setting output parameters ; just need to figure out if caller needs
* Finally , figure out if caller needs to do an aggressive VACUUM or not .
* to do an aggressive VACUUM or not .
*
*
* Determine the table freeze age to use : as specified by the caller , or
* Determine the table freeze age to use : as specified by the caller , or
* vacuum_freeze_table_age , but in any case not more than
* the value of the vacuum_freeze_table_age GUC , but in any case not more
* autovacuum_freeze_max_age * 0.95 , so that if you have e . g nightly
* than autovacuum_freeze_max_age * 0.95 , so that if you have e . g nightly
* VACUUM schedule , the nightly VACUUM gets a chance to freeze tuples
* VACUUM schedule , the nightly VACUUM gets a chance to freeze XIDs before
* before anti - wraparound autovacuum is launched .
* anti - wraparound autovacuum is launched .
*/
*/
freezetable = freeze_table_age ;
if ( freeze_table_age < 0 )
if ( freezetable < 0 )
freeze_table_age = vacuum_freeze_table_age ;
freezetable = vacuum_freeze_table_age ;
freeze_table_age = Min ( freeze_table_age , autovacuum_freeze_max_age * 0.95 ) ;
freezetable = Min ( freezetable , autovacuum_freeze_max_age * 0.95 ) ;
Assert ( freeze_table_age > = 0 ) ;
Assert ( freezetable > = 0 ) ;
aggressiveXIDCutoff = nextXID - freeze_table_age ;
if ( ! TransactionIdIsNormal ( aggressiveXIDCutoff ) )
/*
aggressiveXIDCutoff = FirstNormalTransactionId ;
* Compute XID limit causing an aggressive vacuum , being careful not to
* generate a " permanent " XID
*/
limit = ReadNextTransactionId ( ) - freezetable ;
if ( ! TransactionIdIsNormal ( limit ) )
limit = FirstNormalTransactionId ;
if ( TransactionIdPrecedesOrEquals ( rel - > rd_rel - > relfrozenxid ,
if ( TransactionIdPrecedesOrEquals ( rel - > rd_rel - > relfrozenxid ,
limit ) )
aggressiveXIDCutoff ) )
return true ;
return true ;
/*
/*
* Similar to the above , determine the table freeze age to use for
* Similar to the above , determine the table freeze age to use for
* multixacts : as specified by the caller , or
* multixacts : as specified by the caller , or the value of the
* vacuum_multixact_freeze_table_age , but in any case not more than
* vacuum_multixact_freeze_table_age GUC , but in any case not more than
* autovacuum_multixact_freeze_table _age * 0.95 , so that if you have e . g .
* effective_multixact_freeze_max _age * 0.95 , so that if you have e . g .
* nightly VACUUM schedule , the nightly VACUUM gets a chance to freeze
* nightly VACUUM schedule , the nightly VACUUM gets a chance to freeze
* multixacts before anti - wraparound autovacuum is launched .
* multixacts before anti - wraparound autovacuum is launched .
*/
*/
freezetable = multixact_freeze_table_age ;
if ( multixact_freeze_table_age < 0 )
if ( freezetable < 0 )
multixact_freeze_table_age = vacuum_multixact_freeze_table_age ;
freezetable = vacuum_multixact_freeze_table_age ;
multixact_freeze_table_age =
freezetable = Min ( freezetable ,
Min ( multixact_ freeze_ table_ag e,
effective_multixact_freeze_max_age * 0.95 ) ;
effective_multixact_freeze_max_age * 0.95 ) ;
Assert ( freezetable > = 0 ) ;
Assert ( multixact_freeze_table_age > = 0 ) ;
aggressiveMXIDCutoff = nextMXID - multixact_freeze_table_age ;
/*
if ( aggressiveMXIDCutoff < FirstMultiXactId )
* Compute MultiXact limit causing an aggressive vacuum , being careful to
aggressiveMXIDCutoff = FirstMultiXactId ;
* generate a valid MultiXact value
*/
mxactLimit = ReadNextMultiXactId ( ) - freezetable ;
if ( mxactLimit < FirstMultiXactId )
mxactLimit = FirstMultiXactId ;
if ( MultiXactIdPrecedesOrEquals ( rel - > rd_rel - > relminmxid ,
if ( MultiXactIdPrecedesOrEquals ( rel - > rd_rel - > relminmxid ,
mxactLimit ) )
aggressiveMXIDCutoff ) )
return true ;
return true ;
/* Non-aggressive VACUUM */
return false ;
return false ;
}
}