Re: pg14b1 stuck in lazy_scan_prune/heap_page_prune of pg_statistic - Mailing list pgsql-hackers

From Andres Freund
Subject Re: pg14b1 stuck in lazy_scan_prune/heap_page_prune of pg_statistic
Date
Msg-id 20210615012242.uduncgvn52tujwmz@alap3.anarazel.de
Whole thread Raw
In response to Re: pg14b1 stuck in lazy_scan_prune/heap_page_prune of pg_statistic  (Matthias van de Meent <boekewurm+postgres@gmail.com>)
Responses Re: pg14b1 stuck in lazy_scan_prune/heap_page_prune of pg_statistic
List pgsql-hackers
Hi,

> @@ -4032,6 +4039,24 @@ GlobalVisTestShouldUpdate(GlobalVisState *state)
>  static void
>  GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
>  {
> +    /* assert non-decreasing nature of horizons */
> +    Assert(FullTransactionIdFollowsOrEquals(
> +               FullXidRelativeTo(horizons->latest_completed,
> +                                 horizons->shared_oldest_nonremovable),
> +               GlobalVisSharedRels.maybe_needed));
> +    Assert(FullTransactionIdFollowsOrEquals(
> +               FullXidRelativeTo(horizons->latest_completed,
> +                                 horizons->catalog_oldest_nonremovable),
> +               GlobalVisCatalogRels.maybe_needed));
> +    Assert(FullTransactionIdFollowsOrEquals(
> +               FullXidRelativeTo(horizons->latest_completed,
> +                                 horizons->data_oldest_nonremovable),
> +               GlobalVisDataRels.maybe_needed));
> +    Assert(FullTransactionIdFollowsOrEquals(
> +               FullXidRelativeTo(horizons->latest_completed,
> +                                 horizons->temp_oldest_nonremovable),
> +               GlobalVisTempRels.maybe_needed));
> +
>      GlobalVisSharedRels.maybe_needed =
>          FullXidRelativeTo(horizons->latest_completed,
>                            horizons->shared_oldest_nonremovable);

Thinking more about it, I don't think these are correct. See the
following comment in procarray.c:

 * Note: despite the above, it's possible for the calculated values to move
 * backwards on repeated calls. The calculated values are conservative, so
 * that anything older is definitely not considered as running by anyone
 * anymore, but the exact values calculated depend on a number of things. For
 * example, if there are no transactions running in the current database, the
 * horizon for normal tables will be latestCompletedXid. If a transaction
 * begins after that, its xmin will include in-progress transactions in other
 * databases that started earlier, so another call will return a lower value.
 * Nonetheless it is safe to vacuum a table in the current database with the
 * first result.  There are also replication-related effects: a walsender
 * process can set its xmin based on transactions that are no longer running
 * on the primary but are still being replayed on the standby, thus possibly
 * making the values go backwards.  In this case there is a possibility that
 * we lose data that the standby would like to have, but unless the standby
 * uses a replication slot to make its xmin persistent there is little we can
 * do about that --- data is only protected if the walsender runs continuously
 * while queries are executed on the standby.  (The Hot Standby code deals
 * with such cases by failing standby queries that needed to access
 * already-removed data, so there's no integrity bug.)  The computed values
 * are also adjusted with vacuum_defer_cleanup_age, so increasing that setting
 * on the fly is another easy way to make horizons move backwards, with no
 * consequences for data integrity.

Greetings,

Andres Freund



pgsql-hackers by date:

Previous
From: Kyotaro Horiguchi
Date:
Subject: Re: Duplicate history file?
Next
From: Bruce Momjian
Date:
Subject: Re: PG 14 release notes, first draft