public inbox for [email protected]  
help / color / mirror / Atom feed
enhance wraparound warnings
18+ messages / 6 participants
[nested] [flat]

* enhance wraparound warnings
@ 2025-11-14 17:05  Nathan Bossart <[email protected]>
  0 siblings, 2 replies; 18+ messages in thread

From: Nathan Bossart @ 2025-11-14 17:05 UTC (permalink / raw)
  To: pgsql-hackers

varsup.c has the following comment:

	/*
	 * We'll start complaining loudly when we get within 40M transactions of
	 * data loss.  This is kind of arbitrary, but if you let your gas gauge
	 * get down to 2% of full, would you be looking for the next gas station?
	 * We need to be fairly liberal about this number because there are lots
	 * of scenarios where most transactions are done by automatic clients that
	 * won't pay attention to warnings.  (No, we're not gonna make this
	 * configurable.  If you know enough to configure it, you know enough to
	 * not get in this kind of trouble in the first place.)
	 */

I don't know about you, but I start getting antsy around a quarter tank.
In any case, I'm told that even 40M transactions aren't enough time to
react these days.  Attached are a few patches to enhance the wraparound
warnings.

* 0001 adds a "percent remaining" detail message to the existing WARNING.
The idea is that "1.86% of transaction IDs" is both easier to understand
and better indicates urgency than "39985967 transactions".

* 0002 bumps the warning limit from 40M to 100M to give folks some more
time to react.

* 0003 adds an early warning system for when fewer than 500M transactions
remain.  This system sends a LOG only to the server log every 1M
transactions.  The hope is that this gets someone's attention sooner
without flooding the application and server log.

Thoughts?

-- 
nathan


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2025-12-11 20:28  Nathan Bossart <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 1 reply; 18+ messages in thread

From: Nathan Bossart @ 2025-12-11 20:28 UTC (permalink / raw)
  To: pgsql-hackers

rebased

-- 
nathan


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2025-12-12 02:59  Chao Li <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Chao Li @ 2025-12-12 02:59 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: pgsql-hackers

Hi Nathan,

I just reviewed the patch. My comments are mainly in 0001, and a few nits on 0003. For 0002, the code change is quite straightforward, I am not sure the value bumping to has been discussed.

> On Dec 12, 2025, at 04:28, Nathan Bossart <[email protected]> wrote:
> 
> rebased
> 
> -- 
> nathan
> <v2-0001-Add-percentage-of-transaction-IDs-that-are-availa.patch><v2-0002-Bump-transaction-ID-limit-to-warn-at-100M.patch><v2-0003-Perodically-emit-server-logs-when-fewer-than-500M.patch>

1 - 0001
```
+								   (double) (multiWrapLimit - result) / PG_INT32_MAX * 100),
```

I don’t feel good with using PG_INT32_MAX as denominator, though the value is correct.

Looking at the code of how xidWrapLimit is calculated:
```
	/*
	 * The place where we actually get into deep trouble is halfway around
	 * from the oldest potentially-existing XID.  (This calculation is
	 * probably off by one or two counts, because the special XIDs reduce the
	 * size of the loop a little bit.  But we throw in plenty of slop below,
	 * so it doesn't matter.)
	 */
	xidWrapLimit = oldest_datfrozenxid + (MaxTransactionId >> 1);
	if (xidWrapLimit < FirstNormalTransactionId)
		xidWrapLimit += FirstNormalTransactionId;
```

Where "(MaxTransactionId >> 1)” has the same value as PG_INT32_MAX. But if one day xid is changed to 64 bits, that code doesn’t need to updated, while these patched code will need to be updated.

So, can we define a const in transom.h like:
```
#define MaxTransactionId ((TransactionId) 0xFFFFFFFF)
#define WrapAroundWindow (MaxTransactionId>>1)
```

And use WrapAroundWindow in all places.

2 - 0001
```
+						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
```

“%.2f%%” shows only 2 digits after dot. xidWrapLimit is roughly 2B, when remaining goes down to 107374, it will shows “0.00%”. IMO, when remaining is a large number, percentage makes more sense, while an exact number is clearer when the number is relatively small. So, can we show both percentage and exact number? Or shows the exact number when percentage is 0.00%?

3 - 0001
```
 <programlisting>
 WARNING:  database "mydb" must be vacuumed within 39985967 transactions
+DETAIL:  Approximately 1.86% of transactions IDs are available for use.
```

Typo: " transactions IDs” => " transaction IDs"

4 - 0003
```
Subject: [PATCH v2 3/3] Perodically emit server logs when fewer than 500M
```

Typo: Perodically => Periodically

5 - 0003
```
+	xidLogLimit = xidWrapLimit - 500000000;
```

Instead of hardcode 500M, do we want to consider autovacuum_freeze_max_age? If a deployment sets autovacuum_freeze_max_age > 500M, then vacuum would be triggered first, then this log can get kinda non-intuitive. But if a vacuum cannot freeze anything tuple, then this log will still make sense. I am not sure. Maybe not a real problem.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/









^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2025-12-12 19:19  Nathan Bossart <[email protected]>
  parent: Chao Li <[email protected]>
  0 siblings, 0 replies; 18+ messages in thread

From: Nathan Bossart @ 2025-12-12 19:19 UTC (permalink / raw)
  To: Chao Li <[email protected]>; +Cc: pgsql-hackers

On Fri, Dec 12, 2025 at 10:59:53AM +0800, Chao Li wrote:
> I just reviewed the patch. My comments are mainly in 0001, and a few nits
> on 0003. For 0002, the code change is quite straightforward, I am not
> sure the value bumping to has been discussed.

Thanks!

> Where "(MaxTransactionId >> 1)” has the same value as PG_INT32_MAX. But
> if one day xid is changed to 64 bits, that code doesn’t need to updated,
> while these patched code will need to be updated.
> 
> So, can we define a const in transom.h like:
> ```
> #define MaxTransactionId ((TransactionId) 0xFFFFFFFF)
> #define WrapAroundWindow (MaxTransactionId>>1)
> ```
> 
> And use WrapAroundWindow in all places.

I think I'd rather just open-code the (MaxTransactionId / 2) here.  I'm not
too concerned about 64-bit transaction IDs (there's a lot more than this to
change for that), but it does seem like a good idea to be consistent with
nearby code.

> ```
> +						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
> ```
> 
> “%.2f%%” shows only 2 digits after dot. xidWrapLimit is roughly 2B, when
> remaining goes down to 107374, it will shows “0.00%”. IMO, when remaining
> is a large number, percentage makes more sense, while an exact number is
> clearer when the number is relatively small. So, can we show both
> percentage and exact number? Or shows the exact number when percentage is
> 0.00%?

The errmsg part should already show the exact number of IDs remaining.

> ```
> +	xidLogLimit = xidWrapLimit - 500000000;
> ```
> 
> Instead of hardcode 500M, do we want to consider
> autovacuum_freeze_max_age? If a deployment sets autovacuum_freeze_max_age
> > 500M, then vacuum would be triggered first, then this log can get kinda
> non-intuitive. But if a vacuum cannot freeze anything tuple, then this
> log will still make sense. I am not sure. Maybe not a real problem.

IMHO we should still emit warnings about imminent wraparound even if
autovacuum_freeze_max_age is set to totally-inadvisable values.  I think
the behavior you are describing only happens if users set it to north of
1.6B.

-- 
nathan


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-03-03 20:31  Nathan Bossart <[email protected]>
  parent: Nathan Bossart <[email protected]>
  1 sibling, 1 reply; 18+ messages in thread

From: Nathan Bossart @ 2026-03-03 20:31 UTC (permalink / raw)
  To: Shinya Kato <[email protected]>; +Cc: pgsql-hackers

On Wed, Feb 18, 2026 at 04:16:16PM +0900, Shinya Kato wrote:
> On Sat, Nov 15, 2025 at 2:05 AM Nathan Bossart <[email protected]> wrote:
>> I don't know about you, but I start getting antsy around a quarter tank.
>> In any case, I'm told that even 40M transactions aren't enough time to
>> react these days.  Attached are a few patches to enhance the wraparound
>> warnings.
> 
> Thank you for the patch!

Thanks for reviewing.

> I don't have a strong opinion on whether 100M is the right value, but
> I noticed a documentation issue in 0002.
> 
> <programlisting>
> WARNING:  database "mydb" must be vacuumed within 39985967 transactions
> DETAIL:  Approximately 1.86% of transaction IDs are available for use.
> HINT:  To avoid XID assignment failures, execute a database-wide
> VACUUM in that database.
> </programlisting>
> 
> In maintenance.sgml, above "39985967" and "1.86%" should be updated.

Fixed.

> I'm not sure 0003 is worth the added complexity. It adds a new field
> to TransamVariablesData and a modulo check in GetNewTransactionId(),
> which is a hot path. DBAs who need early warning can already monitor
> age(datfrozenxid) with more flexible thresholds.

Yeah, looking at this one again, I'm less sure it's worth pursuing.  I've
removed it.

-- 
nathan


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-03-06 22:15  Nathan Bossart <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Nathan Bossart @ 2026-03-06 22:15 UTC (permalink / raw)
  To: Shinya Kato <[email protected]>; +Cc: pgsql-hackers

Barring additional feedback or objections, I'm planning to commit this in
the next week or two.

-- 
nathan





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-03-09 12:08  wenhui qiu <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: wenhui qiu @ 2026-03-09 12:08 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Shinya Kato <[email protected]>; pgsql-hackers

Hi Nathan Bossart
> Barring additional feedback or objections, I'm planning to commit this in
> the next week or two.
Thank you for working on this. The path LGTM,But I have a small request,There
are many reasons why the table's age can’t be frozen. Now have a path that
can report the reason to users(https://commitfest.postgresql.org/patch/6188/).
Would you be interested in reviewing it? I think we should tell users the
root cause of why the age can’t be reduced, so they can clearly understand
where the issue is.I think we should not only tell users that the XID is
close to wraparound, but also report why this causes the table‘s age to be
unable to freeze.


Thanks

On Sat, Mar 7, 2026 at 6:15 AM Nathan Bossart <[email protected]>
wrote:

> Barring additional feedback or objections, I'm planning to commit this in
> the next week or two.
>
> --
> nathan
>
>
>


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-03-20 19:16  Nathan Bossart <[email protected]>
  parent: wenhui qiu <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Nathan Bossart @ 2026-03-20 19:16 UTC (permalink / raw)
  To: wenhui qiu <[email protected]>; +Cc: Shinya Kato <[email protected]>; pgsql-hackers

On Mon, Mar 09, 2026 at 08:08:54PM +0800, wenhui qiu wrote:
> Thank you for working on this. The path LGTM,...

Thanks for looking.  Committed.

> ...But I have a small request,There
> are many reasons why the table's age can’t be frozen. Now have a path that
> can report the reason to users(https://commitfest.postgresql.org/patch/6188/).
> Would you be interested in reviewing it? I think we should tell users the
> root cause of why the age can’t be reduced, so they can clearly understand
> where the issue is.I think we should not only tell users that the XID is
> close to wraparound, but also report why this causes the table‘s age to be
> unable to freeze.

Thanks for alerting me to this patch.

-- 
nathan





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-19 18:13  Fujii Masao <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Fujii Masao @ 2026-06-19 18:13 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

On Sat, Mar 21, 2026 at 4:16 AM Nathan Bossart <[email protected]> wrote:
>
> On Mon, Mar 09, 2026 at 08:08:54PM +0800, wenhui qiu wrote:
> > Thank you for working on this. The path LGTM,...
>
> Thanks for looking.  Committed.

Thanks for working on this feature! I have one comment.

ereport(WARNING,
  (errmsg("database \"%s\" must be vacuumed within %u transactions",
  oldest_datname,
  xidWrapLimit - xid),
+ errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+    (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
  errhint("To avoid transaction ID assignment failures, 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.")));

The new DETAIL messages for XID and MultiXactId wraparound warnings
seem misleading.

The percentage is calculated as (xidWrapLimit - xid) divided by half
of the ID space. This represents the remaining ID space before wraparound,
not the percentage of IDs that are still available for use. Since
PostgreSQL stops assigning new XIDs/MultiXactIds at the stop limit
before reaching the wraparound limit, the current wording could be
interpreted as overstating how many IDs remain usable.

So, how about changing the wording to match the calculation? For example:

    Approximately XX.XX% of transaction ID space remains before wraparound.

and similarly for MultiXactIds.

Regards,

-- 
Fujii Masao


Attachments:

  [application/octet-stream] v1-0001-Clarify-wraparound-warning-percentage-messages.patch (7.2K, ../../CAHGQGwHWZTsR6bjdfpa+pOkBPjoXXm2LuJ+5nh+CvdyqEASHcQ@mail.gmail.com/2-v1-0001-Clarify-wraparound-warning-percentage-messages.patch)
  download | inline diff:
From 37d758c78186e6848026a659ca1b35f94c49c248 Mon Sep 17 00:00:00 2001
From: "masao.fujii" <[email protected]'s-MacBook-Pro>
Date: Sat, 20 Jun 2026 02:33:37 +0900
Subject: [PATCH v1] Clarify wraparound warning percentage messages

Commit e646450e609 added DETAIL messages for XID and MultiXactId
wraparound warnings describing the reported percentage as the IDs
available for use. However, the percentage is actually calculated from
the remaining distance to the wraparound limit, not the stop limit
where new IDs are refused. As a result, the wording could be
misinterpreted as meaning that the reported percentage of IDs can still
be allocated.

Update the wording to clarify that the reported percentage represents
the remaining ID space before wraparound.
---
 doc/src/sgml/maintenance.sgml          | 2 +-
 src/backend/access/transam/multixact.c | 8 ++++----
 src/backend/access/transam/varsup.c    | 8 ++++----
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index e341f165efd..a5a779e2e62 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -674,7 +674,7 @@ SELECT datname, age(datfrozenxid) FROM pg_database;
 
 <programlisting>
 WARNING:  database "mydb" must be vacuumed within 99985967 transactions
-DETAIL:  Approximately 4.66% of transaction IDs are available for use.
+DETAIL:  Approximately 4.66% of transaction ID space remains before wraparound.
 HINT:  To avoid XID assignment failures, execute a database-wide VACUUM in that database.
 </programlisting>
 
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 10cbc0d76bd..079f5967e74 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1070,7 +1070,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 									   multiWrapLimit - result,
 									   oldest_datname,
 									   multiWrapLimit - result),
-						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+						 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 								   (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
 						 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.")));
@@ -1081,7 +1081,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 									   multiWrapLimit - result,
 									   oldest_datoid,
 									   multiWrapLimit - result),
-						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+						 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 								   (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
 						 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.")));
@@ -2208,7 +2208,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 								   multiWrapLimit - curMulti,
 								   oldest_datname,
 								   multiWrapLimit - curMulti),
-					 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+					 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 							   (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
 					 errhint("To avoid MultiXactId assignment failures, 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.")));
@@ -2219,7 +2219,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 								   multiWrapLimit - curMulti,
 								   oldest_datoid,
 								   multiWrapLimit - curMulti),
-					 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+					 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 							   (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
 					 errhint("To avoid MultiXactId assignment failures, 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.")));
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index dc5e32d86f3..e0b280665cf 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -166,7 +166,7 @@ GetNewTransactionId(bool isSubXact)
 						(errmsg("database \"%s\" must be vacuumed within %u transactions",
 								oldest_datname,
 								xidWrapLimit - xid),
-						 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+						 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 								   (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
 						 errhint("To avoid transaction ID assignment failures, 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.")));
@@ -175,7 +175,7 @@ GetNewTransactionId(bool isSubXact)
 						(errmsg("database with OID %u must be vacuumed within %u transactions",
 								oldest_datoid,
 								xidWrapLimit - xid),
-						 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+						 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 								   (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
 						 errhint("To avoid XID assignment failures, 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.")));
@@ -485,7 +485,7 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
 					(errmsg("database \"%s\" must be vacuumed within %u transactions",
 							oldest_datname,
 							xidWrapLimit - curXid),
-					 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+					 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 							   (double) (xidWrapLimit - curXid) / (MaxTransactionId / 2) * 100),
 					 errhint("To avoid XID assignment failures, 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.")));
@@ -494,7 +494,7 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
 					(errmsg("database with OID %u must be vacuumed within %u transactions",
 							oldest_datoid,
 							xidWrapLimit - curXid),
-					 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+					 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 							   (double) (xidWrapLimit - curXid) / (MaxTransactionId / 2) * 100),
 					 errhint("To avoid XID assignment failures, 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.")));
-- 
2.53.0



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-19 18:43  Nathan Bossart <[email protected]>
  parent: Fujii Masao <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Nathan Bossart @ 2026-06-19 18:43 UTC (permalink / raw)
  To: Fujii Masao <[email protected]>; +Cc: wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

On Sat, Jun 20, 2026 at 03:13:23AM +0900, Fujii Masao wrote:
> The percentage is calculated as (xidWrapLimit - xid) divided by half
> of the ID space. This represents the remaining ID space before wraparound,
> not the percentage of IDs that are still available for use. Since
> PostgreSQL stops assigning new XIDs/MultiXactIds at the stop limit
> before reaching the wraparound limit, the current wording could be
> interpreted as overstating how many IDs remain usable.
> 
> So, how about changing the wording to match the calculation? For example:
> 
>     Approximately XX.XX% of transaction ID space remains before wraparound.
> 
> and similarly for MultiXactIds.

That seems reasonable to me, thanks.

-- 
nathan






^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-20 11:54  Fujii Masao <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Fujii Masao @ 2026-06-20 11:54 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

On Sat, Jun 20, 2026 at 3:43 AM Nathan Bossart <[email protected]> wrote:
>
> On Sat, Jun 20, 2026 at 03:13:23AM +0900, Fujii Masao wrote:
> > The percentage is calculated as (xidWrapLimit - xid) divided by half
> > of the ID space. This represents the remaining ID space before wraparound,
> > not the percentage of IDs that are still available for use. Since
> > PostgreSQL stops assigning new XIDs/MultiXactIds at the stop limit
> > before reaching the wraparound limit, the current wording could be
> > interpreted as overstating how many IDs remain usable.
> >
> > So, how about changing the wording to match the calculation? For example:
> >
> >     Approximately XX.XX% of transaction ID space remains before wraparound.
> >
> > and similarly for MultiXactIds.
>
> That seems reasonable to me, thanks.

Thanks for the review!

While reading the related log messages again, I noticed that in three of
the four XID wraparound warnings in varsup.c, the HINT still uses "XID"
while the DETAIL message uses "transaction ID". Commit edee0c621de
updated the remaining warning to use "transaction ID",
but seems to have missed the other three. Since using different terms
for the same thing in the DETAIL and HINT messages seems
inconsistent, I included the following changes in the patch. Or would
it be better to do this in a separate patch?

- errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+ errdetail("Approximately %.2f%% of transaction ID space remains
before wraparound.",
     (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
- errhint("To avoid XID assignment failures, execute a database-wide
VACUUM in that database.\n"
+ errhint("To avoid transaction ID assignment failures, execute a
database-wide VACUUM in that database.\n"

I also updated the comments in
src/test/modules/xid_wraparound/t/002_limits.pl, which contain
examples of the XID wraparound warnings.

Attached is the updated patch.


While making these changes, I also noticed that although commit
edee0c621de updated the runtime XID wraparound messages to use
"transaction IDs", the corresponding examples and text in
maintenance.sgml still use the older "XID" terminology. I therefore
created an additional patch (0002) to update the documentation to
match the current messages. I think this should be backpatched to v17.

Thought?

Regards,

-- 
Fujii Masao


Attachments:

  [application/octet-stream] v2-0001-Clarify-wraparound-warning-percentage-messages.patch (8.5K, ../../CAHGQGwHTN-Xc5iDtbzNSjfxuab5Y9qAArw8cB4PrrDJpZ+1fgA@mail.gmail.com/2-v2-0001-Clarify-wraparound-warning-percentage-messages.patch)
  download | inline diff:
From 011fa9d25af818d79c22b7159c3788dd294a1b09 Mon Sep 17 00:00:00 2001
From: "masao.fujii" <[email protected]'s-MacBook-Pro>
Date: Sat, 20 Jun 2026 19:49:58 +0900
Subject: [PATCH v2 1/2] Clarify wraparound warning percentage messages

Commit e646450e609 added DETAIL messages for XID and MultiXactId
wraparound warnings describing the reported percentage as the IDs
available for use. However, the percentage is actually calculated from
the remaining distance to the wraparound limit, not the stop limit
where new IDs are refused. As a result, the wording could be
misinterpreted as meaning that the reported percentage of IDs can still
be allocated.

Update the wording to clarify that the reported percentage represents
the remaining ID space before wraparound.

Also update the related XID warning hints to use "transaction ID"
terminology consistently.
---
 doc/src/sgml/maintenance.sgml                   |  2 +-
 src/backend/access/transam/multixact.c          |  8 ++++----
 src/backend/access/transam/varsup.c             | 14 +++++++-------
 src/test/modules/xid_wraparound/t/002_limits.pl |  3 ++-
 4 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index e341f165efd..a5a779e2e62 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -674,7 +674,7 @@ SELECT datname, age(datfrozenxid) FROM pg_database;
 
 <programlisting>
 WARNING:  database "mydb" must be vacuumed within 99985967 transactions
-DETAIL:  Approximately 4.66% of transaction IDs are available for use.
+DETAIL:  Approximately 4.66% of transaction ID space remains before wraparound.
 HINT:  To avoid XID assignment failures, execute a database-wide VACUUM in that database.
 </programlisting>
 
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 10cbc0d76bd..079f5967e74 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1070,7 +1070,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 									   multiWrapLimit - result,
 									   oldest_datname,
 									   multiWrapLimit - result),
-						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+						 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 								   (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
 						 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.")));
@@ -1081,7 +1081,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 									   multiWrapLimit - result,
 									   oldest_datoid,
 									   multiWrapLimit - result),
-						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+						 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 								   (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
 						 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.")));
@@ -2208,7 +2208,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 								   multiWrapLimit - curMulti,
 								   oldest_datname,
 								   multiWrapLimit - curMulti),
-					 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+					 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 							   (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
 					 errhint("To avoid MultiXactId assignment failures, 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.")));
@@ -2219,7 +2219,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 								   multiWrapLimit - curMulti,
 								   oldest_datoid,
 								   multiWrapLimit - curMulti),
-					 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+					 errdetail("Approximately %.2f%% of MultiXactId space remains before wraparound.",
 							   (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
 					 errhint("To avoid MultiXactId assignment failures, 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.")));
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index dc5e32d86f3..cb68d8fa974 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -166,7 +166,7 @@ GetNewTransactionId(bool isSubXact)
 						(errmsg("database \"%s\" must be vacuumed within %u transactions",
 								oldest_datname,
 								xidWrapLimit - xid),
-						 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+						 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 								   (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
 						 errhint("To avoid transaction ID assignment failures, 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.")));
@@ -175,9 +175,9 @@ GetNewTransactionId(bool isSubXact)
 						(errmsg("database with OID %u must be vacuumed within %u transactions",
 								oldest_datoid,
 								xidWrapLimit - xid),
-						 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+						 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 								   (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
-						 errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
+						 errhint("To avoid transaction ID assignment failures, 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.")));
 		}
 
@@ -485,18 +485,18 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
 					(errmsg("database \"%s\" must be vacuumed within %u transactions",
 							oldest_datname,
 							xidWrapLimit - curXid),
-					 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+					 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 							   (double) (xidWrapLimit - curXid) / (MaxTransactionId / 2) * 100),
-					 errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
+					 errhint("To avoid transaction ID assignment failures, 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.")));
 		else
 			ereport(WARNING,
 					(errmsg("database with OID %u must be vacuumed within %u transactions",
 							oldest_datoid,
 							xidWrapLimit - curXid),
-					 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+					 errdetail("Approximately %.2f%% of transaction ID space remains before wraparound.",
 							   (double) (xidWrapLimit - curXid) / (MaxTransactionId / 2) * 100),
-					 errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
+					 errhint("To avoid transaction ID assignment failures, 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.")));
 	}
 }
diff --git a/src/test/modules/xid_wraparound/t/002_limits.pl b/src/test/modules/xid_wraparound/t/002_limits.pl
index 86632a8d510..29d071a677b 100644
--- a/src/test/modules/xid_wraparound/t/002_limits.pl
+++ b/src/test/modules/xid_wraparound/t/002_limits.pl
@@ -70,7 +70,8 @@ $node->safe_psql('postgres',
 # the warning:
 #
 #  WARNING:  database "postgres" must be vacuumed within 3000024 transactions
-#  HINT:  To avoid a database shutdown, execute a database-wide VACUUM in that database.
+#  DETAIL:  Approximately 0.14% of transaction ID space remains before wraparound.
+#  HINT:  To avoid transaction ID assignment failures, execute a database-wide VACUUM in that database.
 #  You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
 my $stderr;
 my $warn_limit = 0;
-- 
2.53.0



  [application/octet-stream] v2-0002-doc-Update-wraparound-examples-to-say-transaction.patch (2.2K, ../../CAHGQGwHTN-Xc5iDtbzNSjfxuab5Y9qAArw8cB4PrrDJpZ+1fgA@mail.gmail.com/3-v2-0002-doc-Update-wraparound-examples-to-say-transaction.patch)
  download | inline diff:
From 6d1a0eb207cca2e70516fdffb60be7689ba4b8d7 Mon Sep 17 00:00:00 2001
From: "masao.fujii" <[email protected]'s-MacBook-Pro>
Date: Sat, 20 Jun 2026 19:50:03 +0900
Subject: [PATCH v2 2/2] doc: Update wraparound examples to say transaction IDs

Commit edee0c621de changed the runtime XID wraparound messages to
use "transaction IDs" terminology, but the corresponding
examples and text in maintenance.sgml still used the older XID wording.

Update those documentation examples into line with the current runtime
messages.

Backpatch to v17, where the runtime messages were changed.
---
 doc/src/sgml/maintenance.sgml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index a5a779e2e62..8043fb36625 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -675,18 +675,18 @@ SELECT datname, age(datfrozenxid) FROM pg_database;
 <programlisting>
 WARNING:  database "mydb" must be vacuumed within 99985967 transactions
 DETAIL:  Approximately 4.66% of transaction ID space remains before wraparound.
-HINT:  To avoid XID assignment failures, execute a database-wide VACUUM in that database.
+HINT:  To avoid transaction ID assignment failures, execute a database-wide VACUUM in that database.
 </programlisting>
 
     (A manual <command>VACUUM</command> should fix the problem, as suggested by the
     hint; but note that the <command>VACUUM</command> should be performed by a
     superuser, else it will fail to process system catalogs, which prevent it from
     being able to advance the database's <structfield>datfrozenxid</structfield>.)
-    If these warnings are ignored, the system will refuse to assign new XIDs once
+    If these warnings are ignored, the system will refuse to assign new transaction IDs once
     there are fewer than three million transactions left until wraparound:
 
 <programlisting>
-ERROR:  database is not accepting commands that assign new XIDs to avoid wraparound data loss in database "mydb"
+ERROR:  database is not accepting commands that assign new transaction IDs to avoid wraparound data loss in database "mydb"
 HINT:  Execute a database-wide VACUUM in that database.
 </programlisting>
 
-- 
2.53.0



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-24 04:47  Bharath Rupireddy <[email protected]>
  parent: Fujii Masao <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Bharath Rupireddy @ 2026-06-24 04:47 UTC (permalink / raw)
  To: Fujii Masao <[email protected]>; +Cc: Nathan Bossart <[email protected]>; wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

Hi,

On Sat, Jun 20, 2026 at 4:54 AM Fujii Masao <[email protected]> wrote:
>
> While making these changes, I also noticed that although commit
> edee0c621de updated the runtime XID wraparound messages to use
> "transaction IDs", the corresponding examples and text in
> maintenance.sgml still use the older "XID" terminology. I therefore
> created an additional patch (0002) to update the documentation to
> match the current messages. I think this should be backpatched to v17.
>
> Thought?

I happened to quickly review these patches. TBH, "transaction ID
space" and "MultiXactId space" seem a bit confusing because of the
word "space" - it reads fine without it. Is there a specific reason
for this wording?

Also, why not use "multixact IDs" instead of "MultiXactId"? The latter
reads like an internal structure name or such that might confuse users
reading the docs or error messages.

How about something like the following?

+ errdetail("Approximately %.2f%% of multixact IDs remain before wraparound.",
+ errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",

-- 
Bharath Rupireddy
Amazon Web Services: https://aws.amazon.com






^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-24 12:53  Fujii Masao <[email protected]>
  parent: Bharath Rupireddy <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Fujii Masao @ 2026-06-24 12:53 UTC (permalink / raw)
  To: Bharath Rupireddy <[email protected]>; +Cc: Nathan Bossart <[email protected]>; wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

On Wed, Jun 24, 2026 at 1:47 PM Bharath Rupireddy
<[email protected]> wrote:
> I happened to quickly review these patches.

Thanks for the review!


> TBH, "transaction ID
> space" and "MultiXactId space" seem a bit confusing because of the
> word "space" - it reads fine without it. Is there a specific reason
> for this wording?

I was thinking "space" was appropriate here because the message is intended
to express the percentage remaining before wraparound in the ID range.
The documentation also uses expressions such as "normal XID space is ...".

But I'm not a native English speaker, so this wording might be wrong.


> Also, why not use "multixact IDs" instead of "MultiXactId"? The latter
> reads like an internal structure name or such that might confuse users
> reading the docs or error messages.

I left "MultiXactId" unchanged because several existing log messages
use that term. I don't have any strong objection to changing it to
"multixact ID", which is already used in the documentation. However, if
we do that, I think it's better update all log messages that use
"MultiXactId" for consistency, probably as a separate patch. That seems
more like a v20 item to me, though.

Regards,

-- 
Fujii Masao






^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-25 17:19  Bharath Rupireddy <[email protected]>
  parent: Fujii Masao <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Bharath Rupireddy @ 2026-06-25 17:19 UTC (permalink / raw)
  To: Fujii Masao <[email protected]>; +Cc: Nathan Bossart <[email protected]>; wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

Hi,

On Wed, Jun 24, 2026 at 5:53 AM Fujii Masao <[email protected]> wrote:
>
> > TBH, "transaction ID
> > space" and "MultiXactId space" seem a bit confusing because of the
> > word "space" - it reads fine without it. Is there a specific reason
> > for this wording?
>
> I was thinking "space" was appropriate here because the message is intended
> to express the percentage remaining before wraparound in the ID range.
> The documentation also uses expressions such as "normal XID space is ...".

The use there is referring to the whole set of transaction IDs and how
one can visualize the use of them - so "XID space" in that context
seems fine to me.

But the wraparound warnings read better when they say how many more
transaction IDs are left:

+ errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
+ errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",

> > Also, why not use "multixact IDs" instead of "MultiXactId"? The latter
> > reads like an internal structure name or such that might confuse users
> > reading the docs or error messages.
>
> I left "MultiXactId" unchanged because several existing log messages
> use that term. I don't have any strong objection to changing it to
> "multixact ID", which is already used in the documentation. However, if
> we do that, I think it's better update all log messages that use
> "MultiXactId" for consistency, probably as a separate patch. That seems
> more like a v20 item to me, though.

I'm fine to leave "MultiXactIds" as-is - IMHO, it's not worth the cycles.

--
Bharath Rupireddy
Amazon Web Services: https://aws.amazon.com





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-26 00:51  Fujii Masao <[email protected]>
  parent: Bharath Rupireddy <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Fujii Masao @ 2026-06-26 00:51 UTC (permalink / raw)
  To: Bharath Rupireddy <[email protected]>; +Cc: Nathan Bossart <[email protected]>; wenhui qiu <[email protected]>; Shinya Kato <[email protected]>; pgsql-hackers

On Fri, Jun 26, 2026 at 2:19 AM Bharath Rupireddy
<[email protected]> wrote:
> The use there is referring to the whole set of transaction IDs and how
> one can visualize the use of them - so "XID space" in that context
> seems fine to me.
>
> But the wraparound warnings read better when they say how many more
> transaction IDs are left:
>
> + errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
> + errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",

Okay, I've updated the patches as suggested. The updated patches are attached.

Regards,

-- 
Fujii Masao


Attachments:

  [application/octet-stream] v3-0001-Clarify-wraparound-warning-percentage-messages.patch (8.4K, ../../CAHGQGwHHPzYw2qbtwdkmyC+3pLW1aT1p6gUKx4WWhANiJhob2g@mail.gmail.com/2-v3-0001-Clarify-wraparound-warning-percentage-messages.patch)
  download | inline diff:
From 60833ae74d510e6b4f447905da260433f4546569 Mon Sep 17 00:00:00 2001
From: Fujii Masao <[email protected]>
Date: Fri, 26 Jun 2026 09:11:03 +0900
Subject: [PATCH v3 1/2] Clarify wraparound warning percentage messages

Commit e646450e609 added DETAIL messages for XID and MultiXactId
wraparound warnings describing the reported percentage as the IDs
available for use. However, the percentage is actually calculated from
the remaining distance to the wraparound limit, not the stop limit
where new IDs are refused. As a result, the wording could be
misinterpreted as meaning that the reported percentage of IDs can still
be allocated.

Update the wording to clarify that the reported percentage represents
the remaining IDs before wraparound.

Also update the related XID warning hints to use "transaction ID"
terminology consistently.
---
 doc/src/sgml/maintenance.sgml                   |  2 +-
 src/backend/access/transam/multixact.c          |  8 ++++----
 src/backend/access/transam/varsup.c             | 14 +++++++-------
 src/test/modules/xid_wraparound/t/002_limits.pl |  3 ++-
 4 files changed, 14 insertions(+), 13 deletions(-)

diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index e341f165efd..2932ba6a30a 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -674,7 +674,7 @@ SELECT datname, age(datfrozenxid) FROM pg_database;
 
 <programlisting>
 WARNING:  database "mydb" must be vacuumed within 99985967 transactions
-DETAIL:  Approximately 4.66% of transaction IDs are available for use.
+DETAIL:  Approximately 4.66% of transaction IDs remain before wraparound.
 HINT:  To avoid XID assignment failures, execute a database-wide VACUUM in that database.
 </programlisting>
 
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 10cbc0d76bd..7ce615c3eb9 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1070,7 +1070,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 									   multiWrapLimit - result,
 									   oldest_datname,
 									   multiWrapLimit - result),
-						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+						 errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
 								   (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
 						 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.")));
@@ -1081,7 +1081,7 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
 									   multiWrapLimit - result,
 									   oldest_datoid,
 									   multiWrapLimit - result),
-						 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+						 errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
 								   (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
 						 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.")));
@@ -2208,7 +2208,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 								   multiWrapLimit - curMulti,
 								   oldest_datname,
 								   multiWrapLimit - curMulti),
-					 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+					 errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
 							   (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
 					 errhint("To avoid MultiXactId assignment failures, 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.")));
@@ -2219,7 +2219,7 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
 								   multiWrapLimit - curMulti,
 								   oldest_datoid,
 								   multiWrapLimit - curMulti),
-					 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
+					 errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
 							   (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
 					 errhint("To avoid MultiXactId assignment failures, 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.")));
diff --git a/src/backend/access/transam/varsup.c b/src/backend/access/transam/varsup.c
index dc5e32d86f3..d61fe68210e 100644
--- a/src/backend/access/transam/varsup.c
+++ b/src/backend/access/transam/varsup.c
@@ -166,7 +166,7 @@ GetNewTransactionId(bool isSubXact)
 						(errmsg("database \"%s\" must be vacuumed within %u transactions",
 								oldest_datname,
 								xidWrapLimit - xid),
-						 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+						 errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",
 								   (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
 						 errhint("To avoid transaction ID assignment failures, 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.")));
@@ -175,9 +175,9 @@ GetNewTransactionId(bool isSubXact)
 						(errmsg("database with OID %u must be vacuumed within %u transactions",
 								oldest_datoid,
 								xidWrapLimit - xid),
-						 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+						 errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",
 								   (double) (xidWrapLimit - xid) / (MaxTransactionId / 2) * 100),
-						 errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
+						 errhint("To avoid transaction ID assignment failures, 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.")));
 		}
 
@@ -485,18 +485,18 @@ SetTransactionIdLimit(TransactionId oldest_datfrozenxid, Oid oldest_datoid)
 					(errmsg("database \"%s\" must be vacuumed within %u transactions",
 							oldest_datname,
 							xidWrapLimit - curXid),
-					 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+					 errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",
 							   (double) (xidWrapLimit - curXid) / (MaxTransactionId / 2) * 100),
-					 errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
+					 errhint("To avoid transaction ID assignment failures, 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.")));
 		else
 			ereport(WARNING,
 					(errmsg("database with OID %u must be vacuumed within %u transactions",
 							oldest_datoid,
 							xidWrapLimit - curXid),
-					 errdetail("Approximately %.2f%% of transaction IDs are available for use.",
+					 errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",
 							   (double) (xidWrapLimit - curXid) / (MaxTransactionId / 2) * 100),
-					 errhint("To avoid XID assignment failures, execute a database-wide VACUUM in that database.\n"
+					 errhint("To avoid transaction ID assignment failures, 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.")));
 	}
 }
diff --git a/src/test/modules/xid_wraparound/t/002_limits.pl b/src/test/modules/xid_wraparound/t/002_limits.pl
index 86632a8d510..236bea2588c 100644
--- a/src/test/modules/xid_wraparound/t/002_limits.pl
+++ b/src/test/modules/xid_wraparound/t/002_limits.pl
@@ -70,7 +70,8 @@ $node->safe_psql('postgres',
 # the warning:
 #
 #  WARNING:  database "postgres" must be vacuumed within 3000024 transactions
-#  HINT:  To avoid a database shutdown, execute a database-wide VACUUM in that database.
+#  DETAIL:  Approximately 0.14% of transaction IDs remain before wraparound.
+#  HINT:  To avoid transaction ID assignment failures, execute a database-wide VACUUM in that database.
 #  You might also need to commit or roll back old prepared transactions, or drop stale replication slots.
 my $stderr;
 my $warn_limit = 0;
-- 
2.53.0



  [application/octet-stream] v3-0002-doc-Update-wraparound-examples-to-say-transaction.patch (2.2K, ../../CAHGQGwHHPzYw2qbtwdkmyC+3pLW1aT1p6gUKx4WWhANiJhob2g@mail.gmail.com/3-v3-0002-doc-Update-wraparound-examples-to-say-transaction.patch)
  download | inline diff:
From 27d395abaad4e8d9c2220245e7b5101d5e65b4d6 Mon Sep 17 00:00:00 2001
From: Fujii Masao <[email protected]>
Date: Fri, 26 Jun 2026 08:33:10 +0900
Subject: [PATCH v3 2/2] doc: Update wraparound examples to say transaction IDs

Commit edee0c621de changed the runtime XID wraparound messages to
use "transaction IDs" terminology, but the corresponding
examples and text in maintenance.sgml still used the older XID wording.

Update those documentation examples into line with the current runtime
messages.

Backpatch to v17, where the runtime messages were changed.
---
 doc/src/sgml/maintenance.sgml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/doc/src/sgml/maintenance.sgml b/doc/src/sgml/maintenance.sgml
index 2932ba6a30a..add170e5737 100644
--- a/doc/src/sgml/maintenance.sgml
+++ b/doc/src/sgml/maintenance.sgml
@@ -675,18 +675,18 @@ SELECT datname, age(datfrozenxid) FROM pg_database;
 <programlisting>
 WARNING:  database "mydb" must be vacuumed within 99985967 transactions
 DETAIL:  Approximately 4.66% of transaction IDs remain before wraparound.
-HINT:  To avoid XID assignment failures, execute a database-wide VACUUM in that database.
+HINT:  To avoid transaction ID assignment failures, execute a database-wide VACUUM in that database.
 </programlisting>
 
     (A manual <command>VACUUM</command> should fix the problem, as suggested by the
     hint; but note that the <command>VACUUM</command> should be performed by a
     superuser, else it will fail to process system catalogs, which prevent it from
     being able to advance the database's <structfield>datfrozenxid</structfield>.)
-    If these warnings are ignored, the system will refuse to assign new XIDs once
+    If these warnings are ignored, the system will refuse to assign new transaction IDs once
     there are fewer than three million transactions left until wraparound:
 
 <programlisting>
-ERROR:  database is not accepting commands that assign new XIDs to avoid wraparound data loss in database "mydb"
+ERROR:  database is not accepting commands that assign new transaction IDs to avoid wraparound data loss in database "mydb"
 HINT:  Execute a database-wide VACUUM in that database.
 </programlisting>
 
-- 
2.53.0



^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-26 01:55  Kyotaro Horiguchi <[email protected]>
  parent: Fujii Masao <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Kyotaro Horiguchi @ 2026-06-26 01:55 UTC (permalink / raw)
  To: [email protected]; +Cc: [email protected]; [email protected]; [email protected]; [email protected]; pgsql-hackers

Hello,

At Fri, 26 Jun 2026 09:51:16 +0900, Fujii Masao <[email protected]> wrote in 
> On Fri, Jun 26, 2026 at 2:19 AM Bharath Rupireddy
> <[email protected]> wrote:
> > The use there is referring to the whole set of transaction IDs and how
> > one can visualize the use of them - so "XID space" in that context
> > seems fine to me.
> >
> > But the wraparound warnings read better when they say how many more
> > transaction IDs are left:
> >
> > + errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
> > + errdetail("Approximately %.2f%% of transaction IDs remain before wraparound.",
> 
> Okay, I've updated the patches as suggested. The updated patches are attached.

I'm not sure I'm following this correctly, but the explanation above
sounded to me as if the warning should report the number of IDs
remaining before wraparound, e.g. "Approximately N MultiXactIds remain
before wraparound", so I'm a bit confused by the proposed wording.

> + errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",

The attached patch adopts that wording. However, I'm not sure how to
interpret it. The value is still expressed as a percentage, but it is
no longer clear what that percentage is relative to.

Whichever approach we choose, I think the wording should be explicit.
If the value is reported as a percentage, then something like "x.xx%
of MultiXactId space remains" seems clearer to me. If it is reported
as a count, then "N MultiXactIds remain" would make more sense.

Regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center


^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-26 18:06  Nathan Bossart <[email protected]>
  parent: Kyotaro Horiguchi <[email protected]>
  0 siblings, 1 reply; 18+ messages in thread

From: Nathan Bossart @ 2026-06-26 18:06 UTC (permalink / raw)
  To: Kyotaro Horiguchi <[email protected]>; +Cc: [email protected]; [email protected]; [email protected]; [email protected]; pgsql-hackers

On Fri, Jun 26, 2026 at 10:55:39AM +0900, Kyotaro Horiguchi wrote:
> I'm not sure I'm following this correctly, but the explanation above
> sounded to me as if the warning should report the number of IDs
> remaining before wraparound, e.g. "Approximately N MultiXactIds remain
> before wraparound", so I'm a bit confused by the proposed wording.

We already report the number of IDs remaining in the WARNING message.  In
v19, I've added a DETAIL message that also reports the percentage
remaining, with the hope that it makes the urgency clearer.

>> + errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
> 
> The attached patch adopts that wording. However, I'm not sure how to
> interpret it. The value is still expressed as a percentage, but it is
> no longer clear what that percentage is relative to.
> 
> Whichever approach we choose, I think the wording should be explicit.
> If the value is reported as a percentage, then something like "x.xx%
> of MultiXactId space remains" seems clearer to me. If it is reported
> as a count, then "N MultiXactIds remain" would make more sense.

I find both "percentage of IDs remaining" and "percentage of ID space
remaining" equally clear and have no strong opinion on the matter.

-- 
nathan





^ permalink  raw  reply  [nested|flat] 18+ messages in thread

* Re: enhance wraparound warnings
@ 2026-06-26 22:18  Bharath Rupireddy <[email protected]>
  parent: Nathan Bossart <[email protected]>
  0 siblings, 0 replies; 18+ messages in thread

From: Bharath Rupireddy @ 2026-06-26 22:18 UTC (permalink / raw)
  To: Nathan Bossart <[email protected]>; +Cc: Kyotaro Horiguchi <[email protected]>; [email protected]; [email protected]; [email protected]; pgsql-hackers

Hi,

On Fri, Jun 26, 2026 at 11:06 AM Nathan Bossart
<[email protected]> wrote:
>
> On Fri, Jun 26, 2026 at 10:55:39AM +0900, Kyotaro Horiguchi wrote:
> > I'm not sure I'm following this correctly, but the explanation above
> > sounded to me as if the warning should report the number of IDs
> > remaining before wraparound, e.g. "Approximately N MultiXactIds remain
> > before wraparound", so I'm a bit confused by the proposed wording.
>
> We already report the number of IDs remaining in the WARNING message.  In
> v19, I've added a DETAIL message that also reports the percentage
> remaining, with the hope that it makes the urgency clearer.

Yes. For example: WARNING:  database "mydb" must be vacuumed within
99985967 transactions

> >> + errdetail("Approximately %.2f%% of MultiXactIds remain before wraparound.",
> >
> > The attached patch adopts that wording. However, I'm not sure how to
> > interpret it. The value is still expressed as a percentage, but it is
> > no longer clear what that percentage is relative to.
> >
> > Whichever approach we choose, I think the wording should be explicit.
> > If the value is reported as a percentage, then something like "x.xx%
> > of MultiXactId space remains" seems clearer to me. If it is reported
> > as a count, then "N MultiXactIds remain" would make more sense.
>
> I find both "percentage of IDs remaining" and "percentage of ID space
> remaining" equally clear and have no strong opinion on the matter.

My initial comment was that "IDs remaining" reads more naturally to me
than "ID space remaining," but I'm happy to go with the majority here.
IMHO, no need to spend more cycles on this.

--
Bharath Rupireddy
Amazon Web Services: https://aws.amazon.com






^ permalink  raw  reply  [nested|flat] 18+ messages in thread


end of thread, other threads:[~2026-06-26 22:18 UTC | newest]

Thread overview: 18+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2025-11-14 17:05 enhance wraparound warnings Nathan Bossart <[email protected]>
2025-12-11 20:28 ` Nathan Bossart <[email protected]>
2025-12-12 02:59   ` Chao Li <[email protected]>
2025-12-12 19:19     ` Nathan Bossart <[email protected]>
2026-03-03 20:31 ` Nathan Bossart <[email protected]>
2026-03-06 22:15   ` Nathan Bossart <[email protected]>
2026-03-09 12:08     ` wenhui qiu <[email protected]>
2026-03-20 19:16       ` Nathan Bossart <[email protected]>
2026-06-19 18:13         ` Fujii Masao <[email protected]>
2026-06-19 18:43           ` Nathan Bossart <[email protected]>
2026-06-20 11:54             ` Fujii Masao <[email protected]>
2026-06-24 04:47               ` Bharath Rupireddy <[email protected]>
2026-06-24 12:53                 ` Fujii Masao <[email protected]>
2026-06-25 17:19                   ` Bharath Rupireddy <[email protected]>
2026-06-26 00:51                     ` Fujii Masao <[email protected]>
2026-06-26 01:55                       ` Kyotaro Horiguchi <[email protected]>
2026-06-26 18:06                         ` Nathan Bossart <[email protected]>
2026-06-26 22:18                           ` Bharath Rupireddy <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox