• Andres Freund's avatar
    Fix longstanding bug in HeapTupleSatisfiesVacuum(). · 621a99a6
    Andres Freund authored
    HeapTupleSatisfiesVacuum() didn't properly discern between
    DELETE_IN_PROGRESS and INSERT_IN_PROGRESS for rows that have been
    inserted in the current transaction and deleted in a aborted
    subtransaction of the current backend. At the very least that caused
    problems for CLUSTER and CREATE INDEX in transactions that had
    aborting subtransactions producing rows, leading to warnings like:
    WARNING:  concurrent delete in progress within table "..."
    possibly in an endless, uninterruptible, loop.
    
    Instead of treating *InProgress xmins the same as *IsCurrent ones,
    treat them as being distinct like the other visibility routines. As
    implemented this separatation can cause a behaviour change for rows
    that have been inserted and deleted in another, still running,
    transaction. HTSV will now return INSERT_IN_PROGRESS instead of
    DELETE_IN_PROGRESS for those. That's both, more in line with the other
    visibility routines and arguably more correct. The latter because a
    INSERT_IN_PROGRESS will make callers look at/wait for xmin, instead of
    xmax.
    The only current caller where that's possibly worse than the old
    behaviour is heap_prune_chain() which now won't mark the page as
    prunable if a row has concurrently been inserted and deleted. That's
    harmless enough.
    
    As a cautionary measure also insert a interrupt check before the gotos
    in IndexBuildHeapScan() that lead to the uninterruptible loop. There
    are other possible causes, like a row that several sessions try to
    update and all fail, for repeated loops and the cost of doing so in
    the retry case is low.
    
    As this bug goes back all the way to the introduction of
    subtransactions in 573a71a5 backpatch to all supported releases.
    
    Reported-By: Sandro Santilli
    621a99a6
index.c 111 KB