From 2821299896b82eb6ef919616577570ffcd1ef31c Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Thu, 2 Apr 2026 13:45:48 -0500 Subject: [PATCH v8 2/5] always compute autovacuum scores --- src/backend/postmaster/autovacuum.c | 114 ++++++++++++++-------------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 590e4c8e44c..817025ce616 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -3122,6 +3122,10 @@ relation_needs_vacanalyze(Oid relid, TransactionId relfrozenxid; MultiXactId relminmxid; MultiXactId multiForceLimit; + uint32 xid_age; + uint32 mxid_age; + int effective_xid_failsafe_age; + int effective_mxid_failsafe_age; float4 pcnt_unfrozen = 1; float4 reltuples = classForm->reltuples; @@ -3181,6 +3185,7 @@ relation_needs_vacanalyze(Oid relid, : effective_multixact_freeze_max_age; av_enabled = (relopts ? relopts->enabled : true); + av_enabled &= AutoVacuumingActive(); relfrozenxid = classForm->relfrozenxid; relminmxid = classForm->relminmxid; @@ -3201,65 +3206,51 @@ relation_needs_vacanalyze(Oid relid, } *wraparound = force_vacuum; - /* Update the score. */ - if (force_vacuum) - { - uint32 xid_age; - uint32 mxid_age; - int effective_xid_failsafe_age; - int effective_mxid_failsafe_age; - - /* - * To calculate the (M)XID age portion of the score, divide the age by - * its respective *_freeze_max_age parameter. - */ - xid_age = TransactionIdIsNormal(relfrozenxid) ? recentXid - relfrozenxid : 0; - mxid_age = MultiXactIdIsValid(relminmxid) ? recentMulti - relminmxid : 0; - - scores->xid = (double) xid_age / freeze_max_age; - scores->mxid = (double) mxid_age / multixact_freeze_max_age; + /* + * To calculate the (M)XID age portion of the score, divide the age by its + * respective *_freeze_max_age parameter. + */ + xid_age = TransactionIdIsNormal(relfrozenxid) ? recentXid - relfrozenxid : 0; + mxid_age = MultiXactIdIsValid(relminmxid) ? recentMulti - relminmxid : 0; - /* - * To ensure tables are given increased priority once they begin - * approaching wraparound, we scale the score aggressively if the ages - * surpass vacuum_failsafe_age or vacuum_multixact_failsafe_age. - * - * As in vacuum_xid_failsafe_check(), the effective failsafe age is no - * less than 105% the value of the respective *_freeze_max_age - * parameter. Note that per-table settings could result in a low - * score even if the table surpasses the failsafe settings. However, - * this is a strange enough corner case that we don't bother trying to - * handle it. - * - * We further adjust the effective failsafe ages with the weight - * parameters so that increasing them lowers the ages at which we - * begin scaling aggressively. - */ - effective_xid_failsafe_age = Max(vacuum_failsafe_age, - autovacuum_freeze_max_age * 1.05); - effective_mxid_failsafe_age = Max(vacuum_multixact_failsafe_age, - autovacuum_multixact_freeze_max_age * 1.05); + scores->xid = (double) xid_age / freeze_max_age; + scores->mxid = (double) mxid_age / multixact_freeze_max_age; - if (autovacuum_freeze_score_weight > 1.0) - effective_xid_failsafe_age /= autovacuum_freeze_score_weight; - if (autovacuum_multixact_freeze_score_weight > 1.0) - effective_mxid_failsafe_age /= autovacuum_multixact_freeze_score_weight; + /* + * To ensure tables are given increased priority once they begin + * approaching wraparound, we scale the score aggressively if the ages + * surpass vacuum_failsafe_age or vacuum_multixact_failsafe_age. + * + * As in vacuum_xid_failsafe_check(), the effective failsafe age is no + * less than 105% the value of the respective *_freeze_max_age parameter. + * Note that per-table settings could result in a low score even if the + * table surpasses the failsafe settings. However, this is a strange + * enough corner case that we don't bother trying to handle it. + * + * We further adjust the effective failsafe ages with the weight + * parameters so that increasing them lowers the ages at which we begin + * scaling aggressively. + */ + effective_xid_failsafe_age = Max(vacuum_failsafe_age, + autovacuum_freeze_max_age * 1.05); + effective_mxid_failsafe_age = Max(vacuum_multixact_failsafe_age, + autovacuum_multixact_freeze_max_age * 1.05); - if (xid_age >= effective_xid_failsafe_age) - scores->xid = pow(scores->xid, Max(1.0, (double) xid_age / 100000000)); - if (mxid_age >= effective_mxid_failsafe_age) - scores->mxid = pow(scores->mxid, Max(1.0, (double) mxid_age / 100000000)); + if (autovacuum_freeze_score_weight > 1.0) + effective_xid_failsafe_age /= autovacuum_freeze_score_weight; + if (autovacuum_multixact_freeze_score_weight > 1.0) + effective_mxid_failsafe_age /= autovacuum_multixact_freeze_score_weight; - scores->xid *= autovacuum_freeze_score_weight; - scores->mxid *= autovacuum_multixact_freeze_score_weight; + if (xid_age >= effective_xid_failsafe_age) + scores->xid = pow(scores->xid, Max(1.0, (double) xid_age / 100000000)); + if (mxid_age >= effective_mxid_failsafe_age) + scores->mxid = pow(scores->mxid, Max(1.0, (double) mxid_age / 100000000)); - scores->max = Max(scores->xid, scores->mxid); - *dovacuum = true; - } + scores->xid *= autovacuum_freeze_score_weight; + scores->mxid *= autovacuum_multixact_freeze_score_weight; - /* User disabled it in pg_class.reloptions? (But ignore if at risk) */ - if (!av_enabled && !force_vacuum) - return; + scores->max = Max(scores->xid, scores->mxid); + *dovacuum |= force_vacuum; /* * If we found stats for the table, and autovacuum is currently enabled, @@ -3268,7 +3259,7 @@ relation_needs_vacanalyze(Oid relid, * vacuuming only, so don't vacuum (or analyze) anything that's not being * forced. */ - if (!tabentry || !AutoVacuumingActive()) + if (!tabentry) return; vactuples = tabentry->dead_tuples; @@ -3312,7 +3303,7 @@ relation_needs_vacanalyze(Oid relid, scores->vac = (double) vactuples / Max(vacthresh, 1); scores->vac *= autovacuum_vacuum_score_weight; scores->max = Max(scores->max, scores->vac); - *dovacuum = true; + *dovacuum |= av_enabled; } if (vac_ins_base_thresh >= 0 && instuples > vacinsthresh) @@ -3320,7 +3311,7 @@ relation_needs_vacanalyze(Oid relid, scores->vac_ins = (double) instuples / Max(vacinsthresh, 1); scores->vac_ins *= autovacuum_vacuum_insert_score_weight; scores->max = Max(scores->max, scores->vac_ins); - *dovacuum = true; + *dovacuum |= av_enabled; } /* @@ -3334,7 +3325,16 @@ relation_needs_vacanalyze(Oid relid, scores->anl = (double) anltuples / Max(anlthresh, 1); scores->anl *= autovacuum_analyze_score_weight; scores->max = Max(scores->max, scores->anl); - *doanalyze = true; + *doanalyze |= av_enabled; + + /* + * For historical reasons, we analyze even when autovacuum is disabled + * for the table if at risk of wraparound. It's not clear if this is + * necessary or intentional, but it has been this way for nearly 20 + * years, so it seems best to avoid changing it without further + * discussion. + */ + *doanalyze |= (force_vacuum && AutoVacuumingActive()); } if (vac_ins_base_thresh >= 0) -- 2.50.1 (Apple Git-155)