test/sql/segment_reclaim.sql asserts that deferred-free pages have been reclaimed without first checking that the reclaim horizon can actually advance. It fails intermittently in CI, most often under the sanitizer build.
Observed on the PG18.1 Sanitizer job:
parked_after_vacuum
-------------------
- 0
+ 12
reused_freed_pages_no_extension
--------------------------------
- t
+ f
Both jobs passed on a plain re-run, with no code change.
Cause
The test tries to advance the horizon by burning two transaction ids:
-- test/sql/segment_reclaim.sql:34-39
SELECT txid_current() IS NOT NULL AS t1;
SELECT txid_current() IS NOT NULL AS t2;
VACUUM reclaim_t;
SELECT bm25_pending_free_pages('reclaim_idx') AS parked_after_vacuum;
Displaced segment pages return to the FSM only once VACUUM observes that the
merge's stamp precedes GetOldestNonRemovableTransactionId. Burning xids does
not move that horizon if another backend in the same database holds an xmin —
it is bounded by the oldest live snapshot, not by the latest xid. When anything
else is holding a snapshot, the pages stay parked and the assertion fails.
The sanitizer build is slow enough to widen that window considerably, which is
why it shows up there first, but nothing about the race is sanitizer-specific.
Precedent
test/sql/memtable_reclaim.sql guards the same class of assertion:
-- test/sql/memtable_reclaim.sql:11-21
CREATE FUNCTION other_backend_holds_xmin() RETURNS boolean
LANGUAGE sql STABLE AS $$
SELECT EXISTS (
SELECT 1
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND datname = current_database()
AND backend_type = 'client backend'
AND backend_xmin IS NOT NULL
);
$$;
segment_reclaim.sql has no equivalent.
Suggested fix
Port the guard and make the four horizon-sensitive assertions conditional on
it, so the test still verifies reclaim when the horizon is free and degrades to
a skip rather than a failure when it is pinned. The affected assertions are
parked_after_vacuum (line 39), reused_freed_pages_no_extension (line 64),
parked_after_vacuum_drain (line 111), and
vacuum_reused_freed_pages_no_extension (line 122).
Note that the guard as written only covers client backend entries in
pg_stat_activity. A standby with hot_standby_feedback = on publishes its
xmin through pg_replication_slots.xmin instead, so a complete check should
consult both. That does not matter for installcheck, but it would for any
reclaim assertion reused in the replication suite.
test/sql/segment_reclaim.sqlasserts that deferred-free pages have been reclaimed without first checking that the reclaim horizon can actually advance. It fails intermittently in CI, most often under the sanitizer build.Observed on the PG18.1 Sanitizer job:
Both jobs passed on a plain re-run, with no code change.
Cause
The test tries to advance the horizon by burning two transaction ids:
Displaced segment pages return to the FSM only once VACUUM observes that the
merge's stamp precedes
GetOldestNonRemovableTransactionId. Burning xids doesnot move that horizon if another backend in the same database holds an xmin —
it is bounded by the oldest live snapshot, not by the latest xid. When anything
else is holding a snapshot, the pages stay parked and the assertion fails.
The sanitizer build is slow enough to widen that window considerably, which is
why it shows up there first, but nothing about the race is sanitizer-specific.
Precedent
test/sql/memtable_reclaim.sqlguards the same class of assertion:segment_reclaim.sqlhas no equivalent.Suggested fix
Port the guard and make the four horizon-sensitive assertions conditional on
it, so the test still verifies reclaim when the horizon is free and degrades to
a skip rather than a failure when it is pinned. The affected assertions are
parked_after_vacuum(line 39),reused_freed_pages_no_extension(line 64),parked_after_vacuum_drain(line 111), andvacuum_reused_freed_pages_no_extension(line 122).Note that the guard as written only covers
client backendentries inpg_stat_activity. A standby withhot_standby_feedback = onpublishes itsxmin through
pg_replication_slots.xmininstead, so a complete check shouldconsult both. That does not matter for
installcheck, but it would for anyreclaim assertion reused in the replication suite.