On Mon, Mar 14, 2022 at 2:05 AM Melanie Plageman
<melanieplage...@gmail.com> wrote:
>
> On Sat, Mar 12, 2022 at 3:15 PM Andres Freund <and...@anarazel.de> wrote:
> >
> > Hi,
> >
> > On 2022-03-12 08:28:35 +0530, Amit Kapila wrote:
> > > On Sat, Mar 12, 2022 at 2:14 AM Melanie Plageman
> > > <melanieplage...@gmail.com> wrote:
> > > >
> > > > So, I noticed that pg_stat_reset_subscription_stats() wasn't working
> > > > properly, and, upon further investigation, I'm not sure the view
> > > > pg_stat_subscription_stats is being properly populated.
> > > >
> > >
> > > I have tried the below scenario based on this:
> > > Step:1 Create some data that generates conflicts and lead to apply
> > > failures and then check in the view:
> >
> > I think the problem is present when there was *no* conflict
> > previously. Because nothing populates the stats entry without an error, the
> > reset doesn't have anything to set the stats_reset field in, which then 
> > means
> > that the stats_reset field is NULL even though stats have been reset.
>
> Yes, this is what I meant. stats_reset is not initialized and without
> any conflict happening to populate the stats, after resetting the stats,
> the field still does not get populated. I think this is a bit
> unexpected.
>
> psql (15devel)
> Type "help" for help.
>
> mplageman=# select * from pg_stat_subscription_stats ;
>  subid | subname | apply_error_count | sync_error_count | stats_reset
> -------+---------+-------------------+------------------+-------------
>  16398 | mysub   |                 0 |                0 |
> (1 row)
>
> mplageman=# select pg_stat_reset_subscription_stats(16398);
>  pg_stat_reset_subscription_stats
> ----------------------------------
>
> (1 row)
>
> mplageman=# select * from pg_stat_subscription_stats ;
>  subid | subname | apply_error_count | sync_error_count | stats_reset
> -------+---------+-------------------+------------------+-------------
>  16398 | mysub   |                 0 |                0 |
> (1 row)
>

Looking at other statistics such as replication slots, shared stats,
and SLRU stats, it makes sense that resetting it populates the stats.
So we need to fix this issue.

However, I think the proposed fix has two problems; it can create an
entry for non-existing subscriptions if the user directly calls
function pg_stat_get_subscription_stats(), and stats_reset value is
not updated in the stats file as it is not done by the stats
collector.

An alternative solution would be to send the message for creating the
subscription at the end of CRAETE SUBSCRIPTION which basically
resolves them. A caveat is that if CREATE SUBSCRIPTION (that doesn't
involve replication slot creation) is rolled back, the first problem
still occurs. But it should not practically matter as a similar thing
is possible via existing table-related functions for dropped tables.
Also, we normally don't know the OID of subscription that is rolled
back. I've attached a patch for that.

Regards,

--
Masahiko Sawada
EDB:  https://www.enterprisedb.com/
diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index 3922658bbc..e3a878e7cc 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -611,6 +611,14 @@ CreateSubscription(ParseState *pstate, CreateSubscriptionStmt *stmt,
 
 	InvokeObjectPostCreateHook(SubscriptionRelationId, subid, 0);
 
+	/*
+	 * Send a message for creating the subscription to the stats collector.
+	 * CREATE SUBSCRIPTION that doesn't involve replication slot creation
+	 * might be rolled back but these stats won't be shown on the
+	 * pg_stat_subscription_stats view and removed later by (auto)vacuum.
+	 */
+	pgstat_report_subscription_create(subid);
+
 	return myself;
 }
 
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 53ddd930e6..7a6bad0032 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -380,7 +380,7 @@ static void pgstat_recv_connect(PgStat_MsgConnect *msg, int len);
 static void pgstat_recv_disconnect(PgStat_MsgDisconnect *msg, int len);
 static void pgstat_recv_replslot(PgStat_MsgReplSlot *msg, int len);
 static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len);
-static void pgstat_recv_subscription_drop(PgStat_MsgSubscriptionDrop *msg, int len);
+static void pgstat_recv_subscription(PgStat_MsgSubscription *msg, int len);
 static void pgstat_recv_subscription_error(PgStat_MsgSubscriptionError *msg, int len);
 
 /* ------------------------------------------------------------
@@ -1945,6 +1945,23 @@ pgstat_report_subscription_error(Oid subid, bool is_apply_error)
 	pgstat_send(&msg, sizeof(PgStat_MsgSubscriptionError));
 }
 
+/* ----------
+ * pgstat_report_subscription_create() -
+ *
+ *	Tell the collector about creating the subscription.
+ * ----------
+ */
+void
+pgstat_report_subscription_create(Oid subid)
+{
+	PgStat_MsgSubscription msg;
+
+	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_SUBSCRIPTION);
+	msg.m_subid = subid;
+	msg.m_create = true;
+	pgstat_send(&msg, sizeof(PgStat_MsgSubscription));
+}
+
 /* ----------
  * pgstat_report_subscription_drop() -
  *
@@ -1954,11 +1971,12 @@ pgstat_report_subscription_error(Oid subid, bool is_apply_error)
 void
 pgstat_report_subscription_drop(Oid subid)
 {
-	PgStat_MsgSubscriptionDrop msg;
+	PgStat_MsgSubscription msg;
 
-	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_SUBSCRIPTIONDROP);
+	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_SUBSCRIPTION);
 	msg.m_subid = subid;
-	pgstat_send(&msg, sizeof(PgStat_MsgSubscriptionDrop));
+	msg.m_create = false;
+	pgstat_send(&msg, sizeof(PgStat_MsgSubscription));
 }
 
 /* ----------
@@ -3679,8 +3697,8 @@ PgstatCollectorMain(int argc, char *argv[])
 					pgstat_recv_disconnect(&msg.msg_disconnect, len);
 					break;
 
-				case PGSTAT_MTYPE_SUBSCRIPTIONDROP:
-					pgstat_recv_subscription_drop(&msg.msg_subscriptiondrop, len);
+				case PGSTAT_MTYPE_SUBSCRIPTION:
+					pgstat_recv_subscription(&msg.msg_subscription, len);
 					break;
 
 				case PGSTAT_MTYPE_SUBSCRIPTIONERROR:
@@ -6053,21 +6071,26 @@ pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len)
 }
 
 /* ----------
- * pgstat_recv_subscription_drop() -
+ * pgstat_recv_subscription() -
  *
- *	Process a SUBSCRIPTIONDROP message.
+ *	Process a SUBSCRIPTION message.
  * ----------
  */
 static void
-pgstat_recv_subscription_drop(PgStat_MsgSubscriptionDrop *msg, int len)
+pgstat_recv_subscription(PgStat_MsgSubscription *msg, int len)
 {
-	/* Return if we don't have replication subscription statistics */
-	if (subscriptionStatHash == NULL)
-		return;
+	if (msg->m_create)
+		pgstat_get_subscription_entry(msg->m_subid, true);
+	else
+	{
+		/* Return if we don't have replication subscription statistics */
+		if (subscriptionStatHash == NULL)
+			return;
 
-	/* Remove from hashtable if present; we don't care if it's not */
-	(void) hash_search(subscriptionStatHash, (void *) &(msg->m_subid),
-					   HASH_REMOVE, NULL);
+		/* Remove from hashtable if present; we don't care if it's not */
+		(void) hash_search(subscriptionStatHash, (void *) &(msg->m_subid),
+						   HASH_REMOVE, NULL);
+	}
 }
 
 /* ----------
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index be2f7e2bcc..d897952b56 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -85,7 +85,7 @@ typedef enum StatMsgType
 	PGSTAT_MTYPE_REPLSLOT,
 	PGSTAT_MTYPE_CONNECT,
 	PGSTAT_MTYPE_DISCONNECT,
-	PGSTAT_MTYPE_SUBSCRIPTIONDROP,
+	PGSTAT_MTYPE_SUBSCRIPTION,
 	PGSTAT_MTYPE_SUBSCRIPTIONERROR,
 } StatMsgType;
 
@@ -554,15 +554,17 @@ typedef struct PgStat_MsgReplSlot
 } PgStat_MsgReplSlot;
 
 /* ----------
- * PgStat_MsgSubscriptionDrop	Sent by the backend and autovacuum to tell the
- *								collector about the dead subscription.
+ * PgStat_MsgSubscription		Sent by the backend and autovacuum to tell the
+ *								collector about creating/dropping the subscription.
  * ----------
  */
-typedef struct PgStat_MsgSubscriptionDrop
+typedef struct PgStat_MsgSubscription
 {
 	PgStat_MsgHdr m_hdr;
 	Oid			m_subid;
-} PgStat_MsgSubscriptionDrop;
+	bool		m_create;	/* true if creating the subscription and false
+							 * if dropping the subscription. */
+} PgStat_MsgSubscription;
 
 /* ----------
  * PgStat_MsgSubscriptionError	Sent by the apply worker or the table sync
@@ -755,8 +757,8 @@ typedef union PgStat_Msg
 	PgStat_MsgReplSlot msg_replslot;
 	PgStat_MsgConnect msg_connect;
 	PgStat_MsgDisconnect msg_disconnect;
+	PgStat_MsgSubscription msg_subscription;
 	PgStat_MsgSubscriptionError msg_subscriptionerror;
-	PgStat_MsgSubscriptionDrop msg_subscriptiondrop;
 } PgStat_Msg;
 
 
@@ -1093,8 +1095,9 @@ extern void pgstat_report_checksum_failure(void);
 extern void pgstat_report_replslot(const PgStat_StatReplSlotEntry *repSlotStat);
 extern void pgstat_report_replslot_create(const char *slotname);
 extern void pgstat_report_replslot_drop(const char *slotname);
-extern void pgstat_report_subscription_error(Oid subid, bool is_apply_error);
+extern void pgstat_report_subscription_create(Oid subid);
 extern void pgstat_report_subscription_drop(Oid subid);
+extern void pgstat_report_subscription_error(Oid subid, bool is_apply_error);
 
 extern void pgstat_initialize(void);
 
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index eaf3e7a8d4..9cbef71895 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1945,7 +1945,7 @@ PgStat_MsgResetsinglecounter
 PgStat_MsgResetslrucounter
 PgStat_MsgResetsubcounter
 PgStat_MsgSLRU
-PgStat_MsgSubscriptionDrop
+PgStat_MsgSubscription
 PgStat_MsgSubscriptionError
 PgStat_MsgTabpurge
 PgStat_MsgTabstat

Reply via email to