From 84fe025cc5592d7e01ba77b4b2c5eea8d8d5f35d Mon Sep 17 00:00:00 2001 From: "masao.fujii" Date: Thu, 11 Jun 2026 11:18:00 +0900 Subject: [PATCH v1] Refine MultiXact wraparound hints Replication slots can hold back XID horizons, but they do not prevent MultiXact cleanup. Therefore, this commit removes replication slot advice from MultiXact wraparound hint messages and update the maintenance documentation to clarify the distinction. Backpatch to all supported versions. --- doc/src/sgml/maintenance.sgml | 6 ++++++ src/backend/access/transam/multixact.c | 12 ++++++------ src/backend/commands/vacuum.c | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml index d6d44d74069..20552317891 100644 --- a/doc/src/sgml/maintenance.sgml +++ b/doc/src/sgml/maintenance.sgml @@ -820,6 +820,12 @@ HINT: Stop the postmaster and vacuum that database in single-user mode. Running transactions and prepared transactions can be ignored if there is no chance that they might appear in a multixact. + + Unlike transaction ID wraparound, replication slots do not + directly hold back multixact cleanup. Dropping stale replication + slots is therefore not usually relevant to resolving multixact ID + wraparound problems. + MXID information is not directly visible in system views such as pg_stat_activity; however, looking for old XIDs is still a good diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 8408492879b..0778a7c9b80 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -1159,14 +1159,14 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset) errmsg("database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database \"%s\"", oldest_datname), errhint("Execute a database-wide VACUUM in that database.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); + "You might also need to commit or roll back old prepared transactions."))); else ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database with OID %u", oldest_datoid), errhint("Execute a database-wide VACUUM in that database.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); + "You might also need to commit or roll back old prepared transactions."))); } /* @@ -1190,7 +1190,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset) oldest_datname, multiWrapLimit - result), errhint("Execute a database-wide VACUUM in that database.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); + "You might also need to commit or roll back old prepared transactions."))); else ereport(WARNING, (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used", @@ -1199,7 +1199,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset) oldest_datoid, multiWrapLimit - result), errhint("Execute a database-wide VACUUM in that database.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); + "You might also need to commit or roll back old prepared transactions."))); } /* Re-acquire lock and start over */ @@ -2475,7 +2475,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, oldest_datname, multiWrapLimit - curMulti), errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); + "You might also need to commit or roll back old prepared transactions."))); else ereport(WARNING, (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used", @@ -2484,7 +2484,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, oldest_datoid, multiWrapLimit - curMulti), errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n" - "You might also need to commit or roll back old prepared transactions, or drop stale replication slots."))); + "You might also need to commit or roll back old prepared transactions."))); } } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 6c3208eeb84..3185062bf16 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1176,7 +1176,7 @@ vacuum_get_cutoffs(Relation rel, const VacuumParams *params, ereport(WARNING, (errmsg("cutoff for freezing multixacts 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."))); + "You might also need to commit or roll back old prepared transactions."))); /* * Determine the minimum freeze age to use: as specified by the caller, or -- 2.53.0