On Wed, Jun 16, 2021 at 9:03 AM Peter Geoghegan <p...@bowt.ie> wrote: > On Wed, Jun 16, 2021 at 3:59 AM Matthias van de Meent > > So the implicit assumption in heap_page_prune that > > HeapTupleSatisfiesVacuum(OldestXmin) is always consistent with > > heap_prune_satisfies_vacuum(vacrel) has never been true. In that case, > > we'll need to redo the condition in heap_page_prune as well. > > I don't think that this shows that the assumption within > lazy_scan_prune() (the assumption that both "satisfies vacuum" > functions agree) is wrong, with the obvious exception of cases > involving the bug that Justin reported. GlobalVis*.maybe_needed is > supposed to be conservative.
I suppose it's true that they can disagree because we call vacuum_set_xid_limits() to get an OldestXmin inside vacuumlazy.c before calling GlobalVisTestFor() inside vacuumlazy.c to get a vistest. But that only implies that a tuple that would have been considered RECENTLY_DEAD inside lazy_scan_prune() (it just missed being considered DEAD according to OldestXmin) is seen as an LP_DEAD stub line pointer. Which really means it's DEAD to lazy_scan_prune() anyway. These days the only way that lazy_scan_prune() can consider a tuple fully DEAD is if it's no longer a tuple -- it has to actually be an LP_DEAD stub line pointer. It's really no different to an opportunistic prune that concurrently prunes tuples that VACUUM would have seen as RECENTLY_DEAD if it was going solely on the OldestXmin cutoff. There are certain kinds of tables where non-HOT updates and opportunistic pruning constantly leave behind loads of LP_DEAD items. Pruning inside VACUUM won't do much of the total required pruning at all. That'll mean that some DEAD/LP_DEAD items will become dead long after a VACUUM starts, while nevertheless being removed by the same VACUUM. Of course there is no way for lazy_scan_prune() to distinguish one LP_DEAD item from another -- they're all stubs without tuple storage, and without a tuple header with XIDs. -- Peter Geoghegan