VACUUM can set pages all-frozen without also setting them all-visible - Mailing list pgsql-bugs

From Peter Geoghegan
Subject VACUUM can set pages all-frozen without also setting them all-visible
Date
Msg-id CAH2-WznOKC4SS-7wHfjBpwc5meekzs+Yr8Gux5nFm7-VN3xMmA@mail.gmail.com
Whole thread Raw
Responses Re: VACUUM can set pages all-frozen without also setting them all-visible  (Peter Geoghegan <pg@bowt.ie>)
List pgsql-bugs
Attached are two patches. The first patch adds assertions that verify
that calls to visibilitymap_set() don't set VISIBILITYMAP_ALL_FROZEN
for a page without also setting VISIBILITYMAP_ALL_VISIBLE (plus a
similar assertion for visibilitymap_clear()). When I run "make
check-world" with just the first patch, several tests fail because one
of the new assertions fails.

The second patch tentatively addresses the issue by making two of the
calls to visibilitymap_set() made by vacuumlazy.c set
VISIBILITYMAP_ALL_VISIBLE | VISIBILITYMAP_ALL_FROZEN -- as opposed to
just setting VISIBILITYMAP_ALL_FROZEN, which is what happens on HEAD.

It's not clear whether or not it's strictly correct to only set
VISIBILITYMAP_ALL_FROZEN, but it seems questionable. It's also likely
to have negative performance implications. Non-aggressive VACUUMs
won't actually use VISIBILITYMAP_ALL_FROZEN to skip -- they could in
principle, but they don't.

VACUUM's skipping logic doesn't just refuse to skip
VISIBILITYMAP_ALL_VISIBLE pages during an aggressive VACUUM (which is
necessary and makes sense); it also refuses to skip
VISIBILITYMAP_ALL_FROZEN pages during non-aggressive VACUUMs. And so
any page that just has its VISIBILITYMAP_ALL_FROZEN bit set is not
skippable by non-aggressive VACUUMs. I'm referring to this code:

                while (next_unskippable_block < rel_pages)
                {
                    uint8       vmskipflags;

                    vmskipflags = visibilitymap_get_status(vacrel->rel,

next_unskippable_block,
                                                           &vmbuffer);
                    if (vacrel->aggressive)
                    {
                        if ((vmskipflags & VISIBILITYMAP_ALL_FROZEN) == 0)
                            break;
                    }
                    else
                    {
                        if ((vmskipflags & VISIBILITYMAP_ALL_VISIBLE) == 0)
                            break;
                    }
                    vacuum_delay_point();
                    next_unskippable_block++;
                }

-- 
Peter Geoghegan

Attachment

pgsql-bugs by date:

Previous
From: "David G. Johnston"
Date:
Subject: Re: BUG #17439: DROP FUNCTION functionName(); drops associated generated column without using CASCADE
Next
From: Peter Geoghegan
Date:
Subject: Re: VACUUM can set pages all-frozen without also setting them all-visible