Fix race condition when enabling logical decoding concurrently.

With wal_level = 'replica', logical decoding is enabled on demand
when the first logical replication slot is created:

When enabling logical decoding, EnableLogicalDecoding() flips the
shared logical_decoding_enabled flag and writes an
XLOG_LOGICAL_DECODING_STATUS_CHANGE record so that standbys follow the
status change. The initial "already enabled?" check and the WAL record
write happen under two separate acquisitions of
LogicalDecodingControlLock, since the lock must be released while
waiting for the ProcSignalBarrier: processes absorbing the barrier
acquire the same lock in shared mode.

Consequently, if two backends concurrently created the first logical
slots, both could pass the initial check and both write a
status-change record. The redundant record lands after the decoding
start point already reserved by the other backend's slot, so decoding
that slot processes the record and fails with "unexpected logical
decoding status change", as xlog_decode() assumes that no such record
can appear within the WAL range any slot decodes.

Fix by re-checking the status after re-acquiring the lock, so that
only the backend that actually performs the disabled->enabled
transition writes the WAL record.

Reported-by: Srinath Reddy Sadipiralla <[email protected]>
Author: Srinath Reddy Sadipiralla <[email protected]>
Reviewed-by: Masahiko Sawada <[email protected]>
Reviewed-by: Amit Kapila <[email protected]>
Discussion: 
https://postgr.es/m/cafc+b6oyzmagp7f0ivrhfzt46-cjvctru9pwumncem-52yj...@mail.gmail.com
Backpatch-through: 19

Branch
------
master

Details
-------
https://git.postgresql.org/pg/commitdiff/0fd30e2119ede879080cef426abf4f9b304e3f51

Modified Files
--------------
src/backend/replication/logical/logicalctl.c   | 11 +++++
src/test/recovery/t/051_effective_wal_level.pl | 61 ++++++++++++++++++++++++--
2 files changed, 69 insertions(+), 3 deletions(-)

Reply via email to