On 2021/02/16 6:28, Andres Freund wrote:
Hi,

On 2021-02-15 19:45:21 +0900, Michael Paquier wrote:
On Mon, Feb 15, 2021 at 10:47:05PM +1300, Thomas Munro wrote:
Why not initialise it in WalRcvShmemInit()?

I was thinking about doing that as well, but we have no real need to
initialize this stuff in most cases, say standalone deployments.  In
particular for the fallback implementation of atomics, we would
prepare a spinlock for nothing.

So what? It's just about free to initialize a spinlock, whether it's
using the fallback implementation or not. Initializing upon walsender
startup adds a lot of complications, because e.g. somebody could already
hold the spinlock because the previous walsender just disconnected, and
they were looking at the stats.

Even if we initialize "writtenUpto" in WalRcvShmemInit(), WalReceiverMain()
still needs to initialize (reset to 0) by using pg_atomic_write_u64().

Basically we should not acquire new spinlock while holding another spinlock,
to shorten the spinlock duration. Right? If yes, we need to move
pg_atomic_read_u64() of "writtenUpto" after the release of spinlock in
pg_stat_get_wal_receiver.

Attached is the updated version of the patch.

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION
diff --git a/src/backend/replication/walreceiver.c 
b/src/backend/replication/walreceiver.c
index 723f513d8b..316640c275 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -249,7 +249,7 @@ WalReceiverMain(void)
 
        SpinLockRelease(&walrcv->mutex);
 
-       pg_atomic_init_u64(&WalRcv->writtenUpto, 0);
+       pg_atomic_write_u64(&WalRcv->writtenUpto, 0);
 
        /* Arrange to clean up at walreceiver exit */
        on_shmem_exit(WalRcvDie, 0);
@@ -1325,7 +1325,6 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
        state = WalRcv->walRcvState;
        receive_start_lsn = WalRcv->receiveStart;
        receive_start_tli = WalRcv->receiveStartTLI;
-       written_lsn = pg_atomic_read_u64(&WalRcv->writtenUpto);
        flushed_lsn = WalRcv->flushedUpto;
        received_tli = WalRcv->receivedTLI;
        last_send_time = WalRcv->lastMsgSendTime;
@@ -1338,6 +1337,14 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
        strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
        SpinLockRelease(&WalRcv->mutex);
 
+       /*
+        * Read "writtenUpto" without holding a spinlock. So it may not be
+        * consistent with other WAL receiver's shared variables protected by a
+        * spinlock. This is OK because that variable is used only for
+        * informational purpose and should not be used for data integrity 
checks.
+        */
+       written_lsn = pg_atomic_read_u64(&WalRcv->writtenUpto);
+
        /*
         * No WAL receiver (or not ready yet), just return a tuple with NULL
         * values
diff --git a/src/backend/replication/walreceiverfuncs.c 
b/src/backend/replication/walreceiverfuncs.c
index 69b91a7dab..63e60478ea 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -63,6 +63,7 @@ WalRcvShmemInit(void)
                MemSet(WalRcv, 0, WalRcvShmemSize());
                WalRcv->walRcvState = WALRCV_STOPPED;
                SpinLockInit(&WalRcv->mutex);
+               pg_atomic_init_u64(&WalRcv->writtenUpto, 0);
                WalRcv->latch = NULL;
        }
 }
diff --git a/src/test/regress/expected/sysviews.out 
b/src/test/regress/expected/sysviews.out
index 81bdacf59d..6d048e309c 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -83,6 +83,13 @@ select count(*) = 1 as ok from pg_stat_wal;
  t
 (1 row)
 
+-- We expect no walreceiver running in this test
+select count(*) = 0 as ok from pg_stat_wal_receiver;
+ ok 
+----
+ t
+(1 row)
+
 -- This is to record the prevailing planner enable_foo settings during
 -- a regression test run.
 select name, setting from pg_settings where name like 'enable%';
diff --git a/src/test/regress/sql/sysviews.sql 
b/src/test/regress/sql/sysviews.sql
index b9b875bc6a..dc8c9a3ac2 100644
--- a/src/test/regress/sql/sysviews.sql
+++ b/src/test/regress/sql/sysviews.sql
@@ -40,6 +40,9 @@ select count(*) >= 0 as ok from pg_prepared_xacts;
 -- There must be only one record
 select count(*) = 1 as ok from pg_stat_wal;
 
+-- We expect no walreceiver running in this test
+select count(*) = 0 as ok from pg_stat_wal_receiver;
+
 -- This is to record the prevailing planner enable_foo settings during
 -- a regression test run.
 select name, setting from pg_settings where name like 'enable%';

Reply via email to