From 6aa2cefe11841a6bff4dab65860c1a12a3e57146 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 30 Sep 2026 15:36:33 +0300 Subject: [PATCH] Fix autovacuum docs related to widening multixid offsets to 64 bits The explanation of aggressive scans claimed that if the multixact members grows to 2 billion entries, we launch autovacuum even if it's nominally disabled. That's no longer true; anti-wraparound vacuum is only triggered if we're in danger of running out of multixids, we no longer launch it just to shrink the 'members' SLRU. There's no wraparound danger with 'members' anymore, so it's no worse than if a user table becomes very bloated. We do still adjust the freeze threshold though, so that if autovacuum runs, whether on schedule or as an emergency autovacuum to avoid wraparound, it will freeze more aggressively if the members SLRU is large. I removed the mention of the 4 billion member threshold, even though that still exists, because the explanation felt misleading. The aggressiveness is scaled proportionally between 2 and 4 billion members. At 4 billion it's as aggressive as it gets, but there's no sudden cliff. In the passing, fix some comments. Remove obsolete mention of safe threshold for member storage triggering autovacuum. Secondly, the freezing cutoff is adjusted to avoid the *members* SLRU from growing too large. Reported-by: Noah Misch Discussion: https://www.postgresql.org/message-id/20260827231757.78.noahmisch@microsoft.com Backpatch-through: 19 --- doc/src/sgml/maintenance.sgml | 17 +++++++---------- src/backend/access/transam/multixact.c | 6 ++---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index 17a306b172c..c941cc34ba7 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -788,8 +788,8 @@ HINT: Execute a database-wide VACUUM in that database. 32-bit counter and corresponding storage, all of which requires careful aging management, storage cleanup, and wraparound handling. There is a separate storage area which holds the list of members in - each multixact, which also uses a 32-bit counter and which must also - be managed. The system function + each multixact, which cannot wrap around but must also be managed + to keep disk usage under control. The system function pg_get_multixact_members() described in can be used to examine the transaction IDs associated with a multixact ID. @@ -823,16 +823,13 @@ HINT: Execute a database-wide VACUUM in that database. As a safety device, an aggressive vacuum scan will occur for any table whose multixact-age is greater than . Also, if the number - of multixact member entries created exceeds approximately 2 billion - entries (occupying roughly 10GB in the + linkend="guc-autovacuum-multixact-freeze-max-age"/>. The aggressive + scans will occur even if autovacuum is nominally disabled. Also, if + the number of multixact member entries created exceeds approximately + 2 billion entries (occupying roughly 10GB in the pg_multixact/members directory), aggressive vacuum scans will occur more often for all tables, starting with those that - have the oldest multixact-age. Both of these kinds of aggressive - scans will occur even if autovacuum is nominally disabled. At approximately - 4 billion entries (occupying roughly 20GB in the - pg_multixact/members directory), even more aggressive - vacuum scans are triggered to reclaim member storage space. + have the oldest multixact-age. diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index e780522e444..f254f0028c1 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -997,9 +997,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset) * against catastrophic data loss due to multixact wraparound. The basic * rules are: * - * If we're past multiVacLimit or the safe threshold for member storage - * space, or we don't know what the safe threshold for member storage is, - * start trying to force autovacuum cycles. + * If we're past multiVacLimit, start trying to force autovacuum cycles. * If we're past multiWarnLimit, start issuing warnings. * If we're past multiStopLimit, refuse to create new MultiXactIds. * @@ -2167,7 +2165,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid) * Offsets are 64-bits wide and never wrap around, so we don't need to * consider them for emergency autovacuum purposes. But now that we're in * a consistent state, determine MultiXactState->oldestOffset. It will be - * used to adjust the freezing cutoff, to keep the offsets disk usage in + * used to adjust the freezing cutoff, to keep the members disk usage in * check. */ SetOldestOffset();