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.94.2) (envelope-from ) id 1u1g1E-006Gfx-R0 for pgsql-hackers@arkaria.postgresql.org; Mon, 07 Apr 2025 06:31:41 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1u1g1D-00BXkN-9c for pgsql-hackers@arkaria.postgresql.org; Mon, 07 Apr 2025 06:31:39 +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.94.2) (envelope-from ) id 1u1g1C-00BXf8-9P for pgsql-hackers@lists.postgresql.org; Mon, 07 Apr 2025 06:31:39 +0000 Received: from fout-a5-smtp.messagingengine.com ([103.168.172.148]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1u1g19-003Q0R-2z for pgsql-hackers@lists.postgresql.org; Mon, 07 Apr 2025 06:31:37 +0000 Received: from phl-compute-08.internal (phl-compute-08.phl.internal [10.202.2.48]) by mailfout.phl.internal (Postfix) with ESMTP id 76C2C13801A0; Mon, 7 Apr 2025 02:31:34 -0400 (EDT) Received: from phl-mailfrontend-01 ([10.202.2.162]) by phl-compute-08.internal (MEProxy); Mon, 07 Apr 2025 02:31:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=paquier.xyz; h= cc:cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm2; t=1744007494; x=1744093894; bh=7ST+oszwMh 99uV6Qc7kZ1mF8Um85/zkNsBg48JlcoJs=; b=g1GVJUOvU7m7nJ36UwBFcQ18eq 4VsdNQCWbaeAwuK/uaJlw2veMIh6LXsNFHj91oD/ebUy/vmjcxIYyx2cKheqKQgw f1FB7SQ1TZN2nzVrWfvPsnmPfnR+OLMnRi2DF9jtkxZOYu2wEY601LMPLibowjtY M4Vpr/2063kOQRwywb9aqQpV0UmbnLZQNA7Jjdp6yP/V6j5IISWWT2D0d9t6FDoF 8qaKM+nQTRdUJI0hGVpc/n/SihYHwNsHEk9UZAR0RufuTT7nD2Y/tGmMCj1Hk2K/ +fAQb9qPkBfD7ZD+ynNB84y6W6STvadljMFcj5aQgLoFJZimKVDImr5iumqg== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; t= 1744007494; x=1744093894; bh=7ST+oszwMh99uV6Qc7kZ1mF8Um85/zkNsBg 48JlcoJs=; b=Sf5fVnVoKP+i8G1iAq1NjRAQ1Nr9JvP5LStD5Lod427Y+ZZZVJn K69235RiaHPkcAfvGVfgDzOmIhtocdsqzNfsZNiTu/2TnHggF/UHLzqPNjJtWZRq OWAn2s1bmcDykjmWi3khiRyxy9KdWixRk6kmAIiAV9VPQpa0nDB94+BPz3rxoxQ1 /EMSUkuhjZxgV/3lZ9+6+xQcHiwbcn19PShBkO2hLOWJybi3tNvIloQHJXMOowOv VXBjSdZuFrY7ajGJiUvpE5f37TX/q+kjtGjDpLT5eCODmyGbvn3P4OYHKtaRoVN5 RJRYvSPTQYpjyvb8ReJC90TXDd9g+/azetA== X-ME-Sender: X-ME-Received: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdduleelgeejucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucesvcftvggtihhpih gvnhhtshculddquddttddmnegfrhhlucfvnfffucdljedtmdenucfjughrpeffhffvvefu kfhfgggtuggjsehgtderredttddvnecuhfhrohhmpefoihgthhgrvghlucfrrghquhhivg hruceomhhitghhrggvlhesphgrqhhuihgvrhdrgiihiieqnecuggftrfgrthhtvghrnhep teelieefudffhffhtdetleeggeegfffhkeeuveetiefgudduvedutefggeeivdejnecuve hluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehmrghilhhfrhhomhepmhhitghhrggv lhesphgrqhhuihgvrhdrgiihiidpnhgspghrtghpthhtohephedpmhhouggvpehsmhhtph houhhtpdhrtghpthhtohepvhhighhnvghshhdvudesghhmrghilhdrtghomhdprhgtphht thhopegsvghrthhrrghnuggurhhouhhvohhtrdhpghesghhmrghilhdrtghomhdprhgtph htthhopeiguhhnvghnghiihhhouhesghhmrghilhdrtghomhdprhgtphhtthhopegrnhgu rhgvshesrghnrghrrgiivghlrdguvgdprhgtphhtthhopehpghhsqhhlqdhhrggtkhgvrh hssehlihhsthhsrdhpohhsthhgrhgvshhqlhdrohhrgh X-ME-Proxy: Feedback-ID: i0fe9450f:Fastmail Received: by mail.messagingengine.com (Postfix) with ESMTPA; Mon, 7 Apr 2025 02:31:32 -0400 (EDT) Date: Mon, 7 Apr 2025 15:31:14 +0900 From: Michael Paquier To: vignesh C Cc: Bertrand Drouvot , Xuneng Zhou , Andres Freund , pgsql-hackers@lists.postgresql.org Subject: Re: Fwd: [BUG]: the walsender does not update its IO statistics until it exits Message-ID: References: MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha512; protocol="application/pgp-signature"; boundary="+im5kJHLKwcg3mtO" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --+im5kJHLKwcg3mtO Content-Type: multipart/mixed; boundary="VOFUfs2sNY/KKOcm" Content-Disposition: inline --VOFUfs2sNY/KKOcm Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Apr 04, 2025 at 09:33:46PM +0530, vignesh C wrote: > The new test added currently passes even without the patch. It would > be ideal to have a test that fails without the patch and passes once > the patch is applied. Right. The subscription test and logical WAL senders passes without the patch, because we are able to catch some WAL activity through pgoutput. The recovery test for physical WAL sender fails without the patch on timeout. We could need something more advanced here for the logical case, where we could use pg_recvlogical started in the background with a hardcoded endpos, or just kill the pg_recvlogical command once we have checked the state of the stats. I am not sure if this is worth the cycles spent on, TBH, so I would be happy with just the physical case checked in TAP as it's simpler because streaming replication makes that easy to work with. One thing that I'm a bit unhappy about in the patch is the choice to do the stats updates in WalSndLoop() for the logical WAL sender case, because this forces an extra GetCurrentTimestamp() call for each loop, and that's never a cheap system call in what can be a hot code path. How about doing the calculations in WalSndWaitForWal() for the logical part, relying on the existing GetCurrentTimestamp() done there? That's also where the waits are handled for the logical part, so there may be a good point in keeping this code more symmetric for now, rather than split it. Saying that, here is a version 7 with all that included, which is simpler to read. -- Michael --VOFUfs2sNY/KKOcm Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="v7-0001-Flush-the-IO-statistics-of-active-walsenders.patch" Content-Transfer-Encoding: quoted-printable =46rom 9f6dadc679cdc0da7c005d005a06dad6e81020ad Mon Sep 17 00:00:00 2001 =46rom: Bertrand Drouvot Date: Tue, 25 Feb 2025 10:18:05 +0000 Subject: [PATCH v7] Flush the IO statistics of active walsenders The walsender does not flush its IO statistics until it exits. The issue is there since pg_stat_io has been introduced in a9c70b46dbe. This commits: 1. ensures it does not wait to exit to flush its IO statistics 2. flush its IO statistics periodically to not overload the walsender 3. adds a test for a physical walsender and a test for a logical walsender --- src/backend/replication/walsender.c | 36 +++++++++++++++++++++++++-- src/test/recovery/t/001_stream_rep.pl | 15 +++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/backend/replication/walsender.c b/src/backend/replication/= walsender.c index 1028919aecb1..216baeda5cd2 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -91,10 +91,14 @@ #include "utils/guc.h" #include "utils/memutils.h" #include "utils/pg_lsn.h" +#include "utils/pgstat_internal.h" #include "utils/ps_status.h" #include "utils/timeout.h" #include "utils/timestamp.h" =20 +/* Minimum interval used by walsender for stats flushes, in ms */ +#define WALSENDER_STATS_FLUSH_INTERVAL 1000 + /* * Maximum data payload in a WAL data message. Must be >=3D XLOG_BLCKSZ. * @@ -1797,6 +1801,7 @@ WalSndWaitForWal(XLogRecPtr loc) int wakeEvents; uint32 wait_event =3D 0; static XLogRecPtr RecentFlushPtr =3D InvalidXLogRecPtr; + TimestampTz last_flush =3D 0; =20 /* * Fast path to avoid acquiring the spinlock in case we already know we @@ -1817,6 +1822,7 @@ WalSndWaitForWal(XLogRecPtr loc) { bool wait_for_standby_at_stop =3D false; long sleeptime; + TimestampTz now; =20 /* Clear any already-pending wakeups */ ResetLatch(MyLatch); @@ -1927,7 +1933,8 @@ WalSndWaitForWal(XLogRecPtr loc) * new WAL to be generated. (But if we have nothing to send, we don't * want to wake on socket-writable.) */ - sleeptime =3D WalSndComputeSleeptime(GetCurrentTimestamp()); + now =3D GetCurrentTimestamp(); + sleeptime =3D WalSndComputeSleeptime(now); =20 wakeEvents =3D WL_SOCKET_READABLE; =20 @@ -1936,6 +1943,15 @@ WalSndWaitForWal(XLogRecPtr loc) =20 Assert(wait_event !=3D 0); =20 + /* Report IO statistics, if needed */ + if (TimestampDifferenceExceeds(last_flush, now, + WALSENDER_STATS_FLUSH_INTERVAL)) + { + pgstat_flush_io(false); + (void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO); + last_flush =3D now; + } + WalSndWait(wakeEvents, sleeptime, wait_event); } =20 @@ -2742,6 +2758,8 @@ WalSndCheckTimeOut(void) static void WalSndLoop(WalSndSendDataCallback send_data) { + TimestampTz last_flush =3D 0; + /* * Initialize the last reply timestamp. That enables timeout processing * from hereon. @@ -2836,6 +2854,9 @@ WalSndLoop(WalSndSendDataCallback send_data) * WalSndWaitForWal() handle any other blocking; idle receivers need * its additional actions. For physical replication, also block if * caught up; its send_data does not block. + * + * The IO statistics are reported in WalSndWaitForWal() for the + * logical WAL senders. */ if ((WalSndCaughtUp && send_data !=3D XLogSendLogical && !streamingDoneSending) || @@ -2843,6 +2864,7 @@ WalSndLoop(WalSndSendDataCallback send_data) { long sleeptime; int wakeEvents; + TimestampTz now; =20 if (!streamingDoneReceiving) wakeEvents =3D WL_SOCKET_READABLE; @@ -2853,11 +2875,21 @@ WalSndLoop(WalSndSendDataCallback send_data) * Use fresh timestamp, not last_processing, to reduce the chance * of reaching wal_sender_timeout before sending a keepalive. */ - sleeptime =3D WalSndComputeSleeptime(GetCurrentTimestamp()); + now =3D GetCurrentTimestamp(); + sleeptime =3D WalSndComputeSleeptime(now); =20 if (pq_is_send_pending()) wakeEvents |=3D WL_SOCKET_WRITEABLE; =20 + /* Report IO statistics, if needed */ + if (TimestampDifferenceExceeds(last_flush, now, + WALSENDER_STATS_FLUSH_INTERVAL)) + { + pgstat_flush_io(false); + (void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO); + last_flush =3D now; + } + /* Sleep until something happens or we time out */ WalSndWait(wakeEvents, sleeptime, WAIT_EVENT_WAL_SENDER_MAIN); } diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/00= 1_stream_rep.pl index ccd8417d449f..e55d8ec0ec17 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -42,6 +42,9 @@ $node_standby_2->init_from_backup($node_standby_1, $backu= p_name, has_streaming =3D> 1); $node_standby_2->start; =20 +# Reset IO statistics, for the WAL sender check with pg_stat_io. +$node_primary->safe_psql('postgres', "SELECT pg_stat_reset_shared('io')"); + # Create some content on primary and check its presence in standby nodes $node_primary->safe_psql('postgres', "CREATE TABLE tab_int AS SELECT generate_series(1,1002) AS a"); @@ -333,6 +336,18 @@ $node_primary->psql( =20 note "switching to physical replication slot"; =20 +# Wait for the walsender to update its IO statistics. This is done before +# the next restart and far enough from the reset done above. +$node_primary->poll_query_until( + 'postgres', + qq[SELECT sum(reads) > 0 + FROM pg_catalog.pg_stat_io + WHERE backend_type =3D 'walsender' + AND object =3D 'wal'] + ) + or die + "Timed out while waiting for the walsender to update its IO statistics"; + # Switch to using a physical replication slot. We can do this without a new # backup since physical slots can go backwards if needed. Do so on both # standbys. Since we're going to be testing things that affect the slot st= ate, --=20 2.49.0 --VOFUfs2sNY/KKOcm-- --+im5kJHLKwcg3mtO Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEG72nH6vTowiyblFKnvQgOdbyQH0FAmfzcTIACgkQnvQgOdby QH1CkA//SasQ1vwcUhtYQohbaJ3m5NwfSu4AlllE7yTt52I6tWs6+NN6PlxevGyy ZV3SM4U/vQXZDoNARwWgnIxaTxuvbm13hJIlWSo9lCLMGpr/+ipzlVky8Ps9awJ7 m50ddL70+3AsfkEsYsfprqsn0DBUpraKI38FjKlNdRDErr10VvGs73ena4vspFEy yQiJXbBweJ6DrREtvTecgKL7+b5cYv85/iqvwcjCGC4civF6QyNo3ILwUJmjNQTW A465dMT4aR6KyGIGVPPHBu4S1up4+xTs/fiESkjHaFAl20fuRboFS/iUnsufn2Ok Z3kj2w3Qb7Q6RnTlv0ajdTBUogIeID9GPIe3ZXCvBEtBGMn26GYVO8wwzEozOYnn 8fZQNUMpbl1Mpw1q1H2AzcS+9YWe9FLOsY2E8sBSJSbsJgQGix19Sx49RVpdcx+8 tTZQ1WVri8V6WqaiiMbXvu6HoGZ9aE01gwOdiWW34Mhy0pFh1ccvMJXffWmrR/D0 KI+VKeNrrK5HFTjjncjVAWNCqjuRlWjrxxFX3hCz6z27MQ9tp/ipDPPr0EIPB7ia ECtwBgJ6ru0UMN74B2RlJmDrOelLNMV08IJWnILGwVMfvb04bx3RfYM3u3tIc6ts iZ0P0lg/uZ828tGU4KzsKR7Ol815usPSIeG7uRdYn+uO0pfD2NU= =uKo2 -----END PGP SIGNATURE----- --+im5kJHLKwcg3mtO--