postgres.git / summary / log / commit / refs

commit    d4420a97206cad5bcf63405062db5b4ebaa7f2b1
Author:   Tomas Vondra <tomas.vondra@postgresql.org>
Date:     Thu Jul 30 12:06:20 2026 +0000
First released in: 18.6

    Initialize bs_reltuples in parallel GIN builds
    
    Index builds update pg_class.reltuples for the table. In parallel GIN
    builds, workers track the number of processed rows, and report it to
    the leader, who then updates the pg_class with a total. However,
    gin_parallel_build_main failed to initialize the bs_reltuples field,
    leaving it set to whatever happens to be on the stack (which may be
    bogus values like Infinity or NaN, or just impossibly high values).
    
    If such values get reported to the leader and stored in pg_class, that
    can have serious consequences. The pg_class.reltuples field is used to
    decide when a table is due for autovacuum or autoanalyze, and if it
    happens to be set to a bogus value, that may never happen. The field is
    also used by the optimizer when calculating costs.
    
    Fixed by initializing bs_reltuples together with the rest of the build
    state. The bs_numtuples was initialized later, but it seems cleaner to
    just initialize all the fields at once.
    
    After a bogus value gets persisted in pg_class, affected systems are
    unlikely to self-heal. That would require an ANALYZE, but preventing
    that is one of the consequences. We have considered forcing autoanalyze
    in these cases, but there's not a good way to reliably identify bogus
    values (except for a small minority like Infitiny/NaN).
    
    A manual ANALYZE on (possibly) affected tables is the only solution.
    
    Backpatch to 18, where parallel GIN builds were introduced.
    
    Reported-by: Jan Nidzwetzki <jan@planetscale.com>
    Discussion: https://postgr.es/m/518BA772-8026-412A-AA8F-A7FE4C6B3717@planetscale.com
    Backpatch-through: 18


src/backend/access/gin/gininsert.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index a72e531167b..a575afacab3 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -1867,9 +1867,6 @@ _gin_process_worker_data(GinBuildState *state, Tuplesortstate *worker_sort, tuplesort_performsort(state->bs_worker_sort); - /* reset the number of GIN tuples produced by this worker */ - state->bs_numtuples = 0; - if (progress) pgstat_progress_update_param(PROGRESS_CREATEIDX_SUBPHASE, PROGRESS_GIN_PHASE_MERGE_1); @@ -2149,6 +2146,11 @@ _gin_parallel_build_main(dsm_segment *seg, shm_toc *toc) /* initialize the GIN build state */ initGinState(&buildstate.ginstate, indexRel); buildstate.indtuples = 0; + + /* Initialize counters used to report tuple counts to the leader */ + buildstate.bs_numtuples = 0; + buildstate.bs_reltuples = 0; + memset(&buildstate.buildStats, 0, sizeof(GinStatsData)); memset(&buildstate.tid, 0, sizeof(ItemPointerData)); [parent: 0abdb3e3610e]