Re: New strategies for freezing, advancing relfrozenxid early - Mailing list pgsql-hackers
From | Peter Geoghegan |
---|---|
Subject | Re: New strategies for freezing, advancing relfrozenxid early |
Date | |
Msg-id | CAH2-WzmF9UVWv9Nmm3dhP7WS4=-qQSQRM-Jn2-NSr6z=sDsv3g@mail.gmail.com Whole thread Raw |
In response to | Re: New strategies for freezing, advancing relfrozenxid early (Peter Geoghegan <pg@bowt.ie>) |
Responses |
Re: New strategies for freezing, advancing relfrozenxid early
|
List | pgsql-hackers |
On Tue, Dec 20, 2022 at 7:15 PM Peter Geoghegan <pg@bowt.ie> wrote: > On Tue, Dec 20, 2022 at 5:44 PM Jeff Davis <pgsql@j-davis.com> wrote: > > Next, the 'freeze_required' field suggests that it's more involved in > > the control flow that causes freezing than it actually is. All it does > > is communicate how the trackers need to be adjusted. The return value > > of heap_prepare_freeze_tuple() (and underneath, the flags set by > > FreezeMultiXactId()) are what actually control what happens. It would > > be nice to make this more clear somehow. > > I'm not sure what you mean. Page-level freezing *doesn't* have to go > ahead when freeze_required is not ever set to true for any tuple on > the page (which is most of the time, in practice). lazy_scan_prune > gets to make a choice about freezing the page, when the choice is > available. Oh wait, I think I see the point of confusion now. When freeze_required is set to true, that means that lazy_scan_prune literally has no choice -- it simply must freeze the page as instructed by heap_prepare_freeze_tuple/FreezeMultiXactId. It's not just a strong suggestion -- it's crucial that lazy_scan_prune freezes the page as instructed. The "no freeze" trackers (HeapPageFreeze.NoFreezePageRelfrozenXid and HeapPageFreeze.NoFreezePageRelminMxid) won't have been maintained properly when freeze_required was set, so lazy_scan_prune can't expect to use them -- doing so would lead to VACUUM setting incorrect values in pg_class later on. Avoiding the work of maintaining those "no freeze" trackers isn't just a nice-to-have microoptimization -- it is sometimes very important. We kind of rely on this to be able to avoid getting too many MultiXact member SLRU buffer misses inside FreezeMultiXactId. There is a comment above FreezeMultiXactId that advises its caller that it had better not call heap_tuple_should_freeze when freeze_required is set to true, because that could easily lead to multixact member SLRU buffer misses -- misses that FreezeMultiXactId set out to avoid itself. It could actually be cheaper to freeze than to not freeze, in the case of a Multi -- member space misses can sometimes be really expensive. And so FreezeMultiXactId sometimes freezes a Multi even though it's not strictly required to do so. Note also that this isn't a new behavior -- it's actually an old one, for the most part. It kinda doesn't look that way, because we haven't passed down separate FreezeLimit/OldestXmin cutoffs (and separate OldestMxact/MultiXactCutoff cutoffs) until now. But we often don't need that granular information to be able to process Multis before the multi value is < MultiXactCutoff. If you look at how FreezeMultiXactId works, in detail, you'll see that even on Postgres HEAD it can (say) set a tuple's xmax to InvalidTransactionId long before the multi value is < MultiXactCutoff. It just needs to detect that the multi is not still running, and notice that it's HEAP_XMAX_IS_LOCKED_ONLY(). Stuff like that happens quite a bit. So for the most part "eager processing of Multis as a special case" is an old behavior, that has only been enhanced a little bit (the really important, new change in FreezeMultiXactId is how the FRM_NOOP case works with FreezeLimit, even though OldestXmin is used nearby -- this is extra confusing because 0002 doesn't change how we use FreezeLimit -- it actually changes every other use of FreezeLimit nearby, making it OldestXmin). -- Peter Geoghegan
pgsql-hackers by date: