+ tabentry->analyze_count++;
+ }
+}
+
+
+/* ----------
+ * pgstat_recv_bgwriter() -
+ *
+ * Process a BGWRITER message.
+ * ----------
+ */
+static void
+pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len)
+{
+ globalStats.timed_checkpoints += msg->m_timed_checkpoints;
+ globalStats.requested_checkpoints += msg->m_requested_checkpoints;
+ globalStats.buf_written_checkpoints += msg->m_buf_written_checkpoints;
+ globalStats.buf_written_clean += msg->m_buf_written_clean;
+ globalStats.maxwritten_clean += msg->m_maxwritten_clean;
+ globalStats.buf_written_backend += msg->m_buf_written_backend;
+ globalStats.buf_fsync_backend += msg->m_buf_fsync_backend;
+ globalStats.buf_alloc += msg->m_buf_alloc;
+}
+
+/* ----------
+ * pgstat_recv_recoveryconflict() -
+ *
+ * Process as RECOVERYCONFLICT message.
+ * ----------
+ */
+static void
+pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len)
+{
+ PgStat_StatDBEntry *dbentry;
+
+ dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
+
+ switch (msg->m_reason)
+ {
+ case PROCSIG_RECOVERY_CONFLICT_DATABASE:
+
+ /*
+ * Since we drop the information about the database as soon as it
+ * replicates, there is no point in counting these conflicts.
+ */
+ break;
+ case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
+ dbentry->n_conflict_tablespace++;
+ break;
+ case PROCSIG_RECOVERY_CONFLICT_LOCK:
+ dbentry->n_conflict_lock++;
+ break;
+ case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
+ dbentry->n_conflict_snapshot++;
+ break;
+ case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
+ dbentry->n_conflict_bufferpin++;
+ break;
+ case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
+ dbentry->n_conflict_startup_deadlock++;
+ break;
+ }
+}
+
+/* ----------
+ * pgstat_recv_funcstat() -
+ *
+ * Count what the backend has done.
+ * ----------
+ */
+static void
+pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len)
+{
+ PgStat_FunctionEntry *funcmsg = &(msg->m_entry[0]);
+ PgStat_StatDBEntry *dbentry;
+ PgStat_StatFuncEntry *funcentry;
+ int i;
+ bool found;
+
+ dbentry = pgstat_get_db_entry(msg->m_databaseid, true);
+
+ /*
+ * Process all function entries in the message.
+ */
+ for (i = 0; i < msg->m_nentries; i++, funcmsg++)
+ {
+ funcentry = (PgStat_StatFuncEntry *) hash_search(dbentry->functions,
+ (void *) &(funcmsg->f_id),
+ HASH_ENTER, &found);
+
+ if (!found)
+ {
+ /*
+ * If it's a new function entry, initialize counters to the values
+ * we just got.
+ */
+ funcentry->f_numcalls = funcmsg->f_numcalls;
+ funcentry->f_time = funcmsg->f_time;
+ funcentry->f_time_self = funcmsg->f_time_self;
+ }
+ else
+ {
+ /*
+ * Otherwise add the values to the existing entry.
+ */
+ funcentry->f_numcalls += funcmsg->f_numcalls;
+ funcentry->f_time += funcmsg->f_time;
+ funcentry->f_time_self += funcmsg->f_time_self;
+ }
+ }
+}
+
+/* ----------
+ * pgstat_recv_funcpurge() -
+ *
+ * Arrange for dead function removal.
+ * ----------
+ */
+static void
+pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len)
+{
+ PgStat_StatDBEntry *dbentry;
+ int i;
+
+ dbentry = pgstat_get_db_entry(msg->m_databaseid, false);
+
+ /*
+ * No need to purge if we don't even know the database.
+ */
+ if (!dbentry || !dbentry->functions)
+ return;
+
+ /*
+ * Process all function entries in the message.
+ */
+ for (i = 0; i < msg->m_nentries; i++)
+ {
+ /* Remove from hashtable if present; we don't care if it's not. */
+ (void) hash_search(dbentry->functions,
+ (void *) &(msg->m_functionid[i]),
+ HASH_REMOVE, NULL);
+ }