Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVr2F-002EUk-0C for pgsql-hackers@arkaria.postgresql.org; Sat, 06 Jun 2026 13:25:59 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wVr2C-00G6ZM-27 for pgsql-hackers@arkaria.postgresql.org; Sat, 06 Jun 2026 13:25:56 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wVr2C-00G6ZD-0n for pgsql-hackers@lists.postgresql.org; Sat, 06 Jun 2026 13:25:56 +0000 Received: from mail-ed1-x535.google.com ([2a00:1450:4864:20::535]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wVr2A-00000001Okj-0MER for pgsql-hackers@lists.postgresql.org; Sat, 06 Jun 2026 13:25:55 +0000 Received: by mail-ed1-x535.google.com with SMTP id 4fb4d7f45d1cf-68e5f7c1131so5289798a12.2 for ; Sat, 06 Jun 2026 06:25:53 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1780752352; cv=none; d=google.com; s=arc-20240605; b=VuqtupTX3uNnBxfY0tCLkg86LKYM+e5Ui11PlXT9hO80Zt+8JwKiBX7DfWe7mo5eYo JTa+ac3eLgw0TlExBE/h09IIQ7B1XZHu5C/WmKLUxqLtn7CepjjU8Q73LSQIKIgaWZaE hjpPc2m9xfWqriVcccHqOCYTu4yzkw7+cHwoXMqKzLat37mu2gMsvDnVX/fUXUNs5Xrd gx8EnQoO2HRrMY2a9YI+N/MckQwslv5tyXD08E3n0sBOeX/Y4lGuWlWMV70hH9VUxD1J RIgjV9GHBVUbi+ZzQLtKnagvE4deo/IPYAIJOz3GL5jRsW31c97aVR/TBiBOZeSfwG8N FjAQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=CFIA4qrGwtjq3+f9Ip41dbdf/DDFhfGDaQaFDhRdMYg=; fh=wLB3sMHq+qG7g7zJCG40B7QbnPSNwWstqykaIZL+AHE=; b=Kw0b89axk4veBMHAcPV6xWs0KeJxHZDktxhjk20X8Q4a5BGdP6/6r1Ok74iss6jaSA zvug5zmmEKxD6QvLiw1JH5IJOsQ/okymk1J1hXFAyYUfdjVgbEQb/C1sRwVLFh4d2l2Q uBV7x88YDxFva6zjSUjTudeSFqnmKz8eHC11ZheLV69SxhDbB+3BHk6VuV0o4aK0p3qH 2EZ7TIBR8UTSmb3nrlJtosT8b53wf0aogbZxz91nrCbfI4ypHU/vKTwY7GB58kcl2YoH EFZA9AutaUpYCJ4cXZQ/jjC9YRBIi4gcoCm1FB/VyDBpo8wKUXvyQXY2TGLc+A5nDAvM Te6Q==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780752352; x=1781357152; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=CFIA4qrGwtjq3+f9Ip41dbdf/DDFhfGDaQaFDhRdMYg=; b=LERYHfcD6OtT8ki2KqwaL2UADEx9rxqjSqC2YtObhFqnlWN4UAO43+muiduwAuQGzW rXw2xSE6ydYzFYmyaoDOeysmVJ0zD3G51lKvs6fReaMRBKvZuaVSjvAvvgw/Eu2vRafK JH0VGwPzRD5OYsDMYzidnELynKSqZSg/U6pQtdkOqrQ5d3daWK84VPg8lsRZW2llqRKt Frl9XAahDtX5Tzi6N54ExZXc3ujyMooaLefHB9aiJ0+BP+wRbCzLv52MVMWbAG9GN6tU FZ/ETUlRxCG10stjZ1b8U39ZxMD6rKzMSYg9s9McRgH1q7xubK1GPK7OYHF8goqwFnhc /D2Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780752352; x=1781357152; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=CFIA4qrGwtjq3+f9Ip41dbdf/DDFhfGDaQaFDhRdMYg=; b=perV3Ow9sHJVm3X3f52t1JKcykDvje18UF3Wnoa/FBU8xQVB3oYNlfHjbm4n/GDREe WeMnEiIfO+0jezz0pBN0RitTg/bnA8P2B8DZNrtTteTkX+KkC+Th4NvDRquHz4HcK1Oy yM0tlSkJ91/Bc8GPiGsb1RI9yNdNCcsG8Qi/tTURIjBxJDGlEqyhok5j6Ul9KuMAFgp6 qtDAbfaVbFumPxV1KCCaaBYvwXebOXw0/j7i8m84pjksgrlxGkOdVPFpAMpGkz6a70AJ TJ1SJbVXbanKbMV465vzRX0DREHUYJRmz52jdvjMzI+z0MbUWwHa12FIzAHPAeFdYCgy 82+g== X-Forwarded-Encrypted: i=1; AFNElJ90VD1hprW0Bo1Z8Z89APJI087BkTZfsz0l/RWivuAp+F5VpF67qARolchS3B6SreZz5UlZmka9zCXOvLD0@lists.postgresql.org X-Gm-Message-State: AOJu0YzKDrbr2pXAGsdSpXslEer54l5S19EMAVv7DNCcz/FPu9ZD8ABz Ph/cqDPt9goaZYiyOpAWCexqQ15pdmpUNjgXS+/Lq4Rk0sdqRrUPW2Kv3fXsu3FGw39ogevyZSm Kuzn46ovK4nWJRhF0UhgBFcIL06Pqc1M= X-Gm-Gg: Acq92OGZGCTn1MbR/bfMS/VrrGDnzOJHTfbAARYwWYx4/Or+N7j5KvHBfEOxWIdXgGg syQTjlQWTnRvravTDbugnNjTsVZl0I46VFgp4AaA6XDAFA1JbsXwRdv9yvBTrDSbKiIc62mN7/5 3FTPC/1i9fyWG7suLDKjwE76AuMegF81LgtFjRZbnJsV2NKup13PoJ0GGDHE50XRe91Gxvr7Dj4 IKLr+KnQVKpmrVrEFysm5Pj3sGYYM9lDFlm83j2w2VrXvddPuubLDXjMR+RU44RNmXNRpZGWWvJ yac68y14+wFzoDeNCrbrdkqQGDmOE/7PEW9sygficbAD+gXOeCdcZeTirLWUXtuLvfNg1htDCxG EEBmUHfkxw/HsuU+d+sSWPK0u9ePtpJlHTHE1T/GtZ4LW6qZx36Yvzd8+qzBc X-Received: by 2002:a17:907:da3:b0:bed:afd6:9e07 with SMTP id a640c23a62f3a-bf370a64028mr382883366b.14.1780752352156; Sat, 06 Jun 2026 06:25:52 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Xuneng Zhou Date: Sat, 6 Jun 2026 21:25:39 +0800 X-Gm-Features: AVVi8CedqD1Vfjn4sip-YFnoxxLXRhXzjUdhrYSstqot91UnzX_Y9SjbuYJjGwg Message-ID: Subject: Re: Fix race in ReplicationSlotRelease for ephemeral slots To: "Zhijie Hou (Fujitsu)" Cc: Fujii Masao , Srinath Reddy Sadipiralla , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Sat, Jun 6, 2026 at 5:35=E2=80=AFPM Zhijie Hou (Fujitsu) wrote: > > On Friday, June 5, 2026 8:45 PM Xuneng Zhou wrote: > > On Wed, Jun 3, 2026 at 8:03=E2=80=AFPM Fujii Masao wrote: > > > > > > On Tue, Jun 2, 2026 at 3:00=E2=80=AFPM Xuneng Zhou > > wrote: > > > > > > /* Drop the local slot if it is not required to be retained. */ > > > if (!local_sync_slot_required(local_slot, remote_slot_list)) > > > { > > > + bool dropped =3D false; > > > + NameData slot_name =3D {0}; > > > + Oid slot_database =3D local_slot->data.database; > > > bool synced_slot; > > > > > > Is it really safe to read slot_database before acquiring the database= lock? > > > > Reading slot_database before taking the database lock seems not > > inherently unsafe by itself. The comment suggests that the lock is > > primarily used to prevent conflicts with the startup process running > > ReplicationSlotsDropDBSlots() during db-drop replay; it does not > > protect replication slot array reuse. > > > > The unsafe part could be reading slot_database from local_slot after > > ReplicationSlotControlLock has been released. At this point, the slot > > array cell may already have been freed and reused, so the value read > > may no longer belong to the slot that get_local_synced_slots() > > originally collected. As a result, we could end up locking the wrong > > database. > > > > There seems to be two related issues: > > > > 1) Before drop: reading local_slot->data.database / > > local_slot->data.name after the slot-array lock was released, before > > verifying the cell still represents the same synced slot. > > I recall condition (1) is considered acceptable, since the database lock = is > released immediately after re-verifying that the slot is no longer the or= iginal > 'synced' one anyway. Additionally, this race can only occur when replayin= g a > DROP DATABASE, which is rare in practice. Since we only take a shared loc= k, it > does not seem to cause real issues. > > > > > 2) After drop: calling ReplicationSlotDropAcquired(false) and then > > reading local_slot->data.database / local_slot->data.name for > > unlocking/logging after the cell may have been reused by another > > backend. > > Right. I missed this race condition during implementation and agree it's = a real > issue. An even bigger problem is that we could release a lock on the wron= g > database if the slot entry is reused after being dropped. I think we shou= ld fix > this by saving the database OID at the beginning, as your patch does. > > > > > The prior patch targets to fix 2), but leaves 1) unfixed. > > > > > BTW, I'm also wondering whether it's safe for > > > local_sync_slot_required() to access local_slot without holding a loc= k. > > > > I share the same concern here. The issue smells similar to the one > > discussed above -- reading values from the array cell directly without > > the protection of array lock. > > > > To solve them altogether, it might be > > better to stop carrying raw ReplicationSlot * values across > > unprotected windows. We can get the snapshot values such as slot name > > & database oid from get_local_synced_slots() instead. Then > > local_sync_slot_required() works from the snapshot, and > > drop_local_obsolete_slots() uses the copied database OID to take the > > database lock. Before dropping, it should revalidate by copied > > name/database that the slot is still a synced logical slot, then > > acquire/drop by copied name, and use only copied values for > > unlock/logging. I plan to prepare a refactoring patch for this. Does > > that seem like the right direction to you? > > Saving only the name and database OID would force us to search for the sl= ot > again in the loop, which was one reason we didn't implement it that way. The extra search may not be ideal, especially for the worker with a large number of slots to sync. But the cost could be avoided with an extra field like slotno. Were there other blocking issues discussed before? --=20 Regards, Xuneng Zhou HighGo Software Co., Ltd.