On Fri, May 30, 2025 at 5:34 PM Peter Geoghegan <p...@bowt.ie> wrote: > > On Fri, May 30, 2025 at 5:16 PM Melanie Plageman > <melanieplage...@gmail.com> wrote: > > > You're right. I forgot that the visibility_cutoff_xid will be older > > than OldestXmin when all the tuples are going to be frozen. > > I added an assertion in a number of places that > "Assert(!TransactionIdIsValid(visibility_cutoff_xid))" when we go to > set a page all-frozen in the VM -- it's irrelvant, and recovery cannot > possibly need a conflict when it replays the record. This seemed > logical, since an all-frozen page must already be visible to every > possible MVCC snapshot (it might also have some small performance > benefit, though that's not really why I did it).
My point was not about the visibility_cutoff_xid when setting the page all-frozen in the VM, it was that when you are selecting the snapshot conflict horizon for the freeze record, if all of the tuples on the page will be frozen after doing this freezing, then the visibility_cutoff_xid you calculated while in lazy_scan_prune() will necessarily be older than OldestXmin -- you only freeze tuples older than OldestXmin and the visibility_cutoff_xid is the youngest live tuple's xmin on the page. But since all tuples are older than OldestXmin, the youngest live tuple's xmin on the page will be older than OldestXmin (if all of the tuples on the page will be frozen). I wasn't talking about invalidating the visibility_cutoff_xid for the VM record at all. > > I associate the visibility_cutoff_xid with being younger/newer than > > OldestXmin because it often will be when there are newer live tuples > > we don't freeze. > > I'm not sure what you mean by this. visibility_cutoff_xid can only be > set using tuples that HTSV says are HEAPTUPLE_LIVE according to > VACUUM's OldestXmin cutoff. Personally I find it natural to think of > visibility_cutoff_xid as meaningless unless we're actually able to > apply it in some way. Wait, I don't see that. HeapTupleSatisfiesVacuum() passes OldestXmin which is used to evaluate if tuples can be seen as dead: if (TransactionIdPrecedes(dead_after, OldestXmin)) res = HEAPTUPLE_DEAD; Which doesn't do anything for live tuples. And HeapTupleSatisfiesVacuumHorizon() returns HEAPTUPLE_LIVE for tuples whose inserting transaction has committed. First we check if (!HeapTupleHeaderXminCommitted(tuple)) then all those cases have returns and then if it was committed we do this: /* * Okay, the inserter committed, so it was good at some point. Now what * about the deleting transaction? */ if (tuple->t_infomask & HEAP_XMAX_INVALID) return HEAPTUPLE_LIVE; So wouldn't the visibility_cutoff_xid be the newest xmin of a committed live tuple on the page? /* Track newest xmin on page. */ if (TransactionIdFollows(xmin, prunestate->visibility_cutoff_xid) && TransactionIdIsNormal(xmin)) prunestate->visibility_cutoff_xid = xmin; I don't see how OldestXmin comes into play with the visibility_cutoff_xid. So that was why I thought when there are live committed tuples on the page that could be newer than OldestXmin, that visibility_cutoff_xid would be younger than OldestXmin. - Melanie