Skip to content

TruncateMultiXact panics on the standard post-VACUUM path once relminmxid can advance #60

Description

@MauricioPerera

Summary

vac_truncate_clog (crates/backend/commands/vacuum/src/lib.rs:1439), which runs after every VACUUM (manual or autovacuum) once per-database frozen/minmxid horizons are recomputed, calls TruncateMultiXact (crates/backend/access/transam/multixact/src/lib.rs:1940-1956). That function has an early-return-only fast path; as soon as new_oldest_multi actually advances past the current oldestMultiXactId — i.e. any time relminmxid legitimately advances across all tables in the database — it hits:

panic!("unported caller path reached: TruncateMultiXact (multixact.c) — vacuum lane \
 (vac_truncate_clog); needs delay-chkpt seam + WAL truncate record");

Why this matters

This is not a rare/edge-case trigger. Any workload that uses row locking (SELECT FOR UPDATE/SELECT FOR SHARE), foreign keys, or multi-transaction updates will produce MultiXacts, and any subsequent VACUUM cycle that legitimately retires old MultiXacts (i.e. normal, expected steady-state operation, not just anti-wraparound emergency vacuum) will hit this panic. This effectively crashes the vacuum lane under ordinary sustained usage, not just at wraparound extremes.

Reproduction sketch

  1. Create a table, run transactions that produce MultiXacts (e.g. concurrent SELECT ... FOR UPDATE from multiple sessions on overlapping rows, or FK-referencing updates).
  2. Let enough VACUUM cycles run (manual VACUUM or autovacuum) that relminmxid can advance database-wide.
  3. Observe panic in TruncateMultiXact from vac_truncate_clog.

Root cause (as far as I could tell from source only — not runtime-reproduced)

The porting of multixact.c's TruncateMultiXact appears to have stopped at the fast-path/no-op case. The actual truncation logic — including the delay-chkpt seam (the checkpoint-delay interlock the real function uses to avoid concurrent-checkpoint races) and the corresponding WAL truncate record — is explicitly marked unported in the panic message itself.

Suggested scope for a fix

Port the remaining body of TruncateMultiXact from multixact.c, specifically:

  • the delay-checkpoint interlock around the truncation
  • segment-boundary computation and SlruDeleteSegment-equivalent calls for members/offsets SLRUs
  • the WAL record for multixact truncation (XLOG_MULTIXACT_TRUNCATE_ID equivalent) so truncation is crash-safe and replayed correctly on recovery

Environment / where found

Found via static source review of a fresh clone of this repo. Have not attempted to build/run pgrust myself to runtime-confirm the panic; this report is based on reading crates/backend/access/transam/multixact/src/lib.rs and crates/backend/commands/vacuum/src/lib.rs directly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions