Monthly Summary: effective_wal_level Not Decreasing After REPACK (CONCURRENTLY) — May 2026
Problem Statement
A bug was identified in the interaction between PostgreSQL's dynamic WAL level toggling feature (commit 67c2097) and the REPACK (CONCURRENTLY) command (commit 28d534e). When REPACK (CONCURRENTLY) executes, it creates a temporary logical replication slot internally for online table reorganization. This correctly elevates effective_wal_level to logical. However, when REPACK completes and drops the temporary slot during cleanup (repack_cleanup_logical_decoding), it fails to call RequestDisableLogicalDecoding(), leaving effective_wal_level permanently stuck at logical until a server restart.
This causes unnecessary WAL volume increases (full tuple data for UPDATE/DELETE), increased I/O and replication bandwidth, and violates the design contract of the dynamic WAL level toggling feature.
Solution Evolution
v1: Point Fix
The initial patch simply added RequestDisableLogicalDecoding() to repack_cleanup_logical_decoding() after the slot is dropped.
v2: API Redesign
The discussion evolved into a broader infrastructure change. Rather than patching individual call sites, the signature of ReplicationSlotDropAcquired() was changed to:
ReplicationSlotDropAcquired(bool disable_logical_decoding)
This "pit of success" API design forces every caller to explicitly declare whether logical decoding should be re-evaluated upon slot drop. The boolean flag exists to support ReplicationSlotsDropDBSlots(), which drops multiple slots in a loop and only needs a single disable request after completion, rather than N redundant calls.
v3: Final Refinements (Reviewed and Approved)
Three improvements from code review:
- Updated function comment documenting the new parameter's interaction with the checkpointer
- Runtime assertion:
Assert(!disable_logical_decoding || SlotIsLogical(MyReplicationSlot))— prevents nonsensical requests to disable logical decoding when dropping a physical slot - Explanatory comment for the
falsecase indrop_local_obsolete_slots()on physical standbys, where logical decoding state is derived from the upstream primary
Current Status
The v3 patch has been reviewed and approved by Shveta Malik. It awaits committer attention. The thread has converged on the API-level approach, which serves as both a fix and a forced audit of all slot-dropping code paths in the system.