From 58a203616edbf7b2549bc83712bb07355d6b2cf6 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Wed, 2 Mar 2022 18:02:03 -0800 Subject: [PATCH v65 06/11] pgstat: reorder file pgstat.c / pgstat.h contents. --- src/include/pgstat.h | 499 ++++++++++++------------ src/backend/postmaster/pgstat.c | 651 ++++++++++++++++---------------- 2 files changed, 594 insertions(+), 556 deletions(-) diff --git a/src/include/pgstat.h b/src/include/pgstat.h index f808955125b..8d3e8ebf9cf 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -33,6 +33,7 @@ /* Default directory to store temporary statistics data in */ #define PG_STAT_TMP_DIR "pg_stat_tmp" + /* Values for track_functions GUC variable --- order is significant! */ typedef enum TrackFunctionsLevel { @@ -51,50 +52,33 @@ typedef enum SessionEndType DISCONNECT_KILLED } SessionEndType; -/* ---------- - * The types of backend -> collector messages - * ---------- - */ -typedef enum StatMsgType -{ - PGSTAT_MTYPE_DUMMY, - PGSTAT_MTYPE_INQUIRY, - PGSTAT_MTYPE_TABSTAT, - PGSTAT_MTYPE_TABPURGE, - PGSTAT_MTYPE_DROPDB, - PGSTAT_MTYPE_RESETCOUNTER, - PGSTAT_MTYPE_RESETSHAREDCOUNTER, - PGSTAT_MTYPE_RESETSINGLECOUNTER, - PGSTAT_MTYPE_RESETSLRUCOUNTER, - PGSTAT_MTYPE_RESETREPLSLOTCOUNTER, - PGSTAT_MTYPE_RESETSUBCOUNTER, - PGSTAT_MTYPE_AUTOVAC_START, - PGSTAT_MTYPE_VACUUM, - PGSTAT_MTYPE_ANALYZE, - PGSTAT_MTYPE_ARCHIVER, - PGSTAT_MTYPE_BGWRITER, - PGSTAT_MTYPE_CHECKPOINTER, - PGSTAT_MTYPE_WAL, - PGSTAT_MTYPE_SLRU, - PGSTAT_MTYPE_FUNCSTAT, - PGSTAT_MTYPE_FUNCPURGE, - PGSTAT_MTYPE_RECOVERYCONFLICT, - PGSTAT_MTYPE_TEMPFILE, - PGSTAT_MTYPE_DEADLOCK, - PGSTAT_MTYPE_CHECKSUMFAILURE, - PGSTAT_MTYPE_REPLSLOT, - PGSTAT_MTYPE_CONNECT, - PGSTAT_MTYPE_DISCONNECT, - PGSTAT_MTYPE_SUBSCRIPTIONDROP, - PGSTAT_MTYPE_SUBSCRIPTIONERROR, -} StatMsgType; - /* ---------- * The data type used for counters. * ---------- */ typedef int64 PgStat_Counter; +/* Possible targets for resetting cluster-wide shared values */ +typedef enum PgStat_Shared_Reset_Target +{ + RESET_ARCHIVER, + RESET_BGWRITER, + RESET_WAL +} PgStat_Shared_Reset_Target; + +/* Possible object types for resetting single counters */ +typedef enum PgStat_Single_Reset_Type +{ + RESET_TABLE, + RESET_FUNCTION +} PgStat_Single_Reset_Type; + + +/* ------------------------------------------------------------ + * Structures kept in backend local memory while accumulating counts + * ------------------------------------------------------------ + */ + /* ---------- * PgStat_TableCounts The actual per-table counts kept by a backend * @@ -137,27 +121,6 @@ typedef struct PgStat_TableCounts PgStat_Counter t_blocks_hit; } PgStat_TableCounts; -/* Possible targets for resetting cluster-wide shared values */ -typedef enum PgStat_Shared_Reset_Target -{ - RESET_ARCHIVER, - RESET_BGWRITER, - RESET_WAL -} PgStat_Shared_Reset_Target; - -/* Possible object types for resetting single counters */ -typedef enum PgStat_Single_Reset_Type -{ - RESET_TABLE, - RESET_FUNCTION -} PgStat_Single_Reset_Type; - -/* ------------------------------------------------------------ - * Structures kept in backend local memory while accumulating counts - * ------------------------------------------------------------ - */ - - /* ---------- * PgStat_TableStatus Per-table status within a backend * @@ -205,11 +168,92 @@ typedef struct PgStat_TableXactStatus } PgStat_TableXactStatus; +/* ---------- + * PgStat_FunctionCounts The actual per-function counts kept by a backend + * + * This struct should contain only actual event counters, because we memcmp + * it against zeroes to detect whether there are any counts to transmit. + * + * Note that the time counters are in instr_time format here. We convert to + * microseconds in PgStat_Counter format when transmitting to the collector. + * ---------- + */ +typedef struct PgStat_FunctionCounts +{ + PgStat_Counter f_numcalls; + instr_time f_total_time; + instr_time f_self_time; +} PgStat_FunctionCounts; + +/* ---------- + * PgStat_BackendFunctionEntry Entry in backend's per-function hash table + * ---------- + */ +typedef struct PgStat_BackendFunctionEntry +{ + Oid f_id; + PgStat_FunctionCounts f_counts; +} PgStat_BackendFunctionEntry; + +/* + * Working state needed to accumulate per-function-call timing statistics. + */ +typedef struct PgStat_FunctionCallUsage +{ + /* Link to function's hashtable entry (must still be there at exit!) */ + /* NULL means we are not tracking the current function call */ + PgStat_FunctionCounts *fs; + /* Total time previously charged to function, as of function start */ + instr_time save_f_total_time; + /* Backend-wide total time as of function start */ + instr_time save_total; + /* system clock as of function start */ + instr_time f_start; +} PgStat_FunctionCallUsage; + + /* ------------------------------------------------------------ * Message formats follow * ------------------------------------------------------------ */ +/* ---------- + * The types of backend -> collector messages + * ---------- + */ +typedef enum StatMsgType +{ + PGSTAT_MTYPE_DUMMY, + PGSTAT_MTYPE_INQUIRY, + PGSTAT_MTYPE_TABSTAT, + PGSTAT_MTYPE_TABPURGE, + PGSTAT_MTYPE_DROPDB, + PGSTAT_MTYPE_RESETCOUNTER, + PGSTAT_MTYPE_RESETSHAREDCOUNTER, + PGSTAT_MTYPE_RESETSINGLECOUNTER, + PGSTAT_MTYPE_RESETSLRUCOUNTER, + PGSTAT_MTYPE_RESETREPLSLOTCOUNTER, + PGSTAT_MTYPE_RESETSUBCOUNTER, + PGSTAT_MTYPE_AUTOVAC_START, + PGSTAT_MTYPE_VACUUM, + PGSTAT_MTYPE_ANALYZE, + PGSTAT_MTYPE_ARCHIVER, + PGSTAT_MTYPE_BGWRITER, + PGSTAT_MTYPE_CHECKPOINTER, + PGSTAT_MTYPE_WAL, + PGSTAT_MTYPE_SLRU, + PGSTAT_MTYPE_FUNCSTAT, + PGSTAT_MTYPE_FUNCPURGE, + PGSTAT_MTYPE_RECOVERYCONFLICT, + PGSTAT_MTYPE_TEMPFILE, + PGSTAT_MTYPE_DEADLOCK, + PGSTAT_MTYPE_CHECKSUMFAILURE, + PGSTAT_MTYPE_REPLSLOT, + PGSTAT_MTYPE_CONNECT, + PGSTAT_MTYPE_DISCONNECT, + PGSTAT_MTYPE_SUBSCRIPTIONDROP, + PGSTAT_MTYPE_SUBSCRIPTIONERROR, +} StatMsgType; /* ---------- * PgStat_MsgHdr The common message header @@ -304,7 +348,6 @@ typedef struct PgStat_MsgTabstat PgStat_TableEntry m_entry[PGSTAT_NUM_TABENTRIES]; } PgStat_MsgTabstat; - /* ---------- * PgStat_MsgTabpurge Sent by the backend to tell the collector * about dead tables. @@ -322,7 +365,6 @@ typedef struct PgStat_MsgTabpurge Oid m_tableid[PGSTAT_NUM_TABPURGE]; } PgStat_MsgTabpurge; - /* ---------- * PgStat_MsgDropdb Sent by the backend to tell the collector * about a dropped database @@ -334,7 +376,6 @@ typedef struct PgStat_MsgDropdb Oid m_databaseid; } PgStat_MsgDropdb; - /* ---------- * PgStat_MsgResetcounter Sent by the backend to tell the collector * to reset counters @@ -435,7 +476,6 @@ typedef struct PgStat_MsgVacuum PgStat_Counter m_dead_tuples; } PgStat_MsgVacuum; - /* ---------- * PgStat_MsgAnalyze Sent by the backend or autovacuum daemon * after ANALYZE @@ -601,33 +641,6 @@ typedef struct PgStat_MsgTempFile size_t m_filesize; } PgStat_MsgTempFile; -/* ---------- - * PgStat_FunctionCounts The actual per-function counts kept by a backend - * - * This struct should contain only actual event counters, because we memcmp - * it against zeroes to detect whether there are any counts to transmit. - * - * Note that the time counters are in instr_time format here. We convert to - * microseconds in PgStat_Counter format when transmitting to the collector. - * ---------- - */ -typedef struct PgStat_FunctionCounts -{ - PgStat_Counter f_numcalls; - instr_time f_total_time; - instr_time f_self_time; -} PgStat_FunctionCounts; - -/* ---------- - * PgStat_BackendFunctionEntry Entry in backend's per-function hash table - * ---------- - */ -typedef struct PgStat_BackendFunctionEntry -{ - Oid f_id; - PgStat_FunctionCounts f_counts; -} PgStat_BackendFunctionEntry; - /* ---------- * PgStat_FunctionEntry Per-function info in a MsgFuncstat * ---------- @@ -818,7 +831,6 @@ typedef struct PgStat_StatDBEntry HTAB *functions; } PgStat_StatDBEntry; - /* ---------- * PgStat_StatTabEntry The collector's data per table (or index) * ---------- @@ -855,7 +867,6 @@ typedef struct PgStat_StatTabEntry PgStat_Counter autovac_analyze_count; } PgStat_StatTabEntry; - /* ---------- * PgStat_StatFuncEntry The collector's data per function * ---------- @@ -870,7 +881,6 @@ typedef struct PgStat_StatFuncEntry PgStat_Counter f_self_time; } PgStat_StatFuncEntry; - /* * Archiver statistics kept in the stats collector */ @@ -924,22 +934,6 @@ typedef struct PgStat_GlobalStats PgStat_BgWriterStats bgwriter; } PgStat_GlobalStats; -/* - * WAL statistics kept in the stats collector - */ -typedef struct PgStat_WalStats -{ - PgStat_Counter wal_records; - PgStat_Counter wal_fpi; - uint64 wal_bytes; - PgStat_Counter wal_buffers_full; - PgStat_Counter wal_write; - PgStat_Counter wal_sync; - PgStat_Counter wal_write_time; - PgStat_Counter wal_sync_time; - TimestampTz stat_reset_timestamp; -} PgStat_WalStats; - /* * SLRU statistics kept in the stats collector */ @@ -985,32 +979,167 @@ typedef struct PgStat_StatSubEntry } PgStat_StatSubEntry; /* - * Working state needed to accumulate per-function-call timing statistics. + * WAL statistics kept in the stats collector */ -typedef struct PgStat_FunctionCallUsage +typedef struct PgStat_WalStats { - /* Link to function's hashtable entry (must still be there at exit!) */ - /* NULL means we are not tracking the current function call */ - PgStat_FunctionCounts *fs; - /* Total time previously charged to function, as of function start */ - instr_time save_f_total_time; - /* Backend-wide total time as of function start */ - instr_time save_total; - /* system clock as of function start */ - instr_time f_start; -} PgStat_FunctionCallUsage; + PgStat_Counter wal_records; + PgStat_Counter wal_fpi; + uint64 wal_bytes; + PgStat_Counter wal_buffers_full; + PgStat_Counter wal_write; + PgStat_Counter wal_sync; + PgStat_Counter wal_write_time; + PgStat_Counter wal_sync_time; + TimestampTz stat_reset_timestamp; +} PgStat_WalStats; /* ---------- - * GUC parameters + * pgstat.c - statistics infrastructure * ---------- */ + +/* functions called from postmaster */ +extern void pgstat_init(void); +extern void pgstat_reset_all(void); +extern int pgstat_start(void); +extern void allow_immediate_pgstat_restart(void); + +#ifdef EXEC_BACKEND +extern void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); +#endif + +/* Functions for backend initialization */ +extern void pgstat_initialize(void); + +/* transactional integration */ +extern void AtEOXact_PgStat(bool isCommit, bool parallel); +extern void AtEOSubXact_PgStat(bool isCommit, int nestDepth); +extern void AtPrepare_PgStat(void); +extern void PostPrepare_PgStat(void); +extern void pgstat_twophase_postcommit(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void pgstat_twophase_postabort(TransactionId xid, uint16 info, + void *recdata, uint32 len); +extern void pgstat_clear_snapshot(void); + +/* Functions called from backends */ +extern void pgstat_report_stat(bool force); +extern void pgstat_vacuum_stat(void); +extern void pgstat_reset_counters(void); +extern void pgstat_reset_single_counter(Oid objectid, PgStat_Single_Reset_Type type); +extern void pgstat_ping(void); +extern PgStat_GlobalStats *pgstat_fetch_global(void); + +/* GUC parameters */ extern PGDLLIMPORT bool pgstat_track_counts; extern PGDLLIMPORT int pgstat_track_functions; extern char *pgstat_stat_directory; extern char *pgstat_stat_tmpname; extern char *pgstat_stat_filename; + +/* ---------- + * pgstat_database.c - database statistics + * ---------- + */ + +extern void pgstat_drop_database(Oid databaseid); +extern void pgstat_report_recovery_conflict(int reason); +extern void pgstat_report_deadlock(void); +extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount); +extern void pgstat_report_checksum_failure(void); +extern void pgstat_report_connect(Oid dboid); + +#define pgstat_count_buffer_read_time(n) \ + (pgStatBlockReadTime += (n)) +#define pgstat_count_buffer_write_time(n) \ + (pgStatBlockWriteTime += (n)) +#define pgstat_count_conn_active_time(n) \ + (pgStatActiveTime += (n)) +#define pgstat_count_conn_txn_idle_time(n) \ + (pgStatTransactionIdleTime += (n)) + +extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid); + +/* + * Updated by pgstat_count_buffer_*_time macros + */ +extern PgStat_Counter pgStatBlockReadTime; +extern PgStat_Counter pgStatBlockWriteTime; + +/* + * Updated by pgstat_count_conn_*_time macros, called by + * pgstat_report_activity(). + */ +extern PgStat_Counter pgStatActiveTime; +extern PgStat_Counter pgStatTransactionIdleTime; + +/* + * Updated by the traffic cop and in errfinish() + */ +extern SessionEndType pgStatSessionEndCause; + + +/* ---------- + * pgstat_function.c - function statistics + * ---------- + */ + +struct FunctionCallInfoBaseData; +extern void pgstat_init_function_usage(struct FunctionCallInfoBaseData *fcinfo, + PgStat_FunctionCallUsage *fcu); +extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, + bool finalize); + +extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid); +extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id); + + +/* ---------- + * pgstat_global.c - system wide statistics + * ---------- + */ + +extern void pgstat_reset_shared_counters(const char *); + +/* archiver stats */ +extern void pgstat_send_archiver(const char *xlog, bool failed); +extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void); + +/* bgwriter stats */ +extern void pgstat_send_bgwriter(void); +extern PgStat_BgWriterStats *pgstat_fetch_stat_bgwriter(void); + +/* checkpointer stats */ +extern void pgstat_send_checkpointer(void); +extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void); + +/* replication slot stats */ +extern void pgstat_reset_replslot_counter(const char *name); +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 PgStat_StatReplSlotEntry *pgstat_fetch_replslot(NameData slotname); + +/* slru stats */ +extern void pgstat_reset_slru_counter(const char *); +extern void pgstat_count_slru_page_zeroed(int slru_idx); +extern void pgstat_count_slru_page_hit(int slru_idx); +extern void pgstat_count_slru_page_read(int slru_idx); +extern void pgstat_count_slru_page_written(int slru_idx); +extern void pgstat_count_slru_page_exists(int slru_idx); +extern void pgstat_count_slru_flush(int slru_idx); +extern void pgstat_count_slru_truncate(int slru_idx); +extern const char *pgstat_slru_name(int slru_idx); +extern int pgstat_slru_index(const char *name); +extern PgStat_SLRUStats *pgstat_fetch_slru(void); + +/* wal stats */ +extern void pgstat_send_wal(bool force); +extern PgStat_WalStats *pgstat_fetch_stat_wal(void); + /* * BgWriter statistics counters are updated directly by bgwriter and bufmgr */ @@ -1027,58 +1156,15 @@ extern PgStat_MsgCheckpointer PendingCheckpointerStats; */ extern PgStat_MsgWal WalStats; -/* - * Updated by pgstat_count_buffer_*_time macros - */ -extern PgStat_Counter pgStatBlockReadTime; -extern PgStat_Counter pgStatBlockWriteTime; - -/* - * Updated by pgstat_count_conn_*_time macros, called by - * pgstat_report_activity(). - */ -extern PgStat_Counter pgStatActiveTime; -extern PgStat_Counter pgStatTransactionIdleTime; - - -/* - * Updated by the traffic cop and in errfinish() - */ -extern SessionEndType pgStatSessionEndCause; /* ---------- - * Functions called from postmaster + * pgstat_relation.c - relation (tables, indexes) statistics * ---------- */ -extern void pgstat_init(void); -extern int pgstat_start(void); -extern void pgstat_reset_all(void); -extern void allow_immediate_pgstat_restart(void); -#ifdef EXEC_BACKEND -extern void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); -#endif +extern void pgstat_relation_init(Relation rel); +extern void pgstat_relation_assoc(Relation rel); - -/* ---------- - * Functions called from backends - * ---------- - */ -extern void pgstat_ping(void); - -extern void pgstat_report_stat(bool force); -extern void pgstat_vacuum_stat(void); -extern void pgstat_drop_database(Oid databaseid); - -extern void pgstat_clear_snapshot(void); -extern void pgstat_reset_counters(void); -extern void pgstat_reset_shared_counters(const char *); -extern void pgstat_reset_single_counter(Oid objectid, PgStat_Single_Reset_Type type); -extern void pgstat_reset_slru_counter(const char *); -extern void pgstat_reset_replslot_counter(const char *name); -extern void pgstat_reset_subscription_counter(Oid subid); - -extern void pgstat_report_connect(Oid dboid); extern void pgstat_report_autovac(Oid dboid); extern void pgstat_report_vacuum(Oid tableoid, bool shared, PgStat_Counter livetuples, PgStat_Counter deadtuples); @@ -1086,25 +1172,6 @@ extern void pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, PgStat_Counter deadtuples, bool resetcounter); -extern void pgstat_report_recovery_conflict(int reason); -extern void pgstat_report_deadlock(void); -extern void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount); -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_drop(Oid subid); - -extern void pgstat_initialize(void); - - -extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id); -extern PgStat_BackendFunctionEntry *find_funcstat_entry(Oid func_id); - -extern void pgstat_relation_init(Relation rel); -extern void pgstat_relation_assoc(Relation rel); - /* * AFIXME: pgstat_enabled should instead be tri-valued (disabled, * needs-initialization, initialized). Then we don't need to check two @@ -1114,7 +1181,6 @@ extern void pgstat_relation_assoc(Relation rel); (likely((rel)->pgstat_info != NULL) ? true : \ ((rel)->pgstat_enabled ? pgstat_relation_assoc(rel), true : false)) - /* nontransactional event counts are simple enough to inline */ #define pgstat_count_heap_scan(rel) \ @@ -1152,14 +1218,6 @@ extern void pgstat_relation_assoc(Relation rel); if (pgstat_relation_should_count(rel)) \ (rel)->pgstat_info->t_counts.t_blocks_hit++; \ } while (0) -#define pgstat_count_buffer_read_time(n) \ - (pgStatBlockReadTime += (n)) -#define pgstat_count_buffer_write_time(n) \ - (pgStatBlockWriteTime += (n)) -#define pgstat_count_conn_active_time(n) \ - (pgStatActiveTime += (n)) -#define pgstat_count_conn_txn_idle_time(n) \ - (pgStatTransactionIdleTime += (n)) extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n); extern void pgstat_count_heap_update(Relation rel, bool hot); @@ -1167,53 +1225,18 @@ extern void pgstat_count_heap_delete(Relation rel); extern void pgstat_count_truncate(Relation rel); extern void pgstat_update_heap_dead_tuples(Relation rel, int delta); -struct FunctionCallInfoBaseData; -extern void pgstat_init_function_usage(struct FunctionCallInfoBaseData *fcinfo, - PgStat_FunctionCallUsage *fcu); -extern void pgstat_end_function_usage(PgStat_FunctionCallUsage *fcu, - bool finalize); +extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid); +extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id); -extern void AtEOXact_PgStat(bool isCommit, bool parallel); -extern void AtEOSubXact_PgStat(bool isCommit, int nestDepth); - -extern void AtPrepare_PgStat(void); -extern void PostPrepare_PgStat(void); - -extern void pgstat_twophase_postcommit(TransactionId xid, uint16 info, - void *recdata, uint32 len); -extern void pgstat_twophase_postabort(TransactionId xid, uint16 info, - void *recdata, uint32 len); - -extern void pgstat_send_archiver(const char *xlog, bool failed); -extern void pgstat_send_bgwriter(void); -extern void pgstat_send_checkpointer(void); -extern void pgstat_send_wal(bool force); /* ---------- - * Support functions for the SQL-callable functions to - * generate the pgstat* views. + * pgstat_subscription.c - subscription statistics * ---------- */ -extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid); -extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid); -extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid); -extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid); -extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void); -extern PgStat_BgWriterStats *pgstat_fetch_stat_bgwriter(void); -extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void); -extern PgStat_GlobalStats *pgstat_fetch_global(void); -extern PgStat_WalStats *pgstat_fetch_stat_wal(void); -extern PgStat_SLRUStats *pgstat_fetch_slru(void); -extern PgStat_StatReplSlotEntry *pgstat_fetch_replslot(NameData slotname); -extern void pgstat_count_slru_page_zeroed(int slru_idx); -extern void pgstat_count_slru_page_hit(int slru_idx); -extern void pgstat_count_slru_page_read(int slru_idx); -extern void pgstat_count_slru_page_written(int slru_idx); -extern void pgstat_count_slru_page_exists(int slru_idx); -extern void pgstat_count_slru_flush(int slru_idx); -extern void pgstat_count_slru_truncate(int slru_idx); -extern const char *pgstat_slru_name(int slru_idx); -extern int pgstat_slru_index(const char *name); +extern void pgstat_reset_subscription_counter(Oid subid); +extern void pgstat_report_subscription_error(Oid subid, bool is_apply_error); +extern void pgstat_report_subscription_drop(Oid subid); +extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid); #endif /* PGSTAT_H */ diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index 3b693460a93..fc104b52603 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -71,10 +71,12 @@ #include "utils/snapmgr.h" #include "utils/timestamp.h" + /* ---------- * Timer definitions. * ---------- */ + #define PGSTAT_RETRY_DELAY 10 /* How long to wait between checks for a * new file; in milliseconds. */ @@ -95,20 +97,88 @@ #define PGSTAT_MIN_RCVBUF (100 * 1024) +/* ---------- + * Local function forward declarations + * ---------- + */ + +#ifdef EXEC_BACKEND +static pid_t pgstat_forkexec(void); +#endif + +NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); + +static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create); +static PgStat_StatTabEntry *pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, + Oid tableoid, bool create); +static PgStat_StatSubEntry *pgstat_get_subscription_entry(Oid subid, bool create); +static void pgstat_reset_subscription(PgStat_StatSubEntry *subentry, TimestampTz ts); +static void pgstat_write_statsfiles(bool permanent, bool allDbs); +static void pgstat_write_db_statsfile(PgStat_StatDBEntry *dbentry, bool permanent); +static HTAB *pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep); +static void pgstat_read_db_statsfile(Oid databaseid, HTAB *tabhash, HTAB *funchash, + bool permanent); +static void backend_read_statsfile(void); + +static bool pgstat_write_statsfile_needed(void); +static bool pgstat_db_requested(Oid databaseid); + +static PgStat_StatReplSlotEntry *pgstat_get_replslot_entry(NameData name, bool create_it); +static void pgstat_reset_replslot(PgStat_StatReplSlotEntry *slotstats, TimestampTz ts); + +static HTAB *pgstat_collect_oids(Oid catalogid, AttrNumber anum_oid); + +static void pgstat_setup_memcxt(void); + +static void pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len); +static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len); +static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len); +static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len); +static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); +static void pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len); +static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len); +static void pgstat_recv_resetslrucounter(PgStat_MsgResetslrucounter *msg, int len); +static void pgstat_recv_resetreplslotcounter(PgStat_MsgResetreplslotcounter *msg, int len); +static void pgstat_recv_resetsubcounter(PgStat_MsgResetsubcounter *msg, int len); +static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len); +static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len); +static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len); +static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len); +static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len); +static void pgstat_recv_checkpointer(PgStat_MsgCheckpointer *msg, int len); +static void pgstat_recv_wal(PgStat_MsgWal *msg, int len); +static void pgstat_recv_slru(PgStat_MsgSLRU *msg, int len); +static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len); +static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len); +static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len); +static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len); +static void pgstat_recv_checksum_failure(PgStat_MsgChecksumFailure *msg, int len); +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_error(PgStat_MsgSubscriptionError *msg, int len); + + /* ---------- * GUC parameters * ---------- */ + bool pgstat_track_counts = false; + /* ---------- * Built from GUC parameter * ---------- */ + char *pgstat_stat_directory = NULL; char *pgstat_stat_filename = NULL; char *pgstat_stat_tmpname = NULL; + /* ---------- * Local data * ---------- @@ -159,69 +229,6 @@ static bool pgstat_is_shutdown = false; #endif -/* ---------- - * Local function forward declarations - * ---------- - */ -#ifdef EXEC_BACKEND -static pid_t pgstat_forkexec(void); -#endif - -NON_EXEC_STATIC void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn(); - -static PgStat_StatDBEntry *pgstat_get_db_entry(Oid databaseid, bool create); -static PgStat_StatTabEntry *pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, - Oid tableoid, bool create); -static PgStat_StatSubEntry *pgstat_get_subscription_entry(Oid subid, bool create); -static void pgstat_reset_subscription(PgStat_StatSubEntry *subentry, TimestampTz ts); -static void pgstat_write_statsfiles(bool permanent, bool allDbs); -static void pgstat_write_db_statsfile(PgStat_StatDBEntry *dbentry, bool permanent); -static HTAB *pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep); -static void pgstat_read_db_statsfile(Oid databaseid, HTAB *tabhash, HTAB *funchash, - bool permanent); -static void backend_read_statsfile(void); - -static bool pgstat_write_statsfile_needed(void); -static bool pgstat_db_requested(Oid databaseid); - -static PgStat_StatReplSlotEntry *pgstat_get_replslot_entry(NameData name, bool create_it); -static void pgstat_reset_replslot(PgStat_StatReplSlotEntry *slotstats, TimestampTz ts); - -static HTAB *pgstat_collect_oids(Oid catalogid, AttrNumber anum_oid); - -static void pgstat_setup_memcxt(void); - - -static void pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len); -static void pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len); -static void pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len); -static void pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len); -static void pgstat_recv_resetcounter(PgStat_MsgResetcounter *msg, int len); -static void pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len); -static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, int len); -static void pgstat_recv_resetslrucounter(PgStat_MsgResetslrucounter *msg, int len); -static void pgstat_recv_resetreplslotcounter(PgStat_MsgResetreplslotcounter *msg, int len); -static void pgstat_recv_resetsubcounter(PgStat_MsgResetsubcounter *msg, int len); -static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len); -static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len); -static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len); -static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len); -static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len); -static void pgstat_recv_checkpointer(PgStat_MsgCheckpointer *msg, int len); -static void pgstat_recv_wal(PgStat_MsgWal *msg, int len); -static void pgstat_recv_slru(PgStat_MsgSLRU *msg, int len); -static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len); -static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len); -static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len); -static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len); -static void pgstat_recv_checksum_failure(PgStat_MsgChecksumFailure *msg, int len); -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_error(PgStat_MsgSubscriptionError *msg, int len); - /* ------------------------------------------------------------ * Public functions called from postmaster follow * ------------------------------------------------------------ @@ -682,12 +689,231 @@ allow_immediate_pgstat_restart(void) last_pgstat_start_time = 0; } + +/* ------------------------------------------------------------ + * Backend initialization / shutdown functions + * ------------------------------------------------------------ + */ + +/* + * Shut down a single backend's statistics reporting at process exit. + * + * Flush any remaining statistics counts out to the collector. + * Without this, operations triggered during backend exit (such as + * temp table deletions) won't be counted. + */ +static void +pgstat_shutdown_hook(int code, Datum arg) +{ + Assert(!pgstat_is_shutdown); + + /* + * If we got as far as discovering our own database ID, we can report what + * we did to the collector. Otherwise, we'd be sending an invalid + * database ID, so forget it. (This means that accesses to pg_database + * during failed backend starts might never get counted.) + */ + if (OidIsValid(MyDatabaseId)) + pgstat_report_stat(true); + +#ifdef USE_ASSERT_CHECKING + pgstat_is_shutdown = true; +#endif +} + +/* ---------- + * pgstat_initialize() - + * + * Initialize pgstats state, and set up our on-proc-exit hook. Called from + * BaseInit(). + * + * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful. + * ---------- + */ +void +pgstat_initialize(void) +{ + Assert(!pgstat_is_initialized); + + pgstat_wal_initialize(); + + /* Set up a process-exit hook to clean up */ + before_shmem_exit(pgstat_shutdown_hook, 0); + +#ifdef USE_ASSERT_CHECKING + pgstat_is_initialized = true; +#endif +} + + +/* ------------------------------------------------------------ + * Transaction integration + *------------------------------------------------------------ + */ + +/* ---------- + * AtEOXact_PgStat + * + * Called from access/transam/xact.c at top-level transaction commit/abort. + * ---------- + */ +void +AtEOXact_PgStat(bool isCommit, bool parallel) +{ + PgStat_SubXactStatus *xact_state; + + AtEOXact_PgStat_Database(isCommit, parallel); + + /* handle transactional stats information */ + xact_state = pgStatXactStack; + if (xact_state != NULL) + { + Assert(xact_state->nest_level == 1); + Assert(xact_state->prev == NULL); + + AtEOXact_PgStat_Relations(xact_state, isCommit); + } + pgStatXactStack = NULL; + + /* Make sure any stats snapshot is thrown away */ + pgstat_clear_snapshot(); +} + +/* ---------- + * AtEOSubXact_PgStat + * + * Called from access/transam/xact.c at subtransaction commit/abort. + * ---------- + */ +void +AtEOSubXact_PgStat(bool isCommit, int nestDepth) +{ + PgStat_SubXactStatus *xact_state; + + /* merge the sub-transaction's transactional stats into the parent */ + xact_state = pgStatXactStack; + if (xact_state != NULL && + xact_state->nest_level >= nestDepth) + { + /* delink xact_state from stack immediately to simplify reuse case */ + pgStatXactStack = xact_state->prev; + + AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth); + + pfree(xact_state); + } +} + +/* + * AtPrepare_PgStat + * Save the transactional stats state at 2PC transaction prepare. + */ +void +AtPrepare_PgStat(void) +{ + PgStat_SubXactStatus *xact_state; + + xact_state = pgStatXactStack; + if (xact_state != NULL) + { + Assert(xact_state->nest_level == 1); + Assert(xact_state->prev == NULL); + + AtPrepare_PgStat_Relations(xact_state); + } +} + +/* + * PostPrepare_PgStat + * Clean up after successful PREPARE. + * + * Note: AtEOXact_PgStat is not called during PREPARE. + */ +void +PostPrepare_PgStat(void) +{ + PgStat_SubXactStatus *xact_state; + + /* + * We don't bother to free any of the transactional state, since it's all + * in TopTransactionContext and will go away anyway. + */ + xact_state = pgStatXactStack; + if (xact_state != NULL) + { + Assert(xact_state->nest_level == 1); + Assert(xact_state->prev == NULL); + + PostPrepare_PgStat_Relations(xact_state); + } + pgStatXactStack = NULL; + + /* Make sure any stats snapshot is thrown away */ + pgstat_clear_snapshot(); +} + +/* ---------- + * pgstat_clear_snapshot() - + * + * Discard any data collected in the current transaction. Any subsequent + * request will cause new snapshots to be read. + * + * This is also invoked during transaction commit or abort to discard + * the no-longer-wanted snapshot. + * ---------- + */ +void +pgstat_clear_snapshot(void) +{ + pgstat_assert_is_up(); + + /* Release memory, if any was allocated */ + if (pgStatLocalContext) + MemoryContextDelete(pgStatLocalContext); + + /* Reset variables */ + pgStatLocalContext = NULL; + pgStatDBHash = NULL; + replSlotStatHash = NULL; + subscriptionStatHash = NULL; + + /* + * Historically the backend_status.c facilities lived in this file, and + * were reset with the same function. For now keep it that way, and + * forward the reset request. + */ + pgstat_clear_backend_activity_snapshot(); +} + +/* + * Ensure (sub)transaction stack entry for the given nest_level exists, adding + * it if needed. + */ +PgStat_SubXactStatus * +pgstat_xact_stack_level_get(int nest_level) +{ + PgStat_SubXactStatus *xact_state; + + xact_state = pgStatXactStack; + if (xact_state == NULL || xact_state->nest_level != nest_level) + { + xact_state = (PgStat_SubXactStatus *) + MemoryContextAlloc(TopTransactionContext, + sizeof(PgStat_SubXactStatus)); + xact_state->nest_level = nest_level; + xact_state->prev = pgStatXactStack; + xact_state->first = NULL; + pgStatXactStack = xact_state; + } + return xact_state; +} + + /* ------------------------------------------------------------ * Public functions used by backends follow *------------------------------------------------------------ */ - /* ---------- * pgstat_report_stat() - * @@ -976,7 +1202,6 @@ pgstat_vacuum_stat(void) } } - /* ---------- * pgstat_collect_oids() - * @@ -1109,130 +1334,6 @@ pgstat_send_inquiry(TimestampTz clock_time, TimestampTz cutoff_time, Oid databas pgstat_send(&msg, sizeof(msg)); } -/* - * Ensure (sub)transaction stack entry for the given nest_level exists, adding - * it if needed. - */ -PgStat_SubXactStatus * -pgstat_xact_stack_level_get(int nest_level) -{ - PgStat_SubXactStatus *xact_state; - - xact_state = pgStatXactStack; - if (xact_state == NULL || xact_state->nest_level != nest_level) - { - xact_state = (PgStat_SubXactStatus *) - MemoryContextAlloc(TopTransactionContext, - sizeof(PgStat_SubXactStatus)); - xact_state->nest_level = nest_level; - xact_state->prev = pgStatXactStack; - xact_state->first = NULL; - pgStatXactStack = xact_state; - } - return xact_state; -} - -/* ---------- - * AtEOXact_PgStat - * - * Called from access/transam/xact.c at top-level transaction commit/abort. - * ---------- - */ -void -AtEOXact_PgStat(bool isCommit, bool parallel) -{ - PgStat_SubXactStatus *xact_state; - - AtEOXact_PgStat_Database(isCommit, parallel); - - /* handle transactional stats information */ - xact_state = pgStatXactStack; - if (xact_state != NULL) - { - Assert(xact_state->nest_level == 1); - Assert(xact_state->prev == NULL); - - AtEOXact_PgStat_Relations(xact_state, isCommit); - } - pgStatXactStack = NULL; - - /* Make sure any stats snapshot is thrown away */ - pgstat_clear_snapshot(); -} - -/* ---------- - * AtEOSubXact_PgStat - * - * Called from access/transam/xact.c at subtransaction commit/abort. - * ---------- - */ -void -AtEOSubXact_PgStat(bool isCommit, int nestDepth) -{ - PgStat_SubXactStatus *xact_state; - - /* merge the sub-transaction's transactional stats into the parent */ - xact_state = pgStatXactStack; - if (xact_state != NULL && - xact_state->nest_level >= nestDepth) - { - /* delink xact_state from stack immediately to simplify reuse case */ - pgStatXactStack = xact_state->prev; - - AtEOSubXact_PgStat_Relations(xact_state, isCommit, nestDepth); - - pfree(xact_state); - } -} - -/* - * AtPrepare_PgStat - * Save the transactional stats state at 2PC transaction prepare. - */ -void -AtPrepare_PgStat(void) -{ - PgStat_SubXactStatus *xact_state; - - xact_state = pgStatXactStack; - if (xact_state != NULL) - { - Assert(xact_state->nest_level == 1); - Assert(xact_state->prev == NULL); - - AtPrepare_PgStat_Relations(xact_state); - } -} - -/* - * PostPrepare_PgStat - * Clean up after successful PREPARE. - * - * Note: AtEOXact_PgStat is not called during PREPARE. - */ -void -PostPrepare_PgStat(void) -{ - PgStat_SubXactStatus *xact_state; - - /* - * We don't bother to free any of the transactional state, since it's all - * in TopTransactionContext and will go away anyway. - */ - xact_state = pgStatXactStack; - if (xact_state != NULL) - { - Assert(xact_state->nest_level == 1); - Assert(xact_state->prev == NULL); - - PostPrepare_PgStat_Relations(xact_state); - } - pgStatXactStack = NULL; - - /* Make sure any stats snapshot is thrown away */ - pgstat_clear_snapshot(); -} - /* ---------- * pgstat_fetch_stat_dbentry() - * @@ -1259,6 +1360,21 @@ pgstat_fetch_stat_dbentry(Oid dbid) HASH_FIND, NULL); } +/* + * --------- + * pgstat_fetch_global() - + * + * Support function for the SQL-callable pgstat* functions. Returns + * a pointer to the global statistics struct. + * --------- + */ +PgStat_GlobalStats * +pgstat_fetch_global(void) +{ + backend_read_statsfile(); + + return &globalStats; +} /* ---------- * pgstat_fetch_stat_tabentry() - @@ -1394,22 +1510,6 @@ pgstat_fetch_stat_checkpointer(void) return &globalStats.checkpointer; } -/* - * --------- - * pgstat_fetch_global() - - * - * Support function for the SQL-callable pgstat* functions. Returns - * a pointer to the global statistics struct. - * --------- - */ -PgStat_GlobalStats * -pgstat_fetch_global(void) -{ - backend_read_statsfile(); - - return &globalStats; -} - /* * --------- * pgstat_fetch_stat_wal() - @@ -1475,61 +1575,39 @@ pgstat_fetch_stat_subscription(Oid subid) return pgstat_get_subscription_entry(subid, false); } -/* - * Shut down a single backend's statistics reporting at process exit. - * - * Flush any remaining statistics counts out to the collector. - * Without this, operations triggered during backend exit (such as - * temp table deletions) won't be counted. - */ -static void -pgstat_shutdown_hook(int code, Datum arg) -{ - Assert(!pgstat_is_shutdown); - - /* - * If we got as far as discovering our own database ID, we can report what - * we did to the collector. Otherwise, we'd be sending an invalid - * database ID, so forget it. (This means that accesses to pg_database - * during failed backend starts might never get counted.) - */ - if (OidIsValid(MyDatabaseId)) - pgstat_report_stat(true); - -#ifdef USE_ASSERT_CHECKING - pgstat_is_shutdown = true; -#endif -} - -/* ---------- - * pgstat_initialize() - - * - * Initialize pgstats state, and set up our on-proc-exit hook. Called from - * BaseInit(). - * - * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful. - * ---------- - */ -void -pgstat_initialize(void) -{ - Assert(!pgstat_is_initialized); - - pgstat_wal_initialize(); - - /* Set up a process-exit hook to clean up */ - before_shmem_exit(pgstat_shutdown_hook, 0); - -#ifdef USE_ASSERT_CHECKING - pgstat_is_initialized = true; -#endif -} /* ------------------------------------------------------------ - * Local support functions follow + * Helper / infrastructure functions * ------------------------------------------------------------ */ +/* ---------- + * pgstat_setup_memcxt() - + * + * Create pgStatLocalContext, if not already done. + * ---------- + */ +static void +pgstat_setup_memcxt(void) +{ + if (!pgStatLocalContext) + pgStatLocalContext = AllocSetContextCreate(TopMemoryContext, + "Statistics snapshot", + ALLOCSET_SMALL_SIZES); +} + +/* + * Stats should only be reported after pgstat_initialize() and before + * pgstat_shutdown(). This check is put in a few central places to catch + * violations of this rule more easily. + */ +#ifdef USE_ASSERT_CHECKING +void +pgstat_assert_is_up(void) +{ + Assert(pgstat_is_initialized && !pgstat_is_shutdown); +} +#endif /* ---------- * pgstat_setheader() - @@ -3171,69 +3249,6 @@ backend_read_statsfile(void) } -/* ---------- - * pgstat_setup_memcxt() - - * - * Create pgStatLocalContext, if not already done. - * ---------- - */ -static void -pgstat_setup_memcxt(void) -{ - if (!pgStatLocalContext) - pgStatLocalContext = AllocSetContextCreate(TopMemoryContext, - "Statistics snapshot", - ALLOCSET_SMALL_SIZES); -} - -/* - * Stats should only be reported after pgstat_initialize() and before - * pgstat_shutdown(). This check is put in a few central places to catch - * violations of this rule more easily. - */ -#ifdef USE_ASSERT_CHECKING -void -pgstat_assert_is_up(void) -{ - Assert(pgstat_is_initialized && !pgstat_is_shutdown); -} -#endif - - -/* ---------- - * pgstat_clear_snapshot() - - * - * Discard any data collected in the current transaction. Any subsequent - * request will cause new snapshots to be read. - * - * This is also invoked during transaction commit or abort to discard - * the no-longer-wanted snapshot. - * ---------- - */ -void -pgstat_clear_snapshot(void) -{ - pgstat_assert_is_up(); - - /* Release memory, if any was allocated */ - if (pgStatLocalContext) - MemoryContextDelete(pgStatLocalContext); - - /* Reset variables */ - pgStatLocalContext = NULL; - pgStatDBHash = NULL; - replSlotStatHash = NULL; - subscriptionStatHash = NULL; - - /* - * Historically the backend_status.c facilities lived in this file, and - * were reset with the same function. For now keep it that way, and - * forward the reset request. - */ - pgstat_clear_backend_activity_snapshot(); -} - - /* ---------- * pgstat_recv_inquiry() - * -- 2.35.1.354.g715d08a9e5