=== Applying patches on top of PostgreSQL commit ID f0178deecbb56283fda8f4c504c8fe16ce23e1a6 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Thu Aug 6 22:46:33 UTC 2026 On branch cf/6806 nothing to commit, working tree clean === using 'git am' to apply patch ./v3-0001-Avoid-stale-slot-access-after-dropping-obsolete-s.patch === Applying: Avoid stale slot access after dropping obsolete synced slots Using index info to reconstruct a base tree... M src/backend/replication/logical/slotsync.c Falling back to patching base and 3-way merge... Auto-merging src/backend/replication/logical/slotsync.c CONFLICT (content): Merge conflict in src/backend/replication/logical/slotsync.c error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Avoid stale slot access after dropping obsolete synced slots When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v3-0001-Avoid-stale-slot-access-after-dropping-obsolete-s.patch === patching file src/backend/replication/logical/slotsync.c Hunk #1 FAILED at 541. Hunk #2 FAILED at 548. Hunk #3 FAILED at 559. Hunk #4 FAILED at 566. 4 out of 4 hunks FAILED -- saving rejects to file src/backend/replication/logical/slotsync.c.rej Removing src/backend/replication/logical/slotsync.c.rej === using 'git apply' to apply patch ./v3-0001-Avoid-stale-slot-access-after-dropping-obsolete-s.patch === Applied patch to 'src/backend/replication/logical/slotsync.c' with conflicts. U src/backend/replication/logical/slotsync.c diff --cc src/backend/replication/logical/slotsync.c index c0403893e23,a22d0515d48..00000000000 --- a/src/backend/replication/logical/slotsync.c +++ b/src/backend/replication/logical/slotsync.c @@@ -558,18 -557,19 +558,34 @@@ drop_local_obsolete_slots(List *remote_ * locking the database, there is a possibility of a parallel * database drop by the startup process and the creation of a new * slot by the user. This new user-created slot may end up using ++<<<<<<< ours + * the same shared memory as that of 'local_slot'. + * + * Because local_slot still points to a reusable slot-array entry, + * its fields (name, database OID, invalidation state) may already + * describe such a replacement slot by the time we reach here. + * That means the drop decision made by local_sync_slot_required() + * above could have been based on the replacement slot's data, and + * slot_database could refer to an unrelated database. The recheck + * below keeps us from actually dropping a user-created + * replacement slot; the residual risk is confined to this cycle + * (for example, briefly locking an unrelated database) and is + * acceptable because the race is rare and non-fatal. ++======= + * the same shared memory as that of 'local_slot'. Thus check if + * local_slot is still the synced one before performing the actual + * drop. + * + * We cannot close this window by holding + * ReplicationSlotControlLock while taking the database lock, + * because the database-drop path holds the database lock and then + * scans replication slots. Therefore, local_slot may already + * refer to a reused slot-array entry here, and fields such as + * name or database OID could already be stale. That could cause + * an incorrect cleanup decision for this cycle or briefly lock an + * unrelated database. We accept that risk because this race is + * rare and non-fatal. ++>>>>>>> theirs */ SpinLockAcquire(&local_slot->mutex); synced_slot = local_slot->in_use && local_slot->data.synced;