Notice that heap page has dead items during VACUUM.
authorPeter Geoghegan <[email protected]>
Mon, 15 Mar 2021 01:05:57 +0000 (18:05 -0700)
committerPeter Geoghegan <[email protected]>
Mon, 15 Mar 2021 01:05:57 +0000 (18:05 -0700)
Consistently set a flag variable that tracks whether the current heap
page has a dead item during lazy vacuum's heap scan.  We missed the
common case where there is an preexisting (or even a new) LP_DEAD heap
line pointer.

Also make it clear that the variable might be affected by an existing
line pointer, say from an earlier opportunistic pruning operation.  This
distinction is important because it's the main reason why we can't just
use the nearby tups_vacuumed variable instead.

No backpatch.  In theory failing to set the page level flag variable had
no consequences.  Currently it is only used to defensively check if a
page marked all visible has dead items, which should never happen anyway
(if it does then the table must be corrupt).

Author: Masahiko Sawada <[email protected]>
Diagnosed-By: Masahiko Sawada <[email protected]>
Discussion: https://postgr.es/m/CAD21AoAtZb4+HJT_8RoOXvu4HM-Zd4HKS3YSMCH6+-W=bDyh-w@mail.gmail.com

src/backend/access/heap/vacuumlazy.c

index a65dcbebfa8df30ca605ca31bdb0c4b79ac8fa52..366c122bd1ee62d9a770a32c28e4d2133721fced 100644 (file)
@@ -945,7 +945,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
        bool        all_visible_according_to_vm = false;
        bool        all_visible;
        bool        all_frozen = true;  /* provided all_visible is also true */
-       bool        has_dead_tuples;
+       bool        has_dead_items;     /* includes existing LP_DEAD items */
        TransactionId visibility_cutoff_xid = InvalidTransactionId;
 
        /* see note above about forcing scanning of last page */
@@ -1248,7 +1248,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
         * requiring freezing.
         */
        all_visible = true;
-       has_dead_tuples = false;
+       has_dead_items = false;
        nfrozen = 0;
        hastup = false;
        prev_dead_count = dead_tuples->num_tuples;
@@ -1300,6 +1300,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
            {
                lazy_record_dead_tuple(dead_tuples, &(tuple.t_self));
                all_visible = false;
+               has_dead_items = true;
                continue;
            }
 
@@ -1448,7 +1449,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
                HeapTupleHeaderAdvanceLatestRemovedXid(tuple.t_data,
                                                       &vacrelstats->latestRemovedXid);
                tups_vacuumed += 1;
-               has_dead_tuples = true;
+               has_dead_items = true;
            }
            else
            {
@@ -1527,7 +1528,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
                /* Remove tuples from heap if the table has no index */
                lazy_vacuum_page(onerel, blkno, buf, 0, vacrelstats, &vmbuffer);
                vacuumed_pages++;
-               has_dead_tuples = false;
+               has_dead_items = false;
            }
            else
            {
@@ -1625,7 +1626,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
         * There should never be dead tuples on a page with PD_ALL_VISIBLE
         * set, however.
         */
-       else if (PageIsAllVisible(page) && has_dead_tuples)
+       else if (PageIsAllVisible(page) && has_dead_items)
        {
            elog(WARNING, "page containing dead tuples is marked as all-visible in relation \"%s\" page %u",
                 vacrelstats->relname, blkno);