From 8cd06e36cf10554df8bc2d0b126c1efca92edfe1 Mon Sep 17 00:00:00 2001 From: Alena Rybakina Date: Fri, 18 Sep 2026 19:54:26 +0300 Subject: [PATCH] Fix flaky stats check in vacuum_progress_row/column tests The tests read pg_stat_all_tables right after the DELETE, while the stats of the aborted inserts may not have arrived yet and those of the DELETE may already have. Wait for the stats of the aborts and read the view before the DELETE instead. --- .../expected/vacuum_progress_column.out | 22 ++++++++++++++----- .../expected/vacuum_progress_row.out | 22 ++++++++++++++----- .../isolation2/sql/vacuum_progress_column.sql | 10 +++++++-- .../isolation2/sql/vacuum_progress_row.sql | 10 +++++++-- 4 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/test/isolation2/expected/vacuum_progress_column.out b/src/test/isolation2/expected/vacuum_progress_column.out index 587bd35f7c8..92265df87dc 100644 --- a/src/test/isolation2/expected/vacuum_progress_column.out +++ b/src/test/isolation2/expected/vacuum_progress_column.out @@ -41,21 +41,31 @@ ABORT 1: ABORT; ABORT +-- Look up the collected stats before the DELETE below. The stats collector +-- is asynchronous: wait until it has received the dead tuples of both +-- aborted inserts, and read the view before the DELETE, whose own counts +-- may reach the collector at any moment after it. +1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_column'::regclass::oid, 200000); + wait_until_dead_tup_change_to +------------------------------- + OK +(1 row) +SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; + n_live_tup | n_dead_tup | last_vacuum | vacuum_count +------------+------------+-------------+-------------- + 100000 | 200000 | | 0 +(1 row) + -- Also delete half of the tuples evenly before the EOF of segno 2. DELETE FROM vacuum_progress_ao_column where j % 2 = 0; DELETE 50000 --- Lookup pg_class and collected stats view before VACUUM +-- Lookup pg_class before VACUUM SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_column'; relpages | reltuples | relallvisible ----------+-----------+--------------- 0 | -1 | 0 (1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; - n_live_tup | n_dead_tup | last_vacuum | vacuum_count -------------+------------+-------------+-------------- - 100000 | 200000 | | 0 -(1 row) -- Perform VACUUM and observe the progress diff --git a/src/test/isolation2/expected/vacuum_progress_row.out b/src/test/isolation2/expected/vacuum_progress_row.out index 0f1b3e65ef5..fc9cf85955e 100644 --- a/src/test/isolation2/expected/vacuum_progress_row.out +++ b/src/test/isolation2/expected/vacuum_progress_row.out @@ -41,21 +41,31 @@ ABORT 1: ABORT; ABORT +-- Look up the collected stats before the DELETE below. The stats collector +-- is asynchronous: wait until it has received the dead tuples of both +-- aborted inserts, and read the view before the DELETE, whose own counts +-- may reach the collector at any moment after it. +1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_row'::regclass::oid, 200000); + wait_until_dead_tup_change_to +------------------------------- + OK +(1 row) +SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; + n_live_tup | n_dead_tup | last_vacuum | vacuum_count +------------+------------+-------------+-------------- + 100000 | 200000 | | 0 +(1 row) + -- Also delete half of the tuples evenly before the EOF of segno 2. DELETE FROM vacuum_progress_ao_row where j % 2 = 0; DELETE 50000 --- Lookup pg_class and collected stats view before VACUUM +-- Lookup pg_class before VACUUM SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; relpages | reltuples | relallvisible ----------+-----------+--------------- 0 | -1 | 0 (1 row) -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; - n_live_tup | n_dead_tup | last_vacuum | vacuum_count -------------+------------+-------------+-------------- - 100000 | 200000 | | 0 -(1 row) -- Perform VACUUM and observe the progress diff --git a/src/test/isolation2/sql/vacuum_progress_column.sql b/src/test/isolation2/sql/vacuum_progress_column.sql index 648d43303be..e18d482d57c 100644 --- a/src/test/isolation2/sql/vacuum_progress_column.sql +++ b/src/test/isolation2/sql/vacuum_progress_column.sql @@ -27,12 +27,18 @@ CREATE INDEX on vacuum_progress_ao_column(j); -- Abort so that segno 1 has logical EOF = 0. 1: ABORT; +-- Look up the collected stats before the DELETE below. The stats collector +-- is asynchronous: wait until it has received the dead tuples of both +-- aborted inserts, and read the view before the DELETE, whose own counts +-- may reach the collector at any moment after it. +1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_column'::regclass::oid, 200000); +SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; + -- Also delete half of the tuples evenly before the EOF of segno 2. DELETE FROM vacuum_progress_ao_column where j % 2 = 0; --- Lookup pg_class and collected stats view before VACUUM +-- Lookup pg_class before VACUUM SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_column'; -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_column'; -- Perform VACUUM and observe the progress diff --git a/src/test/isolation2/sql/vacuum_progress_row.sql b/src/test/isolation2/sql/vacuum_progress_row.sql index 1ccf6ca090f..bf56a5c5e48 100644 --- a/src/test/isolation2/sql/vacuum_progress_row.sql +++ b/src/test/isolation2/sql/vacuum_progress_row.sql @@ -27,12 +27,18 @@ CREATE INDEX on vacuum_progress_ao_row(j); -- Abort so that segno 1 has logical EOF = 0. 1: ABORT; +-- Look up the collected stats before the DELETE below. The stats collector +-- is asynchronous: wait until it has received the dead tuples of both +-- aborted inserts, and read the view before the DELETE, whose own counts +-- may reach the collector at any moment after it. +1U: SELECT wait_until_dead_tup_change_to('vacuum_progress_ao_row'::regclass::oid, 200000); +SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; + -- Also delete half of the tuples evenly before the EOF of segno 2. DELETE FROM vacuum_progress_ao_row where j % 2 = 0; --- Lookup pg_class and collected stats view before VACUUM +-- Lookup pg_class before VACUUM SELECT relpages, reltuples, relallvisible FROM pg_class where relname = 'vacuum_progress_ao_row'; -SELECT n_live_tup, n_dead_tup, last_vacuum, vacuum_count FROM pg_stat_all_tables WHERE relname = 'vacuum_progress_ao_row'; -- Perform VACUUM and observe the progress