]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Avoid division-by-zero when calculating autovacuum MXID score.
authorNathan Bossart <nathan@postgresql.org>
Thu, 18 Jun 2026 15:18:25 +0000 (10:18 -0500)
committerNathan Bossart <nathan@postgresql.org>
Thu, 18 Jun 2026 15:18:25 +0000 (10:18 -0500)
In some cases, effective_multixact_freeze_max_age can be 0, which
presents a division-by-zero hazard for the multixact ID age score
calculation.  To fix, bump it to 1 in that case so that we use the
multixact ID age as the score.  While at it, also document that
this component score scales due to high multixact member space
usage.

Reported-by: Masahiko Sawada <sawada.mshk@gmail.com>
Author: Sami Imseih <samimseih@gmail.com>
Reviewed-by: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Discussion: https://postgr.es/m/CAD21AoC6nKeYAjTvJ9dmBea03GZK9222h_O%3DONmcVuxfyO88Bg%40mail.gmail.com

doc/src/sgml/maintenance.sgml
src/backend/postmaster/autovacuum.c

index 96ea84b11f24e215f83907d8a4d07003910afb37..e341f165efd904a7e00b92ef603c6478d687d112 100644 (file)
@@ -1112,8 +1112,10 @@ analyze threshold = analyze base threshold + analyze scale factor * number of tu
        field as compared to
        <xref linkend="guc-autovacuum-multixact-freeze-max-age"/>.  Furthermore,
        this component increases greatly once the age surpasses
-       <xref linkend="guc-vacuum-multixact-failsafe-age"/>.  The final value
-       for this component can be adjusted via
+       <xref linkend="guc-vacuum-multixact-failsafe-age"/> or when the number
+       of multixact member entries created exceeds approximately 2 billion
+       entries (see <xref linkend="vacuum-for-multixact-wraparound"/>).  The
+       final value for this component can be adjusted via
        <xref linkend="guc-autovacuum-multixact-freeze-score-weight"/>.  Note
        that increasing this parameter's value also lowers the age at which this
        component begins scaling aggressively, i.e., the scaling age is divided
index a5a8db2ff88793ffcd5d8ce06a3864aadefb1c46..e9aaf24c1bec8d7bf2d6a3e6c2ac04bc17687f9c 100644 (file)
@@ -3048,7 +3048,10 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map,
  * One exception to the previous paragraph is for tables nearing wraparound,
  * i.e., those that have surpassed the effective failsafe ages.  In that case,
  * the relfrozenxid/relminmxid-based score is scaled aggressively so that the
- * table has a decent chance of sorting to the front of the list.
+ * table has a decent chance of sorting to the front of the list.  Furthermore,
+ * the relminmxid-based score is scaled aggressively as
+ * effective_multixact_freeze_max_age is lowered due to high multixact member
+ * space usage.
  *
  * To adjust how strongly each component contributes to the score, the
  * following parameters can be adjusted from their default of 1.0 to anywhere
@@ -3194,13 +3197,15 @@ relation_needs_vacanalyze(Oid relid,
 
        /*
         * To calculate the (M)XID age portion of the score, divide the age by its
-        * respective *_freeze_max_age parameter.
+        * respective *_freeze_max_age parameter.  The multixact_freeze_max_age
+        * variable might be 0 here (i.e., a division-by-zero hazard), so in that
+        * case we use the mxid_age as the MXID score.
         */
        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;
+       scores->mxid = (double) mxid_age / Max(1, multixact_freeze_max_age);
 
        /*
         * To ensure tables are given increased priority once they begin