On Mon, Jun 2, 2025 at 4:00 PM Melanie Plageman <melanieplage...@gmail.com> wrote: > Perhaps I could keep track of the newest modified xid or some such > thing that is the newer of the newest removed xmax and newest frozen > xmin.
BTW, I don't think that you have to worry about removing/freezing xmax when it comes to generating a safe snapshotConflictHorizon. Nothing makes it unsafe for VACUUM to remove an xmax set by an updater that is known to have aborted right away -- no matter how that xmax compares to OldestXmin. Pruning has always been able to remove the successor version right away, no matter how recently the abort happened, so why shouldn't we *also* be able to set the xmax in the original version to InvalidTransactionId? That doesn't need to be taken into account by snapshotConflictHorizon handling. (Note that HeapTupleHeaderAdvanceConflictHorizon() is specifically aware that an aborted tuple's xmin shouldn't need to affect a prune record's conflict horizon; an aborted update can also skip consideration by snapshotConflictHorizon maintenance.) I also think that a locker-only xmax can be removed/frozen/set to InvalidTransactionId, as long as the tuple lock is no longer held on the primary -- it can safely be set to InvalidTransactionId, without it needing to affect snapshotConflictHorizon tracking at all. In a way, we already do this with Multis. It's already possible (though not particularly common) for VACUUM to fully set a Multi xmax to InvalidTransactionId when the Multi is > OldestMxact -- it can even happen when most of the individual members are still > OldestXmin. As long as the operation cannot affect tuple visibility on standbys, no special snapshotConflictHorizon is required. We do currently end up using OldestXmin-1 as our snapshotConflictHorizon when this happens, but as I said in the other email, I don't think that that's really required. -- Peter Geoghegan