Skip to content

Flaky segment_reclaim test: reclaim assertions lack a horizon guard #509

Description

@tjgreen42

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions