Hi Hou-san. Here are some review comments for your patch v1-0001.

======
doc/src/sgml/logical-replication.sgml

nit - added a comma.

======
doc/src/sgml/monitoring.sgml

nit - use <literal> for 'apply_error_count'.
nit - added a period when there are multiple sentences.
nit - adjusted field descriptions using Chat-GPT clarification suggestions

======
src/include/pgstat.h

nit - change the param to 'type' -- ie. same as the implementation calls it

======
src/include/replication/conflict.h

nit - defined 'NUM_CONFLICT_TYPES' inside the enum (I think this way
is often used in other PG source enums)

======
src/test/subscription/t/026_stats.pl

1.
+ # Delete data from the test table on the publisher. This delete operation
+ # should be skipped on the subscriber since the table is already empty.
+ $node_publisher->safe_psql($db, qq(DELETE FROM $table_name;));
+
+ # Wait for the subscriber to report tuple missing conflict.
+ $node_subscriber->poll_query_until(
+ $db,
+ qq[
+ SELECT update_missing_count > 0 AND delete_missing_count > 0
+ FROM pg_stat_subscription_stats
+ WHERE subname = '$sub_name'
+ ])
+   or die
+   qq(Timed out while waiting for tuple missing conflict for
subscription '$sub_name');

Can you write a comment to explain why the replicated DELETE is
expected to increment both the 'update_missing_count' and the
'delete_missing_count'?

~
nit - update several "Apply and Sync errors..." comments that did not
mention conflicts
nit - tweak comments wording for update_differ and delete_differ
nit - /both > 0/> 0/
nit - /both 0/0/

======
Kind Regards,
Peter Smith.
Fujitsu Australia
diff --git a/doc/src/sgml/logical-replication.sgml 
b/doc/src/sgml/logical-replication.sgml
index f3e3641..f682369 100644
--- a/doc/src/sgml/logical-replication.sgml
+++ b/doc/src/sgml/logical-replication.sgml
@@ -1585,7 +1585,7 @@ test_sub=# SELECT * FROM t1 ORDER BY id;
   </para>
 
   <para>
-   Additional logging is triggered and the conflict statistics are collected 
(displayed in the
+   Additional logging is triggered, and the conflict statistics are collected 
(displayed in the
    <link 
linkend="monitoring-pg-stat-subscription-stats"><structname>pg_stat_subscription_stats</structname></link>
 view)
    in the following <firstterm>conflict</firstterm> cases:
    <variablelist>
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index ea36d46..ac3c773 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2159,7 +2159,7 @@ description | Waiting for a newly initialized WAL file to 
reach durable storage
       <para>
        Number of times an error occurred while applying changes. Note that any
        conflict resulting in an apply error will be counted in both
-       apply_error_count and the corresponding conflict count.
+       <literal>apply_error_count</literal> and the corresponding conflict 
count.
       </para></entry>
      </row>
 
@@ -2179,8 +2179,8 @@ description | Waiting for a newly initialized WAL file to 
reach durable storage
       </para>
       <para>
        Number of times a row insertion violated a
-       <literal>NOT DEFERRABLE</literal> unique constraint while applying
-       changes
+       <literal>NOT DEFERRABLE</literal> unique constraint during the
+       application of changes
       </para></entry>
      </row>
 
@@ -2189,11 +2189,11 @@ description | Waiting for a newly initialized WAL file 
to reach durable storage
        <structfield>update_differ_count</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times an update was performed on a row that was previously
-       modified by another source while applying changes. This conflict is
+       Number of times an update was applied to a row that had been previously
+       modified by another source during the application of changes. This 
conflict is
        counted only when the
        <link 
linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
-       option is enabled on the subscriber
+       option is enabled on the subscriber.
       </para></entry>
      </row>
 
@@ -2202,9 +2202,9 @@ description | Waiting for a newly initialized WAL file to 
reach durable storage
        <structfield>update_exists_count</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times that the updated value of a row violated a
-       <literal>NOT DEFERRABLE</literal> unique constraint while applying
-       changes
+       Number of times that an updated row value violated a
+       <literal>NOT DEFERRABLE</literal> unique constraint during the
+       application of changes
       </para></entry>
      </row>
 
@@ -2213,8 +2213,8 @@ description | Waiting for a newly initialized WAL file to 
reach durable storage
        <structfield>update_missing_count</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times that the tuple to be updated was not found while 
applying
-       changes
+       Number of times the tuple to be updated was not found during the
+       application of changes
       </para></entry>
      </row>
 
@@ -2223,11 +2223,11 @@ description | Waiting for a newly initialized WAL file 
to reach durable storage
        <structfield>delete_differ_count</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times a delete was performed on a row that was previously
-       modified by another source while applying changes. This conflict is
-       counted only when the
+       Number of times a delete operation was applied to row that had been
+       previously modified by another source during the application of changes.
+       This conflict is counted only when the
        <link 
linkend="guc-track-commit-timestamp"><varname>track_commit_timestamp</varname></link>
-       option is enabled on the subscriber
+       option is enabled on the subscriber.
       </para></entry>
      </row>
 
@@ -2236,8 +2236,8 @@ description | Waiting for a newly initialized WAL file to 
reach durable storage
        <structfield>delete_missing_count</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times that the tuple to be deleted was not found while 
applying
-       changes
+       Number of times the tuple to be deleted was not found during the 
application
+       of changes
       </para></entry>
      </row>
 
diff --git a/src/backend/utils/activity/pgstat_subscription.c 
b/src/backend/utils/activity/pgstat_subscription.c
index e06c927..ebb0135 100644
--- a/src/backend/utils/activity/pgstat_subscription.c
+++ b/src/backend/utils/activity/pgstat_subscription.c
@@ -116,7 +116,7 @@ pgstat_subscription_flush_cb(PgStat_EntryRef *entry_ref, 
bool nowait)
 #define SUB_ACC(fld) shsubent->stats.fld += localent->fld
        SUB_ACC(apply_error_count);
        SUB_ACC(sync_error_count);
-       for (int i = 0; i < CONFLICT_NUM_TYPES; i++)
+       for (int i = 0; i < NUM_CONFLICT_TYPES; i++)
                SUB_ACC(conflict_count[i]);
 #undef SUB_ACC
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c 
b/src/backend/utils/adt/pgstatfuncs.c
index 870aee8..7dd4b1e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -2019,7 +2019,7 @@ pg_stat_get_subscription_stats(PG_FUNCTION_ARGS)
        values[i++] = Int64GetDatum(subentry->sync_error_count);
 
        /* conflict count */
-       for (int nconflict = 0; nconflict < CONFLICT_NUM_TYPES; nconflict++)
+       for (int nconflict = 0; nconflict < NUM_CONFLICT_TYPES; nconflict++)
                values[i++] = 
Int64GetDatum(subentry->conflict_count[nconflict]);
 
        /* stats_reset */
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index adb91f5..91b54aa 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -166,7 +166,7 @@ typedef struct PgStat_BackendSubEntry
 {
        PgStat_Counter apply_error_count;
        PgStat_Counter sync_error_count;
-       PgStat_Counter conflict_count[CONFLICT_NUM_TYPES];
+       PgStat_Counter conflict_count[NUM_CONFLICT_TYPES];
 } PgStat_BackendSubEntry;
 
 /* ----------
@@ -425,7 +425,7 @@ typedef struct PgStat_StatSubEntry
 {
        PgStat_Counter apply_error_count;
        PgStat_Counter sync_error_count;
-       PgStat_Counter conflict_count[CONFLICT_NUM_TYPES];
+       PgStat_Counter conflict_count[NUM_CONFLICT_TYPES];
        TimestampTz stat_reset_timestamp;
 } PgStat_StatSubEntry;
 
@@ -728,7 +728,7 @@ extern PgStat_SLRUStats *pgstat_fetch_slru(void);
  */
 
 extern void pgstat_report_subscription_error(Oid subid, bool is_apply_error);
-extern void pgstat_report_subscription_conflict(Oid subid, ConflictType 
conflict);
+extern void pgstat_report_subscription_conflict(Oid subid, ConflictType type);
 extern void pgstat_create_subscription(Oid subid);
 extern void pgstat_drop_subscription(Oid subid);
 extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid);
diff --git a/src/include/replication/conflict.h 
b/src/include/replication/conflict.h
index 7232c88..37c9100 100644
--- a/src/include/replication/conflict.h
+++ b/src/include/replication/conflict.h
@@ -45,9 +45,9 @@ typedef enum
         * complex rules than simple equality checks. These conflicts are left 
for
         * future improvements.
         */
-} ConflictType;
 
-#define CONFLICT_NUM_TYPES (CT_DELETE_MISSING + 1)
+       NUM_CONFLICT_TYPES      /* must be last */
+} ConflictType;
 
 extern bool GetTupleTransactionInfo(TupleTableSlot *localslot,
                                                                        
TransactionId *xmin,
diff --git a/src/test/subscription/t/026_stats.pl 
b/src/test/subscription/t/026_stats.pl
index 4773528..e22b0b1 100644
--- a/src/test/subscription/t/026_stats.pl
+++ b/src/test/subscription/t/026_stats.pl
@@ -162,7 +162,7 @@ sub create_sub_pub_w_errors
        ));
 
        # Update the data in the test table on the publisher. This should 
generate
-       # a conflict because it attempts to update a row on the subscriber that 
has
+       # a conflict because it causes subscriber to attempt to update a row 
that has
        # been modified by a different origin.
        $node_publisher->safe_psql($db, qq(UPDATE $table_name SET a = 2;));
 
@@ -184,7 +184,7 @@ sub create_sub_pub_w_errors
        ));
 
        # Delete data from the test table on the publisher. This should 
generate a
-       # conflict because it attempts to delete a row on the subscriber that 
has
+       # conflict because it causes subscriber to attempt to delete a row that 
has
        # been modified by a different origin.
        $node_publisher->safe_psql($db, qq(DELETE FROM $table_name;));
 
@@ -216,7 +216,7 @@ my ($pub1_name, $sub1_name) =
   create_sub_pub_w_errors($node_publisher, $node_subscriber, $db,
        $table1_name);
 
-# Apply and Sync errors are > 0 and reset timestamp is NULL
+# Apply errors, sync errors, and conflicts are > 0 and reset timestamp is NULL
 is( $node_subscriber->safe_psql(
                $db,
                qq(SELECT apply_error_count > 0,
@@ -232,7 +232,7 @@ is( $node_subscriber->safe_psql(
        WHERE subname = '$sub1_name')
        ),
        qq(t|t|t|t|t|t|t|t|t),
-       qq(Check that apply errors, sync errors, and conflicts are both > 0 and 
stats_reset is NULL for subscription '$sub1_name'.)
+       qq(Check that apply errors, sync errors, and conflicts are > 0 and 
stats_reset is NULL for subscription '$sub1_name'.)
 );
 
 # Reset a single subscription
@@ -240,7 +240,7 @@ $node_subscriber->safe_psql($db,
        qq(SELECT pg_stat_reset_subscription_stats((SELECT subid FROM 
pg_stat_subscription_stats WHERE subname = '$sub1_name')))
 );
 
-# Apply and Sync errors are 0 and stats reset is not NULL
+# Apply errors, sync errors, and conflicts are 0 and stats reset is not NULL
 is( $node_subscriber->safe_psql(
                $db,
                qq(SELECT apply_error_count = 0,
@@ -256,7 +256,7 @@ is( $node_subscriber->safe_psql(
        WHERE subname = '$sub1_name')
        ),
        qq(t|t|t|t|t|t|t|t|t),
-       qq(Confirm that apply errors, sync errors, and conflicts are both 0 and 
stats_reset is not NULL after reset for subscription '$sub1_name'.)
+       qq(Confirm that apply errors, sync errors, and conflicts are 0 and 
stats_reset is not NULL after reset for subscription '$sub1_name'.)
 );
 
 # Get reset timestamp
@@ -286,7 +286,7 @@ my ($pub2_name, $sub2_name) =
   create_sub_pub_w_errors($node_publisher, $node_subscriber, $db,
        $table2_name);
 
-# Apply and Sync errors are > 0 and reset timestamp is NULL
+# Apply errors, sync errors, and conflicts are > 0 and reset timestamp is NULL
 is( $node_subscriber->safe_psql(
                $db,
                qq(SELECT apply_error_count > 0,
@@ -302,14 +302,14 @@ is( $node_subscriber->safe_psql(
        WHERE subname = '$sub2_name')
        ),
        qq(t|t|t|t|t|t|t|t|t),
-       qq(Confirm that apply errors, sync errors, and conflicts are both > 0 
and stats_reset is NULL for sub '$sub2_name'.)
+       qq(Confirm that apply errors, sync errors, and conflicts are > 0 and 
stats_reset is NULL for sub '$sub2_name'.)
 );
 
 # Reset all subscriptions
 $node_subscriber->safe_psql($db,
        qq(SELECT pg_stat_reset_subscription_stats(NULL)));
 
-# Apply and Sync errors are 0 and stats reset is not NULL
+# Apply errors, sync errors, and conflicts are 0 and stats reset is not NULL
 is( $node_subscriber->safe_psql(
                $db,
                qq(SELECT apply_error_count = 0,
@@ -325,7 +325,7 @@ is( $node_subscriber->safe_psql(
        WHERE subname = '$sub1_name')
        ),
        qq(t|t|t|t|t|t|t|t|t),
-       qq(Confirm that apply errors, sync errors, and conflicts are both 0 and 
stats_reset is not NULL for sub '$sub1_name' after reset.)
+       qq(Confirm that apply errors, sync errors, and conflicts are 0 and 
stats_reset is not NULL for sub '$sub1_name' after reset.)
 );
 
 is( $node_subscriber->safe_psql(
@@ -343,7 +343,7 @@ is( $node_subscriber->safe_psql(
        WHERE subname = '$sub2_name')
        ),
        qq(t|t|t|t|t|t|t|t|t),
-       qq(Confirm that apply errors, sync errors, and conflicts are both 0 and 
stats_reset is not NULL for sub '$sub2_name' after reset.)
+       qq(Confirm that apply errors, sync errors, and conflicts are 0 and 
stats_reset is not NULL for sub '$sub2_name' after reset.)
 );
 
 $reset_time1 = $node_subscriber->safe_psql($db,

Reply via email to