Thread: Improving the "Routine Vacuuming" docs

Improving the "Routine Vacuuming" docs

From
Peter Geoghegan
Date:
Recent work on VACUUM and relfrozenxid advancement required that I
update the maintenance.sgml VACUUM documentation ("Routine
Vacuuming"). It was tricky to keep things current, due in part to
certain structural problems. Many of these problems are artifacts of
how the document evolved over time.

"Routine Vacuuming" ought to work as a high level description of how
VACUUM keeps the system going over time. The intended audience is
primarily DBAs, so low level implementation details should either be
given much less prominence, or not even mentioned. We should keep it
practical -- without going too far in the direction of assuming that
we know the limits of what information might be useful.

My high level concerns are:

* Instead of discussing FrozenTransactionId (and then explaining how
that particular magic value is not really used anymore anyway), why
not describe freezing in terms of the high level rules?

Something along the lines of the following seems more useful: "A tuple
whose xmin is frozen (and xmax is unset) is considered visible to
every possible MVCC snapshot. In other words, the transaction that
inserted the tuple is treated as if it ran and committed at some point
that is now *infinitely* far in the past."

It might also be useful to describe freezing all of a live tuple's
XIDs as roughly the opposite process as completely physically removing
a dead tuple. It follows that we don't necessarily need to freeze
anything to advance relfrozenxid (especially not on Postgres 15).

* The general description of how the XID space works similarly places
way too much emphasis on low level details that are of very little
relevance.

These details would even seem totally out of place if I was the
intended audience. The problem isn't really that the information is
too technical. The problem is that we emphasize mechanistic stuff
while never quite explaining the point of it all.

Currently, "25.1.5. Preventing Transaction ID Wraparound Failures"
says this, right up-front:

"But since transaction IDs have limited size (32 bits) a cluster that
runs for a long time (more than 4 billion transactions) would suffer
transaction ID wraparound"

This is way too mechanistic. We totally muddle things by even
mentioning 4 billion XIDs in the first place. It seems like a
confusing artefact of a time before freezing was invented, back when
you really could have XIDs that were more than 2 billion XIDs apart.

This statement has another problem: it's flat-out untrue. The
xidStopLimit stuff will reliably kick in at about 2 billion XIDs.

* The description of wraparound sounds terrifying, implying that data
corruption can result.

The alarming language isn't proportionate to the true danger
(something I complained about in a dedicated thread last year [1]).

* XID space isn't really a precious resource -- it isn't even a
resource at all IMV.

ISTM that we should be discussing wraparound as an issue about the
maximum *difference* between any two unfrozen XIDs in a
cluster/installation.

Talking about an abstract-sounding XID space seems to me to be quite
counterproductive. The logical XID space is practically infinite,
after all. We should move away from the idea that physical XID space
is a precious resource. Sure, users are often concerned that the
xidStopLimit mechanism might kick-in, effectively resulting in an
outage. That makes perfect sense. But it doesn't follow that XIDs are
precious, and implying that they are intrinsically valuable just
confuses matters.

First of all, physical XID space is usually abundantly available. A
"distance" of ~2 billion XIDs is a vast distance in just about any
application (barring those with pathological problems, such as a
leaked replication slot). Second of all, Since the amount of physical
freezing required to be able to advance relfrozenxid by any given
amount (amount of XIDs) varies enormously, and is not even predictable
for a given table (because individual tables don't get their own
physical XID space), the age of datfrozenxid predicts very little
about how close we are to having the dreaded xidStopLimit mechanism
kick in. We do need some XID-wise slack, but that's just a way of
absorbing shocks -- it's ballast, usually only really needed for one
or two very large tables.

Third of all, and most importantly, the whole idea that we can just
put off freezing indefinitely and actually reduce the pain (rather
than having a substantial increase in problems) seems to have just
about no basis in reality, at least once you get into the tens of
millions range (though usually well before that).

Why should you be better off if all of your freezing occurs in one big
balloon payment? Sometimes getting into debt for a while is useful,
but why should it make sense to keep delaying freezing? And if it
doesn't make sense, then why does it still make sense to treat XID
space as a precious resource?

* We don't cleanly separate discussion of anti-wraparound autovacuums,
and aggressive vacuums, and the general danger of wraparound (by which
I actually mean the danger of having the xidStopLimit stop limit kick
in).

I think that we should move towards a world in which we explicitly
treat the autovacuum anti-wraparound criteria as not all that
different to any of the standard criteria (so we probably still have
the behavior with autovacuums not being cancellable, but it would be a
dynamic thing that didn't depend on the original reason why
autovacuum.c launched an autovacuum worker). But even now we aren't
clear enough about the fact that anti-wraparound autovacuums really
aren't all that special. Which makes them seem scarier than they
should be.

[1] https://postgr.es/m/CAH2-Wzk_FxfJvs4TnUtj=DCsokbiK0CxfjZ9jjrfSx8sTWkeUg@mail.gmail.com
-- 
Peter Geoghegan



Re: Improving the "Routine Vacuuming" docs

From
"David G. Johnston"
Date:
On Tue, Apr 12, 2022 at 2:53 PM Peter Geoghegan <pg@bowt.ie> wrote:
Recent work on VACUUM and relfrozenxid advancement required that I
update the maintenance.sgml VACUUM documentation ("Routine
Vacuuming"). It was tricky to keep things current, due in part to
certain structural problems. Many of these problems are artifacts of
how the document evolved over time.

"Routine Vacuuming" ought to work as a high level description of how
VACUUM keeps the system going over time. The intended audience is
primarily DBAs, so low level implementation details should either be
given much less prominence, or not even mentioned. We should keep it
practical -- without going too far in the direction of assuming that
we know the limits of what information might be useful.

+1

I've attached some off-the-cuff thoughts on reworking the first three paragraphs and the note.

It's hopefully useful for providing perspective if nothing else.


My high level concerns are:

* Instead of discussing FrozenTransactionId (and then explaining how
that particular magic value is not really used anymore anyway), why
not describe freezing in terms of the high level rules?

Agreed and considered

Something along the lines of the following seems more useful: "A tuple
whose xmin is frozen (and xmax is unset) is considered visible to
every possible MVCC snapshot. In other words, the transaction that
inserted the tuple is treated as if it ran and committed at some point
that is now *infinitely* far in the past."

I'm assuming and caring only about visible rows when I'm reading this section. Maybe we need to make that explicit - only xmin matters (and the invisible frozen flag)?


It might also be useful to describe freezing all of a live tuple's
XIDs as roughly the opposite process as completely physically removing
a dead tuple. It follows that we don't necessarily need to freeze
anything to advance relfrozenxid (especially not on Postgres 15).

I failed to pickup on how this and "mod-2^32" math interplay, and I'm not sure I care when reading this.  It made more sense to consider "shortest path" along the "circle".


Currently, "25.1.5. Preventing Transaction ID Wraparound Failures"
says this, right up-front:

"But since transaction IDs have limited size (32 bits) a cluster that
runs for a long time (more than 4 billion transactions) would suffer
transaction ID wraparound"

I both agree and disagree - where I settled (as of now) is reflected in the patch.
 
* The description of wraparound sounds terrifying, implying that data
corruption can result.

Agreed, though I just skimmed a bit after the material the patch covers.

* XID space isn't really a precious resource -- it isn't even a
resource at all IMV.

Agreed

* We don't cleanly separate discussion of anti-wraparound autovacuums,
and aggressive vacuums, and the general danger of wraparound (by which
I actually mean the danger of having the xidStopLimit stop limit kick
in).

Didn't really get this far.

I am wondering, for the more technical details, is there an existing place to send xrefs, do you plan to create one, or is it likely unnecessary?
David J.

Attachment

Re: Improving the "Routine Vacuuming" docs

From
Peter Geoghegan
Date:
On Tue, Apr 12, 2022 at 4:24 PM David G. Johnston
<david.g.johnston@gmail.com> wrote:
> I've attached some off-the-cuff thoughts on reworking the first three paragraphs and the note.
>
> It's hopefully useful for providing perspective if nothing else.

More perspective is definitely helpful.

> I'm assuming and caring only about visible rows when I'm reading this section. Maybe we need to make that explicit -
onlyxmin matters (and the invisible frozen flag)?
 

The statement "only xmin matters" is true in spirit. If xmax needed to
be frozen then we'd actually remove the whole tuple instead (unless it
was a MultiXact). Alternatively, if it looked like xmax needed to be
frozen, but the XID turned out to have been from an aborted xact, then
we'd clear the XID from xmax instead.

Freezing tends to lag the removal of dead tuples, but that's just an
optimization. If you set vacuum_freeze_min_age to 0 then freezing and
dead tuple removal happen in tandem (actually, we can remove tuples
inserted by an XID after VACUUM's OldestXmin/removal cutoff when the
inserting xact aborts, but VACUUM makes no real promises about XIDs >=
OldestXmin anyway).

>> It might also be useful to describe freezing all of a live tuple's
>> XIDs as roughly the opposite process as completely physically removing
>> a dead tuple. It follows that we don't necessarily need to freeze
>> anything to advance relfrozenxid (especially not on Postgres 15).
>
>
> I failed to pickup on how this and "mod-2^32" math interplay, and I'm not sure I care when reading this.  It made
moresense to consider "shortest path" along the "circle".
 

It would probably be possible to teach the system to deal with
coexisting XIDs that are close to a full ~4 billion XIDs apart. We'd
have to give up on the mod-2^32 comparison stuff in functions like
TransactionIdPrecedes(), and carefully keep track of things per-table,
and carry that context around a lot more. I certainly don't think that
that's a good idea (if 2 billion XIDs wasn't enough, why should 4
billion XIDs be?), but it does seem feasible.

My point is this: there is nothing particularly intuitive or natural
about the current ~2 billion XID limit, even if you already know that
XIDs are generally represented on disk as 32-bit unsigned integers.
And so the fact is that we are already asking users to take it on
faith that there are truly good reasons why the system cannot tolerate
any scenario in which two unfrozen XIDs are more than about ~2 billion
XIDs apart. Why not just admit that, and then deem the XID comparison
rules out of scope for this particular chapter of the docs?

*Maybe* it's still useful to discuss why things work that way in code
like TransactionIdPrecedes(), but that's a totally different
discussion -- it doesn't seem particularly relevant to the design of
VACUUM, no matter the audience. Most DBAs will just accept that the
"XID distance" limit/invariant is about ~2 billion XIDs for esoteric
implementation reasons, with some vague idea of why it must be so
(e.g., "32-bit integers don't have enough space"). They will be no
worse off for it.

(Bear in mind that mod-2^32 comparison stuff was only added when
freezing/wraparound was first implemented back in 2001, by commit
bc7d37a525.)

>> Currently, "25.1.5. Preventing Transaction ID Wraparound Failures"
>> says this, right up-front:
>>
>> "But since transaction IDs have limited size (32 bits) a cluster that
>> runs for a long time (more than 4 billion transactions) would suffer
>> transaction ID wraparound"
>
>
> I both agree and disagree - where I settled (as of now) is reflected in the patch.

I just don't think that you need to make it any more complicated than
this: physical XID values are only meaningful when compared to other
XIDs from the same cluster. The system needs to make sure that no two
XIDs can ever be more than about 2 billion XIDs apart, and here's how
you as a DBA can help the system to make sure of that.

Discussion of the past becoming the future just isn't helpful, because
that simply cannot ever happen on any version of Postgres from the
last decade. Freezing is more or less an overhead of storing data in
Postgres long term (even medium term) -- that is the simple reality.
We should say so.

> I am wondering, for the more technical details, is there an existing place to send xrefs, do you plan to create one,
oris it likely unnecessary?
 

I might end up doing that, but just want to get a general sense of how
other hackers feel about it for now.

-- 
Peter Geoghegan



Re: Improving the "Routine Vacuuming" docs

From
"David G. Johnston"
Date:
On Tue, Apr 12, 2022 at 5:22 PM Peter Geoghegan <pg@bowt.ie> wrote:
I just don't think that you need to make it any more complicated than
this: physical XID values are only meaningful when compared to other
XIDs from the same cluster. The system needs to make sure that no two
XIDs can ever be more than about 2 billion XIDs apart, and here's how
you as a DBA can help the system to make sure of that.


I decided to run with that perspective and came up with the following rough draft.  A decent amount of existing material I would either just remove or place elsewhere as "see for details".

The following represents the complete section.

David J.

   <para>
    This vacuum responsibility is necessary due to the fact that a transaction ID (xid)
    has a lifetime of 2 billion transactions.  The rows created by a given transaction
    (recorded in xmin) must be frozen prior to the expiration of the xid.
    (The expired xid values can then be resurrected, see ... for details).
    This is done by flagging the rows as frozen and thus visible for the remainder
    of the row's life.
   </para>
   
   <para>
    While vacuum will not touch a row's xmin while updating its frozen status, two reserved xid
    values may be seen. <literal>BootstreapTransactionId</literal> (1) may be seen on system catalog
    tables to indicate records inserted during initdb. <literal>FronzenTransactionID</literal> (2)
    may be seen on any table and also indicates that the row is frozen.  This was the mechanism
    used in versions prior to 9.4, when it was decided to keep the xmin unchanged for forensic use.
   </para>

   <para>
    <command>VACUUM</command> uses the <link linkend="storage-vm">visibility map</link>
    to determine which pages of a table must be scanned.  Normally, it
    will skip pages that don't have any dead row versions even if those pages
    might still have row versions with old XID values.  Therefore, normal
    <command>VACUUM</command>s won't always freeze every old row version in the table.
    When that happens, <command>VACUUM</command> will eventually need to perform an
    <firstterm>aggressive vacuum</firstterm>, which will freeze all eligible unfrozen
    XID and MXID values, including those from all-visible but not all-frozen pages.
    In practice most tables require periodic aggressive vacuuming.
   </para>

   <para>
    Thus, an aging transaction will potentially pass a number of milestone ages,
    controlled by various configuration settings or hard-coded into the server,
    as it awaits its fate either being memorialized cryogenically or in death.
    While the following speaks of an individual transaction's age, in practice
    each table has a relfrozenxid attribute which is used by system as a reference
    age as it is oldest potentially living transaction on the table (see xref for details).
   </para>
   
   <para>
    The first milestone is controlled by vacuum_freeze_min_age (50 million) and marks the age
    at which the row becomes eligible to become frozen.
   </para>
   <para>
    Next up is vacuum_freeze_table_age (120 million).  Before this age the row can be frozen,
    but a non-aggressive vacuum may not encounter the row due to the visibility
    map optimizations described above.  Vacuums performed while relfrozenxid
    is older than this age will be done aggressively.
   </para>
   <para>
    For tables where routine complete vacuuming doesn't happen the auto-vacuum
    daemon acts as a safety net.  When the age of the row exceeds
    autovacuum_freeze_max_age (200 million) the autovacuum daemon, even if disabled for the table,
    will perform an anti-wraparound vacuum on the table (see below).
   </para>
   <para>
    Finally, as a measure of last resort, the system will begin emitting warnings
    (1.940 billion) and then (1.997 billion) shutdown.
    It may be restarted in single user mode for manual aggressive vacuuming.
   </para>

   <para>
    An anti-wraparound vacuum is much more expensive than an aggressive vacuum and
    so the gap between the vacuum_freeze_table_age and autovacuum_freeze_max_age
    should be somewhat large (vacuum age must be at most 95% of the autovacuum age
    to be meaningful).
   </para>

   <para>
    Transaction history and commit status storage requirements are directly related to
    <varname>autovacuum_freeze_max_age</varname> due to retention policies based upon
    that age. See xref ... for additional details.
   </para>

   <para>
    The reason for vacuum_freeze_min_age is to manage the trade-off between minimizing
    rows marked dead that are already frozen versus minimizing the number of rows
    being frozen aggressively.
   </para>

Re: Improving the "Routine Vacuuming" docs

From
Robert Haas
Date:
On Tue, Apr 12, 2022 at 5:53 PM Peter Geoghegan <pg@bowt.ie> wrote:
> My high level concerns are:
>
> * Instead of discussing FrozenTransactionId (and then explaining how
> that particular magic value is not really used anymore anyway), why
> not describe freezing in terms of the high level rules?
>
> Something along the lines of the following seems more useful: "A tuple
> whose xmin is frozen (and xmax is unset) is considered visible to
> every possible MVCC snapshot. In other words, the transaction that
> inserted the tuple is treated as if it ran and committed at some point
> that is now *infinitely* far in the past."

I agree with this idea.

> * The description of wraparound sounds terrifying, implying that data
> corruption can result.
>
> The alarming language isn't proportionate to the true danger
> (something I complained about in a dedicated thread last year [1]).

I mostly agree with this, but not entirely. The section needs some
rephrasing, but xidStopLimit doesn't apply in single-user mode, and
relfrozenxid and datfrozenxid values can and do get corrupted. So it's
not a purely academic concern.

> * XID space isn't really a precious resource -- it isn't even a
> resource at all IMV.

I disagree with this. Usable XID space is definitely a resource, and
if you're in the situation where you care deeply about this section of
the documentation, it's probably one in short supply. Being careful
not to expend too many XIDs while fixing the problems that have cause
you to be short of safe XIDs is *definitely* a real thing.

> * We don't cleanly separate discussion of anti-wraparound autovacuums,
> and aggressive vacuums, and the general danger of wraparound (by which
> I actually mean the danger of having the xidStopLimit stop limit kick
> in).

I think it is wrong to conflate wraparound with xidStopLimit.
xidStopLimit is the final defense against an actual wraparound, and
like I say, an actual wraparound is quite possible if you put the
system in single user mode and then do something like this:

backend> VACUUM FULL;

Big ouch.

-- 
Robert Haas
EDB: http://www.enterprisedb.com



Re: Improving the "Routine Vacuuming" docs

From
Peter Geoghegan
Date:
On Wed, Apr 13, 2022 at 8:40 AM Robert Haas <robertmhaas@gmail.com> wrote:
> > Something along the lines of the following seems more useful: "A tuple
> > whose xmin is frozen (and xmax is unset) is considered visible to
> > every possible MVCC snapshot. In other words, the transaction that
> > inserted the tuple is treated as if it ran and committed at some point
> > that is now *infinitely* far in the past."
>
> I agree with this idea.

Cool. Maybe I should write a doc patch just for this part, then.

What do you think of the idea of relating freezing to removing tuples
by VACUUM at this point? This would be a basis for explaining how
freezing and tuple removal are constrained by the same cutoff. A very
old snapshot can hold up cleanup, but it can also hold up freezing to
the same degree (it's just not as obvious because we are less eager
about freezing by default).

> > The alarming language isn't proportionate to the true danger
> > (something I complained about in a dedicated thread last year [1]).
>
> I mostly agree with this, but not entirely. The section needs some
> rephrasing, but xidStopLimit doesn't apply in single-user mode, and
> relfrozenxid and datfrozenxid values can and do get corrupted. So it's
> not a purely academic concern.

I accept the distinction that you want to make is valid. More on that below.

> > * XID space isn't really a precious resource -- it isn't even a
> > resource at all IMV.
>
> I disagree with this. Usable XID space is definitely a resource, and
> if you're in the situation where you care deeply about this section of
> the documentation, it's probably one in short supply. Being careful
> not to expend too many XIDs while fixing the problems that have cause
> you to be short of safe XIDs is *definitely* a real thing.

I may have gone too far with this metaphor. My point was mostly that
XID space has a highly unpredictable cost (paid in freezing).

Perhaps we can agree on some (or even all) of the following specific points:

* We shouldn't mention "4 billion XIDs" at all.

* We should say that the issue is an issue of distances between
unfrozen XIDs. The maximum distance that can ever be allowed to emerge
between any two unfrozen XIDs in a cluster is about 2 billion XIDs.

* We don't need to say anything about how XIDs are compared, normal vs
permanent XIDs, etc.

* The system takes drastic intervention to prevent this implementation
restriction from becoming a problem, starting with anti-wraparound
autovacuums. Then there's the failsafe. Finally, there's the
xidStopLimit mechanism, our last line of defense.

> I think it is wrong to conflate wraparound with xidStopLimit.
> xidStopLimit is the final defense against an actual wraparound, and
> like I say, an actual wraparound is quite possible if you put the
> system in single user mode and then do something like this:

I forget to emphasize one aspect of the problem that seems quite
important: the document itself seems to conflate the xidStopLimit
mechanism with true wraparound. At least I thought so. Last year's
thread on this subject ('What is "wraparound failure", really?') was
mostly about that confusion. I personally found that very confusing,
and I doubt that I'm the only one.

There is no good reason to use single user mode anymore (a related
problem with the docs is that we still haven't made that point). And
the pg_upgrade bug that led to invalid relfrozenxid values was
flagrantly just a bug (adding a WARNING for this recently, in commit
e83ebfe6). So while I accept that the distinction you're making here
is valid, maybe we can fix the single user mode doc bug too, removing
the need to discuss "true wraparound" as a general phenomenon. You
shouldn't ever see it in practice anymore. If you do then either
you've done something that "invalidated the warranty", or you've run
into a legitimate bug.

-- 
Peter Geoghegan



Re: Improving the "Routine Vacuuming" docs

From
Robert Haas
Date:
On Wed, Apr 13, 2022 at 12:34 PM Peter Geoghegan <pg@bowt.ie> wrote:
> What do you think of the idea of relating freezing to removing tuples
> by VACUUM at this point? This would be a basis for explaining how
> freezing and tuple removal are constrained by the same cutoff. A very
> old snapshot can hold up cleanup, but it can also hold up freezing to
> the same degree (it's just not as obvious because we are less eager
> about freezing by default).

I think something like that could be useful, if we can find a way to
word it sufficiently clearly.

> Perhaps we can agree on some (or even all) of the following specific points:
>
> * We shouldn't mention "4 billion XIDs" at all.
>
> * We should say that the issue is an issue of distances between
> unfrozen XIDs. The maximum distance that can ever be allowed to emerge
> between any two unfrozen XIDs in a cluster is about 2 billion XIDs.
>
> * We don't need to say anything about how XIDs are compared, normal vs
> permanent XIDs, etc.
>
> * The system takes drastic intervention to prevent this implementation
> restriction from becoming a problem, starting with anti-wraparound
> autovacuums. Then there's the failsafe. Finally, there's the
> xidStopLimit mechanism, our last line of defense.

Those all sound pretty reasonable. There's a little bit of doubt in my
mind about the third one; I think it could possibly be useful to
explain that the XID space is circular and 0-2 are special, but maybe
not.

> > I think it is wrong to conflate wraparound with xidStopLimit.
> > xidStopLimit is the final defense against an actual wraparound, and
> > like I say, an actual wraparound is quite possible if you put the
> > system in single user mode and then do something like this:
>
> I forget to emphasize one aspect of the problem that seems quite
> important: the document itself seems to conflate the xidStopLimit
> mechanism with true wraparound. At least I thought so. Last year's
> thread on this subject ('What is "wraparound failure", really?') was
> mostly about that confusion. I personally found that very confusing,
> and I doubt that I'm the only one.

OK.

> There is no good reason to use single user mode anymore (a related
> problem with the docs is that we still haven't made that point). And

Agreed.

> the pg_upgrade bug that led to invalid relfrozenxid values was
> flagrantly just a bug (adding a WARNING for this recently, in commit
> e83ebfe6). So while I accept that the distinction you're making here
> is valid, maybe we can fix the single user mode doc bug too, removing
> the need to discuss "true wraparound" as a general phenomenon. You
> shouldn't ever see it in practice anymore. If you do then either
> you've done something that "invalidated the warranty", or you've run
> into a legitimate bug.

I think it is probably important to discuss this, but along the lines
of: it is possible to bypass all of these safeguards and cause a true
wraparound by running in single-user mode. Don't do that. There's no
wraparound situation that can't be addressed just fine in multi-user
mode, and here's how to do that. In previous releases, we used to
sometimes recommend single user mode, but that's no longer necessary
and not a good idea, so steer clear.

-- 
Robert Haas
EDB: http://www.enterprisedb.com



Re: Improving the "Routine Vacuuming" docs

From
Peter Geoghegan
Date:
On Wed, Apr 13, 2022 at 1:25 PM Robert Haas <robertmhaas@gmail.com> wrote:
> On Wed, Apr 13, 2022 at 12:34 PM Peter Geoghegan <pg@bowt.ie> wrote:
> > What do you think of the idea of relating freezing to removing tuples
> > by VACUUM at this point? This would be a basis for explaining how
> > freezing and tuple removal are constrained by the same cutoff.

> I think something like that could be useful, if we can find a way to
> word it sufficiently clearly.

What if the current "25.1.5. Preventing Transaction ID
Wraparound Failures" section was split into two parts? The first part
would cover freezing, the second part would cover
relfrozenxid/relminmxid advancement.

Freezing can sensibly be discussed before introducing relfrozenxid.
Freezing is a maintenance task that makes tuples self-contained
things, suitable for long term storage. Freezing makes tuples not rely
on transient transaction metadata (mainly clog), and so is an overhead
of storing data in Postgres long term.

That's how I think of it, at least. That definition seems natural to me.

> Those all sound pretty reasonable.

Great.

I have two more things that I see as problems. Would be good to get
your thoughts here, too. They are:

1. We shouldn't really be discussing VACUUM FULL here at all, except
to say that it's out of scope, and probably a bad idea.

You once wrote about the problem of how VACUUM FULL is perceived by
users (VACUUM FULL doesn't mean "VACUUM, but better"), expressing an
opinion of VACUUM FULL that I agree with fully. The docs definitely
contributed to that problem.

2. We don't go far enough in emphasizing the central role of autovacuum.

Technically the entire section assumes that its primary audience are
those users that have opted to not use autovacuum. This seems entirely
backwards to me.

We should make it clear that technically autovacuum isn't all that
different from running your own VACUUM commands, because that's an
important part of understanding autovacuum. But that's all. ISTM that
anybody that *entirely* opts out of using autovacuum is just doing it
wrong (besides, it's kind of impossible to do it anyway, what with
anti-wraparound autovacuum being impossible to disable).

There is definitely a role for using tools like cron to schedule
off-hours VACUUM operations, and that's still worth pointing out
prominently. But that should be a totally supplementary thing, used
when the DBA understands that running VACUUM off-hours is less
disruptive.

> There's a little bit of doubt in my
> mind about the third one; I think it could possibly be useful to
> explain that the XID space is circular and 0-2 are special, but maybe
> not.

I understand the concern. I'm not saying that this kind of information
doesn't have any business being in the docs. Just that it has no
business being in this particular chapter of the docs. In fact, it
doesn't even belong in "III. Server Administration". If it belongs
anywhere, it should be in some chapter from "VII. Internals".

Discussing it here just seems inappropriate (and would be even if it
wasn't how we introduce discussion of wraparound). It's really only
tangentially related to VACUUM anyway. It seems like it should be
covered when discussing the heapam on-disk representation.

> I think it is probably important to discuss this, but along the lines
> of: it is possible to bypass all of these safeguards and cause a true
> wraparound by running in single-user mode. Don't do that. There's no
> wraparound situation that can't be addressed just fine in multi-user
> mode, and here's how to do that. In previous releases, we used to
> sometimes recommend single user mode, but that's no longer necessary
> and not a good idea, so steer clear.

Yeah, that should probably happen somewhere.

On the other hand...why do we even need to tolerate wraparound in
single-user mode? I do see some value in reserving extra XIDs that can
be used in single-user mode (apparently single-user mode can be used
in scenarios where you have buggy event triggers, things like that).
But that in itself does not justify allowing single-user mode to
exceed xidWrapLimit.

Why shouldn't single-user mode also refuse to allocate new XIDs when
we reach xidWrapLimit (as opposed to when we reach xidStopLimit)?

Maybe there is a good reason to believe that allowing single-user mode
to corrupt the database is the lesser evil, but if there is then I'd
like to know the reason.


--
Peter Geoghegan



Re: Improving the "Routine Vacuuming" docs

From
"David G. Johnston"
Date:
On Wed, Apr 13, 2022 at 2:19 PM Peter Geoghegan <pg@bowt.ie> wrote:
On Wed, Apr 13, 2022 at 1:25 PM Robert Haas <robertmhaas@gmail.com> wrote:
> On Wed, Apr 13, 2022 at 12:34 PM Peter Geoghegan <pg@bowt.ie> wrote:
> > What do you think of the idea of relating freezing to removing tuples
> > by VACUUM at this point? This would be a basis for explaining how
> > freezing and tuple removal are constrained by the same cutoff.

> I think something like that could be useful, if we can find a way to
> word it sufficiently clearly.

What if the current "25.1.5. Preventing Transaction ID
Wraparound Failures" section was split into two parts? The first part
would cover freezing, the second part would cover
relfrozenxid/relminmxid advancement.

Freezing can sensibly be discussed before introducing relfrozenxid.
Freezing is a maintenance task that makes tuples self-contained
things, suitable for long term storage. Freezing makes tuples not rely
on transient transaction metadata (mainly clog), and so is an overhead
of storing data in Postgres long term.

That's how I think of it, at least. That definition seems natural to me.

I was trying to do that with my second try, and partially failed.  I'm on board with the idea though.


> Those all sound pretty reasonable.

Great.

I have two more things that I see as problems. Would be good to get
your thoughts here, too. They are:

1. We shouldn't really be discussing VACUUM FULL here at all, except
to say that it's out of scope, and probably a bad idea.

You once wrote about the problem of how VACUUM FULL is perceived by
users (VACUUM FULL doesn't mean "VACUUM, but better"), expressing an
opinion of VACUUM FULL that I agree with fully. The docs definitely
contributed to that problem.

I agree.  I would remove VACUUM FULL from the "Vacuuming Basics" and "Recovering Disk Space" section aside from adding a warning box saying it exists, it is not part of routine maintenance (hence out-of-scope for the "Routine Vacuuming" Chapter), and to look elsewhere for details.

2. We don't go far enough in emphasizing the central role of autovacuum.

Technically the entire section assumes that its primary audience are
those users that have opted to not use autovacuum. This seems entirely
backwards to me.

I would be on board with having the language of the entire section written with the assumption that autovacuum is enabled, with a single statement upfront that this is the case.  Most of the content remains as-is but we remove a non-trivial number of sentences and fragments of the form "The autovacuum daemon, if enabled, will..." and "For those not using autovacuum,..."

If the basic content is deemed worthy of preservation, relocating all of those kinds of hints and whatnot to a single "supplementing or disabling auto-vacuum" section.


> There's a little bit of doubt in my
> mind about the third one; I think it could possibly be useful to
> explain that the XID space is circular and 0-2 are special, but maybe
> not.

I understand the concern. I'm not saying that this kind of information
doesn't have any business being in the docs. Just that it has no
business being in this particular chapter of the docs. In fact, it
doesn't even belong in "III. Server Administration". If it belongs
anywhere, it should be in some chapter from "VII. Internals".

I think we do want to relocate some of this material elsewhere, and Internals seems probable, and we'd want to have a brief sentence or two here before pointing the reader to more information.  I'm sure we'll come to some conclusion on the level of detail that lead-in should include.  Less is more to start with.  Unless the rest of the revised chapter is going to lean heavily into it.
 

Why shouldn't single-user mode also refuse to allocate new XIDs when
we reach xidWrapLimit (as opposed to when we reach xidStopLimit)?


I lack the familiarity with the details here to comment on this last major point.

I do think the "Server Administration" section is missing a chapter though - "Error Handling and Recovery".

With that chapter in place I would mention the warning threshold in the routine maintenance chapter as something that might be seen if routine maintenance is misconfigured or encounters problems.  Then direct the user to "Error Handling and Recovery" for discussion about the warning and whatever else may happen if it is ignored; and how to go about fixing the problem(s) that caused the warning.

David J.

Re: Improving the "Routine Vacuuming" docs

From
John Naylor
Date:
On Thu, Apr 14, 2022 at 5:03 AM David G. Johnston
<david.g.johnston@gmail.com> wrote:

> I would be on board with having the language of the entire section written with the assumption that autovacuum is
enabled,with a single statement upfront that this is the case.  Most of the content remains as-is but we remove a
non-trivialnumber of sentences and fragments of the form "The autovacuum daemon, if enabled, will..." and "For those
notusing autovacuum,..." 

+1

The second one goes on to say "a typical approach...", which seems to
imply there are plenty of installations that hum along happily with
autovacuum disabled. If there are, I haven't heard of any. (Aside: In
my experience, it's far more common for someone to disable autovacuum
on 118 tables via reloptions for who-knows-what-reason and without
regard for the consequences). Also:

- "Some database administrators will want to supplement or replace the
daemon's activities with manually-managed VACUUM commands". I'm not
sure why we go as far as to state that *replacing* is an option to
consider.

- " you will need to use VACUUM FULL, or alternatively CLUSTER or one
of the table-rewriting variants of ALTER TABLE."

If you follow the link to the ALTER TABLE documentation, there is no
easy-to-find info on what these table-rewriting variants might be.
Within that page there are two instances of the text "one of the forms
of ALTER TABLE that ...", but again no easy-to-find advice on what
those might be. Furthermore, I don't recall there being an ALTER TABLE
that rewrites the table with no other effects (*). So if you find
yourself *really* needing to VACUUM FULL or CLUSTER, which primary
effect of ALTER TABLE should they consider, in order to get the side
effect of rewriting the table? Why are we mentioning ALTER TABLE here
at all?

> If the basic content is deemed worthy of preservation, relocating all of those kinds of hints and whatnot to a single
"supplementingor disabling auto-vacuum" section. 

I think any mention of disabling should be in a context where it is
not assumed to be normal, i.e. exceptional situations. Putting it in a
section heading makes it too normal. Here's how I think about this: do
we have a section heading anywhere on disabling fsync? I know it's not
the same, but that's how I think about it.

(*) Should there be? As alluded to upthread, VACUUM FULL is a terrible
name for what it does as of 9.0. I continue to encounter admins who
have a weekly script that runs database-wide VACUUM FULL, followed by
REINDEX. Or, upon asking someone to run a manual vacuum on a table,
will echo what they think they heard: "okay, so run a full vacuum". I
would prefer these misunderstandings to get a big fat syntax error if
they are carried out.

--
John Naylor
EDB: http://www.enterprisedb.com