Re: Comment explaining why vacuum needs to push snapshot seemsinsufficient. - Mailing list pgsql-hackers

From Andres Freund
Subject Re: Comment explaining why vacuum needs to push snapshot seemsinsufficient.
Date
Msg-id 20200415231309.rk6mlvfmn5a5cxe3@alap3.anarazel.de
Whole thread Raw
In response to Re: Comment explaining why vacuum needs to push snapshot seemsinsufficient.  (Alvaro Herrera <alvherre@2ndquadrant.com>)
List pgsql-hackers
Hi,

On 2020-04-15 17:56:58 -0400, Alvaro Herrera wrote:
> On 2020-Apr-05, Andres Freund wrote:
> 
> > vacuum_rel() has the following comment:
> >     /*
> >      * Functions in indexes may want a snapshot set.  Also, setting a snapshot
> >      * ensures that RecentGlobalXmin is kept truly recent.
> >      */
> >     PushActiveSnapshot(GetTransactionSnapshot());
> > 
> > which was added quite a while ago in
> > 
> > commit d53a56687f3d4772d17ffa0013a33231b7163731
> 
> Note that what that commit did was change the snapshot acquisition from
> occurring solely during vacuum full to being acquired always -- and
> added a small additional bit of knowledge:
> 
> -   if (vacstmt->full)
> -   {
> -       /* functions in indexes may want a snapshot set */
> -       PushActiveSnapshot(GetTransactionSnapshot());
> -   }
> -   else
> +   /*
> +    * Functions in indexes may want a snapshot set.  Also, setting
> +    * a snapshot ensures that RecentGlobalXmin is kept truly recent.
> +    */
> +   PushActiveSnapshot(GetTransactionSnapshot());
> 
> so I wouldn't blame that commit for failing to understand all the side
> effects of acquiring a snapshot there and then.

Fair enough. I just looked far enough to find where the comment was
introduced. But I'm not sure the logic leading to that is correct - see
below.


> > But to me that's understating the issue. Don't we e.g. need a snapshot
> > to ensure that pg_subtrans won't be truncated away?  I thought xlog.c
> > doesn't pass PROCARRAY_FLAGS_VACUUM to GetOldestXmin when truncating?
> >         TruncateSUBTRANS(GetOldestXmin(NULL, PROCARRAY_FLAGS_DEFAULT));
> 
> Nice find.  This bug would probably be orders-of-magnitude easier to hit
> now than it was in 2008 -- given both the hardware advances and the
> increased transaction rates.

Yea. I think there's a lot of very old sloppiness around xmin horizons
that we just avoided hitting frequently due to what you say. Although
I'm fairly sure that we've declared some of the resulting bugs
OS/hardware level issues that actually were horizon related...


> > How about replacing it with something like
> >     /*
> >      * Need to acquire a snapshot to prevent pg_subtrans from being truncated,
> >      * cutoff xids in local memory wrapping around, and to have updated xmin
> >      * horizons.
> >      */
> 
> "While we don't typically need a snapshot, we need the side effects of
> acquiring one: having an xmin prevents concurrent pg_subtrans truncation
> and prevents our cutoff Xids from becoming wrapped-around; this also
> updates our Xmin horizons.  Lastly, functions in indexes may want a
> snapshot set."
> 
> (You omitted that last point without explanation -- maybe on purpose?
> is it no longer needed?)

I left out the "typically need a snapshot" part because it doesn't
really seem to say something meaningful. To me it's adding confusion
without removing any.  I guess we could reformulate it to explain that
while we don't use the snapshot to make mvcc visibility determinations
(since only definitely dead rows matter to vacuum), nor do we use it to
prevent concurrent removal of dead tuples (since we're fine with that
happening), we still need to ensure that resources like pg_subtrans stay
around.

I left out the "in indexes" part because I didn't see it
saying/guaranteeing much. Thinking more about it, that's probably not
quite right. In fact, I wonder if PushActiveSnapshot() does anything
meaningful for the case of expression indexes.  If a snapshot is needed
for some indexes, I assume that would be because visibility tests are
done. But because we set PROC_IN_VACUUM it'd not at all be safe to
actually do visibility tests - rows that are still visible could get
removed.

It's not clear to me which functions this is talking about. For vacuum
full, where the comment originated from, it's obvious (new index being
built) that we need to evaluate arbitrary functions, in particular for
expression indexes. But there's no different behaviour for expression
indexes during normal vacuums, all the expression related work was done
during index insertion.  And if the index operators themselves needed a
valid snapshot, it'd not be safe to set PROC_IN_VACUUM.

I think, at least for btree, it's presumably ok that we invoke btree
operators without a valid snapshot. Because we need to be able to
compare tuples on inner pages during normal operation, which might long
ago may have been removed, btree operators need to be safe against
underlying data vanishing anyway (which is why e.g. enum values are hard
to remove).

Greetings,

Andres Freund



pgsql-hackers by date:

Previous
From: David Steele
Date:
Subject: Re: documenting the backup manifest file format
Next
From: Cary Huang
Date:
Subject: Re: Include sequence relation support in logical replication