mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Refactor how heap_prune_chain() updates prunable_xid
In preparation of freezing and counting tuples which are not candidates for pruning, split heap_prune_record_unchanged() into multiple functions, depending the kind of line pointer. That's not too interesting right now, but makes the next commit smaller. Recording the lowest soon-to-be prunable xid is one of the actions we take for unchanged LP_NORMAL item pointers but not for others, so move that to the new heap_prune_record_unchanged_lp_normal() function. The next commit will add more actions to these functions. Author: Melanie Plageman <melanieplageman@gmail.com> Discussion: https://www.postgresql.org/message-id/20240330055710.kqg6ii2cdojsxgje@liskov
This commit is contained in:
@ -78,7 +78,11 @@ static void heap_prune_record_redirect(PruneState *prstate,
|
|||||||
static void heap_prune_record_dead(PruneState *prstate, OffsetNumber offnum, bool was_normal);
|
static void heap_prune_record_dead(PruneState *prstate, OffsetNumber offnum, bool was_normal);
|
||||||
static void heap_prune_record_dead_or_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal);
|
static void heap_prune_record_dead_or_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal);
|
||||||
static void heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal);
|
static void heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_normal);
|
||||||
static void heap_prune_record_unchanged(PruneState *prstate, OffsetNumber offnum);
|
|
||||||
|
static void heap_prune_record_unchanged_lp_unused(Page page, PruneState *prstate, OffsetNumber offnum);
|
||||||
|
static void heap_prune_record_unchanged_lp_normal(Page page, int8 *htsv, PruneState *prstate, OffsetNumber offnum);
|
||||||
|
static void heap_prune_record_unchanged_lp_dead(Page page, PruneState *prstate, OffsetNumber offnum);
|
||||||
|
static void heap_prune_record_unchanged_lp_redirect(PruneState *prstate, OffsetNumber offnum);
|
||||||
|
|
||||||
static void page_verify_redirects(Page page);
|
static void page_verify_redirects(Page page);
|
||||||
|
|
||||||
@ -311,7 +315,7 @@ heap_page_prune(Relation relation, Buffer buffer,
|
|||||||
/* Nothing to do if slot doesn't contain a tuple */
|
/* Nothing to do if slot doesn't contain a tuple */
|
||||||
if (!ItemIdIsUsed(itemid))
|
if (!ItemIdIsUsed(itemid))
|
||||||
{
|
{
|
||||||
heap_prune_record_unchanged(&prstate, offnum);
|
heap_prune_record_unchanged_lp_unused(page, &prstate, offnum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,7 +328,7 @@ heap_page_prune(Relation relation, Buffer buffer,
|
|||||||
if (unlikely(prstate.mark_unused_now))
|
if (unlikely(prstate.mark_unused_now))
|
||||||
heap_prune_record_unused(&prstate, offnum, false);
|
heap_prune_record_unused(&prstate, offnum, false);
|
||||||
else
|
else
|
||||||
heap_prune_record_unchanged(&prstate, offnum);
|
heap_prune_record_unchanged_lp_dead(page, &prstate, offnum);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +438,7 @@ heap_page_prune(Relation relation, Buffer buffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
heap_prune_record_unchanged(&prstate, offnum);
|
heap_prune_record_unchanged_lp_normal(page, presult->htsv, &prstate, offnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We should now have processed every tuple exactly once */
|
/* We should now have processed every tuple exactly once */
|
||||||
@ -652,9 +656,6 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
|
|||||||
*/
|
*/
|
||||||
chainitems[nchain++] = offnum;
|
chainitems[nchain++] = offnum;
|
||||||
|
|
||||||
/*
|
|
||||||
* Check tuple's visibility status.
|
|
||||||
*/
|
|
||||||
switch (htsv_get_valid_status(htsv[offnum]))
|
switch (htsv_get_valid_status(htsv[offnum]))
|
||||||
{
|
{
|
||||||
case HEAPTUPLE_DEAD:
|
case HEAPTUPLE_DEAD:
|
||||||
@ -670,9 +671,6 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
|
|||||||
case HEAPTUPLE_RECENTLY_DEAD:
|
case HEAPTUPLE_RECENTLY_DEAD:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This tuple may soon become DEAD. Update the hint field so
|
|
||||||
* that the page is reconsidered for pruning in future.
|
|
||||||
*
|
|
||||||
* We don't need to advance the conflict horizon for
|
* We don't need to advance the conflict horizon for
|
||||||
* RECENTLY_DEAD tuples, even if we are removing them. This
|
* RECENTLY_DEAD tuples, even if we are removing them. This
|
||||||
* is because we only remove RECENTLY_DEAD tuples if they
|
* is because we only remove RECENTLY_DEAD tuples if they
|
||||||
@ -681,8 +679,6 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
|
|||||||
* tuple by virtue of being later in the chain. We will have
|
* tuple by virtue of being later in the chain. We will have
|
||||||
* advanced the conflict horizon for the DEAD tuple.
|
* advanced the conflict horizon for the DEAD tuple.
|
||||||
*/
|
*/
|
||||||
heap_prune_record_prunable(prstate,
|
|
||||||
HeapTupleHeaderGetUpdateXid(htup));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Advance past RECENTLY_DEAD tuples just in case there's a
|
* Advance past RECENTLY_DEAD tuples just in case there's a
|
||||||
@ -693,24 +689,8 @@ heap_prune_chain(Page page, BlockNumber blockno, OffsetNumber maxoff,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
||||||
|
|
||||||
/*
|
|
||||||
* This tuple may soon become DEAD. Update the hint field so
|
|
||||||
* that the page is reconsidered for pruning in future.
|
|
||||||
*/
|
|
||||||
heap_prune_record_prunable(prstate,
|
|
||||||
HeapTupleHeaderGetUpdateXid(htup));
|
|
||||||
goto process_chain;
|
|
||||||
|
|
||||||
case HEAPTUPLE_LIVE:
|
case HEAPTUPLE_LIVE:
|
||||||
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
||||||
|
|
||||||
/*
|
|
||||||
* If we wanted to optimize for aborts, we might consider
|
|
||||||
* marking the page prunable when we see INSERT_IN_PROGRESS.
|
|
||||||
* But we don't. See related decisions about when to mark the
|
|
||||||
* page prunable in heapam.c.
|
|
||||||
*/
|
|
||||||
goto process_chain;
|
goto process_chain;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -757,8 +737,15 @@ process_chain:
|
|||||||
* No DEAD tuple was found, so the chain is entirely composed of
|
* No DEAD tuple was found, so the chain is entirely composed of
|
||||||
* normal, unchanged tuples. Leave it alone.
|
* normal, unchanged tuples. Leave it alone.
|
||||||
*/
|
*/
|
||||||
for (int i = 0; i < nchain; i++)
|
int i = 0;
|
||||||
heap_prune_record_unchanged(prstate, chainitems[i]);
|
|
||||||
|
if (ItemIdIsRedirected(rootlp))
|
||||||
|
{
|
||||||
|
heap_prune_record_unchanged_lp_redirect(prstate, rootoffnum);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
for (; i < nchain; i++)
|
||||||
|
heap_prune_record_unchanged_lp_normal(page, htsv, prstate, chainitems[i]);
|
||||||
}
|
}
|
||||||
else if (ndeadchain == nchain)
|
else if (ndeadchain == nchain)
|
||||||
{
|
{
|
||||||
@ -784,7 +771,7 @@ process_chain:
|
|||||||
|
|
||||||
/* the rest of tuples in the chain are normal, unchanged tuples */
|
/* the rest of tuples in the chain are normal, unchanged tuples */
|
||||||
for (int i = ndeadchain; i < nchain; i++)
|
for (int i = ndeadchain; i < nchain; i++)
|
||||||
heap_prune_record_unchanged(prstate, chainitems[i]);
|
heap_prune_record_unchanged_lp_normal(page, htsv, prstate, chainitems[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,9 +881,81 @@ heap_prune_record_unused(PruneState *prstate, OffsetNumber offnum, bool was_norm
|
|||||||
prstate->ndeleted++;
|
prstate->ndeleted++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record a line pointer that is left unchanged */
|
/*
|
||||||
|
* Record an unused line pointer that is left unchanged.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
heap_prune_record_unchanged(PruneState *prstate, OffsetNumber offnum)
|
heap_prune_record_unchanged_lp_unused(Page page, PruneState *prstate, OffsetNumber offnum)
|
||||||
|
{
|
||||||
|
Assert(!prstate->processed[offnum]);
|
||||||
|
prstate->processed[offnum] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record LP_NORMAL line pointer that is left unchanged.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
heap_prune_record_unchanged_lp_normal(Page page, int8 *htsv, PruneState *prstate, OffsetNumber offnum)
|
||||||
|
{
|
||||||
|
HeapTupleHeader htup;
|
||||||
|
|
||||||
|
Assert(!prstate->processed[offnum]);
|
||||||
|
prstate->processed[offnum] = true;
|
||||||
|
|
||||||
|
switch (htsv[offnum])
|
||||||
|
{
|
||||||
|
case HEAPTUPLE_LIVE:
|
||||||
|
case HEAPTUPLE_INSERT_IN_PROGRESS:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we wanted to optimize for aborts, we might consider marking
|
||||||
|
* the page prunable when we see INSERT_IN_PROGRESS. But we
|
||||||
|
* don't. See related decisions about when to mark the page
|
||||||
|
* prunable in heapam.c.
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEAPTUPLE_RECENTLY_DEAD:
|
||||||
|
case HEAPTUPLE_DELETE_IN_PROGRESS:
|
||||||
|
|
||||||
|
htup = (HeapTupleHeader) PageGetItem(page, PageGetItemId(page, offnum));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This tuple may soon become DEAD. Update the hint field so that
|
||||||
|
* the page is reconsidered for pruning in future.
|
||||||
|
*/
|
||||||
|
heap_prune_record_prunable(prstate,
|
||||||
|
HeapTupleHeaderGetUpdateXid(htup));
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
/*
|
||||||
|
* DEAD tuples should've been passed to heap_prune_record_dead()
|
||||||
|
* or heap_prune_record_unused() instead.
|
||||||
|
*/
|
||||||
|
elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result %d", htsv[offnum]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record line pointer that was already LP_DEAD and is left unchanged.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
heap_prune_record_unchanged_lp_dead(Page page, PruneState *prstate, OffsetNumber offnum)
|
||||||
|
{
|
||||||
|
Assert(!prstate->processed[offnum]);
|
||||||
|
prstate->processed[offnum] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Record LP_REDIRECT that is left unchanged.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
heap_prune_record_unchanged_lp_redirect(PruneState *prstate, OffsetNumber offnum)
|
||||||
{
|
{
|
||||||
Assert(!prstate->processed[offnum]);
|
Assert(!prstate->processed[offnum]);
|
||||||
prstate->processed[offnum] = true;
|
prstate->processed[offnum] = true;
|
||||||
|
Reference in New Issue
Block a user