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 1whgm0-000MjR-2N for pgsql-hackers@arkaria.postgresql.org; Thu, 09 Jul 2026 04:54:09 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1whglz-00AtAh-0t for pgsql-hackers@arkaria.postgresql.org; Thu, 09 Jul 2026 04:54:08 +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 1whgly-00AtAA-2Q for pgsql-hackers@lists.postgresql.org; Thu, 09 Jul 2026 04:54:07 +0000 Received: from mail-ej1-x631.google.com ([2a00:1450:4864:20::631]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1whglx-00000000GPq-0Gi0 for pgsql-hackers@lists.postgresql.org; Thu, 09 Jul 2026 04:54:06 +0000 Received: by mail-ej1-x631.google.com with SMTP id a640c23a62f3a-c15bf399d3bso169177566b.2 for ; Wed, 08 Jul 2026 21:54:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1783572842; cv=none; d=google.com; s=arc-20260327; b=eZVMHh1IC+2hAi788WW6ebXeMsBgDpG7PH1vl0P5R8/08sea+wUbHsP4cUrNAP3n1p Huo/MmXmwnoX3nn+GzBB1fJnjMd/xy0H6O+ivb19tROJcL712331tQeNPqhD1gfpsAST O1t5/x3+jheMGwA2rGQr+lWaw225lna8T5jNz6XktFbmeV4Wjep6xlcUgY3YImC3C8bp siRKkSCkCYkX2ttM8C6rvSQK7ttxEB/WchhKN4YIvDSBLaH6gjXZusgHlq8D95PPRmkT 7N7CxVvk9884yR++oN1XxioRe1Xstcf/HAnqtCSBcqhp1/AeUM0kL64+/OG6iqbLDc5Y 4Bsg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=j3t7hwMqgCJWf/qYCaPqVjzlX9UybIkrOeFeYJdwLE4=; fh=kFKC0n174YQDqLY938lCApPub7x3andKsGoaXT80Ot8=; b=UYFErIvogSwadBJbWZYl7gWZtQWmW1d3tquvF0lzP6ccZ0d1+fxsN6FUgIR30UxZXM Sn3DOSBD2pdkKZI8W1p8FNRErQ6Y73bef/RGbHI01DGb+d3CYSNaKup0qBM5Rrn92isU Fkdmj66a0gM6dTyQgsoJzBTwrLLbrfwY6UvqmWtmCE4hx7gvtgNsdFpxJ1LyNd9jyfWu 7gGwNKK3/yu7g5fJTfOCdx2jHZLd/PDJWWxuuywDa4NwI7EMoO/Ds+o/vf4kQVst4kJJ tBvACMKjyItzxYgQK/6IZEidImzOpIJCcAST0hhjJHYX1NoHRKPjucNs0JxwJ8Isk20V Jknw==; 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=1783572842; x=1784177642; darn=lists.postgresql.org; h=content-transfer-encoding:content-type:cc:to:subject:message-id :date:from:in-reply-to:references:mime-version:from:to:cc:subject :date:message-id:reply-to:content-type; bh=j3t7hwMqgCJWf/qYCaPqVjzlX9UybIkrOeFeYJdwLE4=; b=aptkNX2L/20mBXdCHM/lY4xRltipCG5sa1EKMjmczFtw7XrDe0/gy7JQuPj2aqZkXk Vx+/p4wApIPjbWtDVkFX8AGqjinF/2bQHUHVdN91tfjfFGrEr2NY6CDXJmG3gNjDc6Vy bVRCSGNEbCsQKVpTm78Xkl1nvBzcGWhp02CNkAs+xwHj0bLHb8qn0rratXdnv6RE6GS0 1lFXtTjlSrDPl5C0wYwIo/U6a3Ml2xcO1+5RmcBBmeVE9eoMhqGuyZhHqgqL8awKC25r Eupgw9i6xfV10K1XC48T+j3G9usOxfM7hJC8i9NNc1Pip6i3WYKCIaQ7wgoUZjNMjrYk QGHw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1783572842; x=1784177642; h=content-transfer-encoding:content-type: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 :content-type; bh=j3t7hwMqgCJWf/qYCaPqVjzlX9UybIkrOeFeYJdwLE4=; b=Ex+T8BenmSSqciRXGEYRv14HnfuX5Xq9NqeTitLdgt2Iy8gSAIQMOL/UzE4k5SNMO+ AMbkXCPEFTYHMH27rnlu5EjqZsR3rKgOoANnjIE5y8ajuyCQ7WefvsSpq4ibMNE6NSd9 dxYQ7J7lF76LzCr5Oz0yJuzt04w+Xyw9hULAJa3hlwXhwl0y8SjQTOMjEZ22Fr3hk+IM RQcWXhXyyntnPSRHYRT2zVDc34s9ODxAXhiZSpgphhDwQQyOaZI7Ha/HLCcN1JdboCiM iAXf8FmuaMSzkfMHbtqjNpShiQcMauaAlzF1o4VSerGabpEFENTp8jUssej5hFscLJma 5xWQ== X-Forwarded-Encrypted: i=1; AHgh+RrDTrDSMAzytJj7FzYP9mT0uso4TqKIS7L/RIXaHzEY95IxYVP8Jcr76HsOkE5maNEsv6g0QLmJn4obfYTp@lists.postgresql.org X-Gm-Message-State: AOJu0YxP4nkFjQ998DxiA4T5FWefh4fpL51GFJci3SMjn1KxglYVkxrV zL02FaZ/PD90C1qSdj+VdOl4c54hGXXNpun96T+RCeqK0cjUJYF0cyj8PpQuecNEdc3fXIoq+14 IQx0dodhETblavrBItjrcoLGWRzTWTVw= X-Gm-Gg: AfdE7ckfBO8bo1aoqs8rZmSskwlq6O41F8eA9wrk/QLKSm3XB5hxYHDMsalvrghvkbP b8G3Twu/0bOP5G95ax9qnfvRrabTh3YDwsdweRHs4wWpTQFmDKmYGxwrt4f6qC2/iQOcFg+3zNw xHHTL9Dn5mAnpD3sjcxYU/TWyznBH7k3Fw/2yQOl7dH3B7kC921JfUhUBKEMw0hmsPAGkxDEoDv Iy6D+yUwSslAxbH84udHjxsX1ZUnZalCn/wnxnLCJcKkS0MSuryO9/COd7wWCEq42Dctw0Q1Gox GDIC0t22/mKlYt6xbou2bhSTbiRzBBN4gCIlW6hnhdqYBvrRYqkS+x6AxQbxt8bXq0iq+g2rrsn /+Qg67lnC4U0AIA9x+Ii2KIsPDBI= X-Received: by 2002:a17:907:787:b0:c12:e178:9e68 with SMTP id a640c23a62f3a-c15cdfe8dc7mr218259366b.19.1783572841891; Wed, 08 Jul 2026 21:54:01 -0700 (PDT) MIME-Version: 1.0 References: <1959506.1775527693@sss.pgh.pa.us> In-Reply-To: From: Xuneng Zhou Date: Thu, 9 Jul 2026 12:53:48 +0800 X-Gm-Features: AUfX_mwDnaTOhV4qTlHo2DqNQVMjbpGnJsLM2IJxz2WJ9zcGfabyAjIeatDJugQ Message-ID: Subject: Re: Implement waiting for wal lsn replay: reloaded To: Alexander Korotkov Cc: Heikki Linnakangas , Andres Freund , Tom Lane , Peter Eisentraut , Thomas Munro , =?UTF-8?Q?=C3=81lvaro_Herrera?= , Chao Li , pgsql-hackers , Michael Paquier , jian he , Tomas Vondra , Yura Sokolov 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 Thu, Jul 9, 2026 at 1:38=E2=80=AFAM Alexander Korotkov wrote: > > On Wed, Jul 8, 2026 at 3:08=E2=80=AFPM Xuneng Zhou = wrote: > > On Mon, Jul 6, 2026 at 10:17=E2=80=AFPM Xuneng Zhou wrote: > > > > > > On Mon, Jul 6, 2026 at 9:49=E2=80=AFPM Xuneng Zhou wrote: > > > > > > > > Hi Heikki, > > > > > > > > Thanks for looking into this! > > > > > > > > On Mon, Jul 6, 2026 at 7:04=E2=80=AFPM Heikki Linnakangas wrote: > > > > /* > > > > > > * Apply the record > > > > > > */ > > > > > > ApplyWalRecord(xlogreader, record, &repla= yTLI); > > > > > > > > > > > > /* > > > > > > * Wake up processes waiting for standby = replay, write, or flush > > > > > > * LSN to reach current replay position. = Replay implies that the > > > > > > * WAL was already written and flushed to= disk, so write and flush > > > > > > * waiters can be woken at the replay pos= ition too. > > > > > > */ > > > > > > WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_REPLA= Y, > > > > > > XLogRecoveryCtl= ->lastReplayedEndRecPtr); > > > > > > WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_WRITE= , > > > > > > XLogRecoveryCtl= ->lastReplayedEndRecPtr); > > > > > > WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_FLUSH= , > > > > > > XLogRecoveryCtl= ->lastReplayedEndRecPtr); > > > > > > > > > > That's not wrong, but I've got some comments: > > > > > > > > > > 1. It's reading XLogRecoveryCtl->lastReplayedEndRecPtr without a = lock or > > > > > atomics. That's ok, no other process modifies lastReplayedEndRecP= tr, but > > > > > it feels a little dirty. > > > > > > > > > > 2. We're now doing three extra function calls on every WAL record= . This > > > > > is a very hot path, and most of the time, we'll just take the fas= t path > > > > > in WaitLSNWakeup to return without doing anything. Andres and oth= ers > > > > > assumed up-thread that it's negligible (we used to have pre-check= s here > > > > > in the caller), but I wonder if you did any performance testing? > > > > > > > > Agreed, this is a hot path. The performance impact of these extra > > > > calls doing real work hasn't been measured yet. I'll do some testin= g. > > > > > > > > > 3. There are other "wakeup" calls inside ApplyWalRecord(), to wak= e up > > > > > walsenders and walreceivers. They could perhaps use the same wait= -lsn > > > > > machinery now, but that's v20 material. However, I think these > > > > > WaitLSNWakeup() calls should also be moved inside ApplyWalRecord(= ), so > > > > > that we'd have all the wakeup actions in one place. > > > > > > > > + 1. This makes the code safer and more readable. > > > > > > > > > 4. Once you move those calls inside ApplyWalRecord(), like this: > > > > > > > > > > > @@ -1979,20 +1979,30 @@ ApplyWalRecord(XLogReaderState *xlogrea= der, XLogRecord *record, TimeLineID *repl > > > > > > /* > > > > > > * Update lastReplayedEndRecPtr after this record has b= een successfully > > > > > > * replayed. > > > > > > */ > > > > > > SpinLockAcquire(&XLogRecoveryCtl->info_lck); > > > > > > XLogRecoveryCtl->lastReplayedReadRecPtr =3D xlogreader-= >ReadRecPtr; > > > > > > XLogRecoveryCtl->lastReplayedEndRecPtr =3D xlogreader->= EndRecPtr; > > > > > > XLogRecoveryCtl->lastReplayedTLI =3D *replayTLI; > > > > > > SpinLockRelease(&XLogRecoveryCtl->info_lck); > > > > > > > > > > > > + /* > > > > > > + * Wake up processes waiting for standby replay, write,= or flush LSN to > > > > > > + * reach current replay position. Replay implies that = the WAL was already > > > > > > + * written and flushed to disk, so write and flush wait= ers can be woken at > > > > > > + * the replay position too. > > > > > > + */ > > > > > > + WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_REPLAY, xlogreader-= >EndRecPtr); > > > > > > + WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_WRITE, xlogreader->= EndRecPtr); > > > > > > + WaitLSNWakeup(WAIT_LSN_TYPE_STANDBY_FLUSH, xlogreader->= EndRecPtr); > > > > > > + > > > > > > /* ------ > > > > > > * Wakeup walsenders: > > > > > > * > > > > > > * On the standby, the WAL is flushed first (which will= only wake up > > > > > > * physical walsenders) and then applied, which will on= ly wake up logical > > > > > > * walsenders. > > > > > > > > > > It becomes clear that you don't actually need the memory barrier = inside > > > > > WaitLSNWakeup(). Not sure if they're needed for other callers, bu= t here > > > > > we have just released a spinlock, which acts as a memory barrier.= It > > > > > might not be worth relaxing, but it does seem a little silly. > > > > > > > > If we made the move here, I think the memory barrier could be relax= ed > > > > since other callers are guarded by either the spinlock or full-barr= ier > > > > atomic write already. We might also want to make the contract of > > > > > > OK, the 'if' here is redundant... > > > > After revisiting the memory barrier in WaitLSNWakeup and why it is > > introduced there in a80a593ab63 rather than recalling it from memory, > > I think relaxing it here could be unsafe. > > > > In WaitLSNWakeup(), use pg_atomic_read_membarrier_u64() in the > > fast-path check so the waker's preceding position store is globally > > visible before minWaitedLSN is read. > > > > Without the barrier in WaitLSNWakeup(), this interleaving is possible: > > > > Initial: > > minWaitedLSN =3D PG_UINT64_MAX > > replayLSN =3D 90 > > > > Waiter: > > stores minWaitedLSN =3D 100 > > reads replayLSN before the waker publishes the new replay position > > sees replayLSN =3D 90 > > decides it should sleep > > > > Waker: > > publishes replayLSN =3D 100 > > reads old minWaitedLSN =3D PG_UINT64_MAX > > skips the wakeup > > > > Then the waiter goes to sleep even though replay has reached its > > target LSN. To avoid this, we still need to make sure that the > > publication of replayLSN precedes the read of minWaitedLSN, so that > > the waker cannot decide "nobody is waiting" before its own progress is > > still not visible to the waiter. > > Yes, I also think the memory barrier for waker between publishing > replayLSN and reading minWaitedLSN is required. However, sequence of > three WaitLSNWakeup() calls makes 3 memory barriers while only one is > required. We could introduce a hierarchy for WAIT_LSN_TYPE_STANDBY_*: > WAIT_LSN_TYPE_STANDBY_FLUSH implies WAIT_LSN_TYPE_STANDBY_WRITE, > WAIT_LSN_TYPE_STANDBY_REPLAY implies WAIT_LSN_TYPE_STANDBY_WRITE and > WAIT_LSN_TYPE_STANDBY_FLUSH. Then ApplyWalRecord() can call > WaitLSNWakeup() only once and make only 1 memory barrier. This optimization seems desirable to me and the hierarchy idea is clever! I pondered it for a while, it may not be necessary for WAIT_LSN_TYPE_STANDBY_FLUSH, do we need to add an additional wake-up call for write waiters at flush lsn publication? Another less clever idea is to add a special helper for relay wake-up, we can still use a single memory barrier followed by three plan reads. However, this seems less unified and needs extra clarification and safe checking. I am curious about your thoughts on this. Maybe I just don't get the idea right. --=20 Regards, Xuneng Zhou HighGo Software Co., Ltd.