Re: Confine vacuum skip logic to lazy_scan_skip

Melanie Plageman <melanieplageman@gmail.com>

From: Melanie Plageman <melanieplageman@gmail.com>
To: Masahiko Sawada <sawada.mshk@gmail.com>
Cc: Tomas Vondra <tomas@vondra.me>, Thomas Munro <thomas.munro@gmail.com>, Noah Misch <noah@leadboat.com>, vignesh C <vignesh21@gmail.com>, Andres Freund <andres@anarazel.de>, Pg Hackers <pgsql-hackers@postgresql.org>, Heikki Linnakangas <hlinnaka@iki.fi>, Nazir Bilal Yavuz <byavuz81@gmail.com>, Robert Haas <robertmhaas@gmail.com>, "Andrey M. Borodin" <x4mmm@yandex-team.ru>
Date: 2025-02-14T00:54:52Z
Lists: pgsql-hackers

Attachments

Thanks for your review! I've made the changes in attached v18.

I do want to know what you think we should do about what you brought
up about lazy_check_wraparound_failsafe() -- given my reply (below).

On Thu, Feb 13, 2025 at 6:08 PM Masahiko Sawada <sawada.mshk@gmail.com> wrote:
>
> Sorry for the late chiming in. I've reviewed the v16 patch set, and
> the patches mostly look good. Here are some comments mostly about
> cosmetic things:
>
> 0001:
>
> -   bool        all_visible_according_to_vm,
> -               was_eager_scanned = false;
> +   uint8       blk_flags = 0;
>
> Can we probably declare blk_flags inside the main loop?

I've done this in 0002 (can't in 0001 because of it being used inside
the while loop itself).

> 0002:
>
> In lazy_scan_heap(), we have a failsafe check at the beginning of the
> main loop, which is performed before reading the first block. Isn't it
> better to move this check after scanning a block (especially after
> incrementing scanned_pages)? Otherwise, we would end up calling
> lazy_check_wraparound_failsafe() at the very first loop, which
> previously didn't happen without the patch. Since we already called
> lazy_check_wraparound_failsafe() just before calling lazy_scan_heap(),
> the extra check would not make much sense.

Yes, I agonized over this a bit. The problem with calling
lazy_check_wraparound_failsafe() (and vacuum_delay_point() especially)
after reading the first block is that read_stream_next_buffer()
returns the buffer pinned. We don't want to hang onto that pin for a
long time. But I can't move them to the bottom of the loop after we
release the buffer because some of the code paths don't make it that
far. I don't see a good way other than how I did it or special-casing
block 0. What do you think?

> ---
> +   /* Set up the read stream for vacuum's first pass through the heap */
> +   stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE,
> +                                       vacrel->bstrategy,
> +                                       vacrel->rel,
> +                                       MAIN_FORKNUM,
> +                                       heap_vac_scan_next_block,
> +                                       vacrel,
> +                                       sizeof(bool));
>
> Is there any reason to use sizeof(bool) instead of sizeof(uint8) here?

Nope. That was a buglet (fixed in my v17 but I'm glad you caught it
too). Thanks!

>             /*
>              * Vacuum the Free Space Map to make newly-freed space visible on
> -            * upper-level FSM pages.  Note we have not yet processed blkno.
> +            * upper-level FSM pages.  Note that blkno is the previously
> +            * processed block.
>              */
>             FreeSpaceMapVacuumRange(vacrel->rel, next_fsm_block_to_vacuum,
>                                     blkno);
>
> Given the blkno is already processed, should we pass 'blkno + 1'
> instead of blkno?

Good idea! Done in attached v18.

> 0003:
>
> -   while ((iter_result = TidStoreIterateNext(iter)) != NULL)
>
> I think we can declare iter_result in the main loop of lazy_vacuum_heap_rel().

Done.

- Melanie

Commits

  1. Fix explicit valgrind interaction in read_stream.c.

  2. Reduce scope of heap vacuum per_buffer_data

  3. Use streaming read I/O in VACUUM's third phase

  4. Use streaming read I/O in VACUUM's first phase

  5. Convert heap_vac_scan_next_block() boolean parameters to flags

  6. Refactor tidstore.c iterator buffering.

  7. Increase default vacuum_buffer_usage_limit to 2MB.

  8. Remove unneeded vacuum_delay_point from heap_vac_scan_get_next_block

  9. Confine vacuum skip logic to lazy_scan_skip()

  10. Set all_visible_according_to_vm correctly with DISABLE_PAGE_SKIPPING

  11. Tighten up VACUUM's approach to setting VM bits.