Re: BUG #17257: (auto)vacuum hangs within lazy_scan_prune()
Melanie Plageman <melanieplageman@gmail.com>
Commits
GET /api/v1/messages/:b64id/commits
the thread's linked commits as JSON, with link sources.
API reference →
-
Ensure vacuum removes all visibly dead tuples older than OldestXmin
- 06bf404cd07b 16.4 landed
- 45ce054c02b8 14.13 landed
- dc6354c67017 15.8 landed
-
Combine freezing and pruning steps in VACUUM
- 6dbb490261a6 17.0 cited
-
Handle non-chain tuples outside of heap_prune_chain()
- 6f47f6883151 17.0 cited
-
Fix false reports in pg_visibility
- e85662df44ff 17.0 cited
-
Remove retry loop in heap_page_prune().
- 1ccc1e05ae8f 17.0 cited
-
vacuumlazy.c: document vistest and OldestXmin.
- 73f6ec3d3c8d 15.0 cited
-
Deduplicate choice of horizon for a relation procarray.c.
- d9d8aa9bb9aa 15.0 cited
-
Remove tupgone special case from vacuumlazy.c.
- 8523492d4e34 14.0 cited
-
Simplify state managed by VACUUM.
- b4af70cb2103 14.0 cited
-
Recycle nbtree pages deleted during same VACUUM.
- 9dd963ae2534 14.0 cited
-
snapshot scalability: Don't compute global horizons while building snapshots.
- dc7420c2c927 14.0 cited
-
Raise error when affecting tuple moved into different partition.
- f16241bef7cc 11.0 cited
On Mon, Apr 15, 2024 at 1:39 PM Andres Freund <andres@anarazel.de> wrote:
>
> Hi,
>
> I've tried a couple times to catch up with this thread. But always kinda felt
> I must be missing something. It might be that this is one part of the
> confusion:
>
> On 2024-01-06 12:24:13 -0800, Noah Misch wrote:
> > Fair enough. While I agree there's a decent chance back-patching would be
> > okay, I think there's also a decent chance that 1ccc1e05ae creates the problem
> > Matthias theorized. Something like: we update relfrozenxid based on
> > OldestXmin, even though GlobalVisState caused us to retain a tuple older than
> > OldestXmin. Then relfrozenxid disagrees with table contents.
>
> Looking at the state as of 1ccc1e05ae, I don't see how - in lazy_scan_prune(),
> if heap_page_prune() spuriously didn't prune a tuple, because the horizon went
> backwards, we'd encounter the tuple in the loop below and call
> heap_prepare_freeze_tuple(), which would error out with one of
>
> /*
> * Process xmin, while keeping track of whether it's already frozen, or
> * will become frozen iff our freeze plan is executed by caller (could be
> * neither).
> */
> xid = HeapTupleHeaderGetXmin(tuple);
> if (!TransactionIdIsNormal(xid))
> xmin_already_frozen = true;
> else
> {
> if (TransactionIdPrecedes(xid, cutoffs->relfrozenxid))
> ereport(ERROR,
> (errcode(ERRCODE_DATA_CORRUPTED),
> errmsg_internal("found xmin %u from before relfrozenxid %u",
> xid, cutoffs->relfrozenxid)));
>
> or
> if (TransactionIdPrecedes(update_xact, cutoffs->relfrozenxid))
> ereport(ERROR,
> (errcode(ERRCODE_DATA_CORRUPTED),
> errmsg_internal("multixact %u contains update XID %u from before relfrozenxid %u",
> multi, update_xact,
> cutoffs->relfrozenxid)));
> or
> /* Raw xmax is normal XID */
> if (TransactionIdPrecedes(xid, cutoffs->relfrozenxid))
> ereport(ERROR,
> (errcode(ERRCODE_DATA_CORRUPTED),
> errmsg_internal("found xmax %u from before relfrozenxid %u",
> xid, cutoffs->relfrozenxid)));
>
>
> I'm not saying that spuriously erroring out would be ok. But I guess I just
> don't understand the data corruption theory in this subthread, because we'd
> error out if we encountered a tuple that should have been frozen but wasn't?
I have a more basic question. How could GlobalVisState->maybe_needed
going backwards cause a problem with relfrozenxid? Yes, if
maybe_needed goes backwards, we may not remove a tuple whose xmin/xmax
are older than VacuumCutoffs->OldestXmin. But, if that tuple's
xmin/xmax are older than OldestXmin, then wouldn't we freeze it? If we
freeze it, there isn't an issue. And if the tuple's xids are not newer
than OldestXmin, then how could we end up advancing relfrozenxid to a
value greater than the tuple's xids?
- Melanie