From 315ae75e9b6da72456eaa44e55ace9ab1b95ef74 Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Mon, 21 Mar 2022 16:16:42 -0700 Subject: [PATCH] pgstat: reorder pgstat.[ch] contents. Now that 13619598f10 has split pgstat up into multiple files it isn't quite as hard to come up with a sensible order for pgstat.[ch]. Inconsistent naming makes it still not quite right looking, but that's work for another commit. Author: Andres Freund Discussion: https://postgr.es/m/20220303021600.hs34ghqcw6zcokdh@alap3.anarazel.de --- src/backend/postmaster/pgstat.c | 998 ++++++++++++++++---------------- src/include/pgstat.h | 730 ++++++++++++----------- 2 files changed, 899 insertions(+), 829 deletions(-) diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index e781cac7bf7..1e7adc27b9d 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; + /* ---------- * state shared with pgstat_*.c * ---------- @@ -116,6 +186,7 @@ char *pgstat_stat_tmpname = NULL; pgsocket pgStatSock = PGINVALID_SOCKET; + /* ---------- * Local data * ---------- @@ -164,69 +235,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 * ------------------------------------------------------------ @@ -687,11 +695,230 @@ allow_immediate_pgstat_restart(void) last_pgstat_start_time = 0; } + /* ------------------------------------------------------------ - * Public functions used by backends follow - *------------------------------------------------------------ + * 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() - @@ -974,7 +1201,6 @@ pgstat_vacuum_stat(void) } } - /* ---------- * pgstat_collect_oids() - * @@ -1140,130 +1366,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() - * @@ -1290,6 +1392,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() - @@ -1425,22 +1542,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() - @@ -1506,61 +1607,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() - @@ -2003,7 +2082,6 @@ pgstat_get_db_entry(Oid databaseid, bool create) return result; } - /* * Lookup the hash table entry for the specified table. If no hash * table entry exists, initialize it, if the create parameter is true. @@ -2053,6 +2131,151 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create) return result; } +/* ---------- + * pgstat_replslot_entry + * + * Return the entry of replication slot stats with the given name. Return + * NULL if not found and the caller didn't request to create it. + * + * create tells whether to create the new slot entry if it is not found. + * ---------- + */ +static PgStat_StatReplSlotEntry * +pgstat_get_replslot_entry(NameData name, bool create) +{ + PgStat_StatReplSlotEntry *slotent; + bool found; + + if (replSlotStatHash == NULL) + { + HASHCTL hash_ctl; + + /* + * Quick return NULL if the hash table is empty and the caller didn't + * request to create the entry. + */ + if (!create) + return NULL; + + hash_ctl.keysize = sizeof(NameData); + hash_ctl.entrysize = sizeof(PgStat_StatReplSlotEntry); + replSlotStatHash = hash_create("Replication slots hash", + PGSTAT_REPLSLOT_HASH_SIZE, + &hash_ctl, + HASH_ELEM | HASH_BLOBS); + } + + slotent = (PgStat_StatReplSlotEntry *) hash_search(replSlotStatHash, + (void *) &name, + create ? HASH_ENTER : HASH_FIND, + &found); + + if (!slotent) + { + /* not found */ + Assert(!create && !found); + return NULL; + } + + /* initialize the entry */ + if (create && !found) + { + namestrcpy(&(slotent->slotname), NameStr(name)); + pgstat_reset_replslot(slotent, 0); + } + + return slotent; +} + +/* ---------- + * pgstat_reset_replslot + * + * Reset the given replication slot stats. + * ---------- + */ +static void +pgstat_reset_replslot(PgStat_StatReplSlotEntry *slotent, TimestampTz ts) +{ + /* reset only counters. Don't clear slot name */ + slotent->spill_txns = 0; + slotent->spill_count = 0; + slotent->spill_bytes = 0; + slotent->stream_txns = 0; + slotent->stream_count = 0; + slotent->stream_bytes = 0; + slotent->total_txns = 0; + slotent->total_bytes = 0; + slotent->stat_reset_timestamp = ts; +} + +/* ---------- + * pgstat_get_subscription_entry + * + * Return the subscription statistics entry with the given subscription OID. + * If no subscription entry exists, initialize it, if the create parameter is + * true. Else, return NULL. + * ---------- + */ +static PgStat_StatSubEntry * +pgstat_get_subscription_entry(Oid subid, bool create) +{ + PgStat_StatSubEntry *subentry; + bool found; + HASHACTION action = (create ? HASH_ENTER : HASH_FIND); + + if (subscriptionStatHash == NULL) + { + HASHCTL hash_ctl; + + /* + * Quick return NULL if the hash table is empty and the caller didn't + * request to create the entry. + */ + if (!create) + return NULL; + + hash_ctl.keysize = sizeof(Oid); + hash_ctl.entrysize = sizeof(PgStat_StatSubEntry); + subscriptionStatHash = hash_create("Subscription hash", + PGSTAT_SUBSCRIPTION_HASH_SIZE, + &hash_ctl, + HASH_ELEM | HASH_BLOBS); + } + + subentry = (PgStat_StatSubEntry *) hash_search(subscriptionStatHash, + (void *) &subid, + action, &found); + + if (!create && !found) + return NULL; + + /* If not found, initialize the new one */ + if (!found) + pgstat_reset_subscription(subentry, 0); + + return subentry; +} + +/* ---------- + * pgstat_reset_subscription + * + * Reset the given subscription stats. + * ---------- + */ +static void +pgstat_reset_subscription(PgStat_StatSubEntry *subentry, TimestampTz ts) +{ + subentry->apply_error_count = 0; + subentry->sync_error_count = 0; + subentry->stat_reset_timestamp = ts; +} + + +/* ------------------------------------------------------------ + * reading and writing of on-disk stats file + * ------------------------------------------------------------ + */ + /* ---------- * pgstat_write_statsfiles() - * Write the global statistics file, as well as requested DB files. @@ -3201,70 +3424,53 @@ backend_read_statsfile(void) pgStatDBHash = pgstat_read_statsfiles(MyDatabaseId, false, true); } - /* ---------- - * pgstat_setup_memcxt() - + * pgstat_write_statsfile_needed() - * - * Create pgStatLocalContext, if not already done. + * Do we need to write out any stats files? * ---------- */ -static void -pgstat_setup_memcxt(void) +static bool +pgstat_write_statsfile_needed(void) { - if (!pgStatLocalContext) - pgStatLocalContext = AllocSetContextCreate(TopMemoryContext, - "Statistics snapshot", - ALLOCSET_SMALL_SIZES); -} + if (pending_write_requests != NIL) + return true; -/* - * 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); + /* Everything was written recently */ + return false; } -#endif - /* ---------- - * pgstat_clear_snapshot() - + * pgstat_db_requested() - * - * 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. + * Checks whether stats for a particular DB need to be written to a file. * ---------- */ -void -pgstat_clear_snapshot(void) +static bool +pgstat_db_requested(Oid databaseid) { - 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. + * If any requests are outstanding at all, we should write the stats for + * shared catalogs (the "database" with OID 0). This ensures that + * backends will see up-to-date stats for shared catalogs, even though + * they send inquiry messages mentioning only their own DB. */ - pgstat_clear_backend_activity_snapshot(); + if (databaseid == InvalidOid && pending_write_requests != NIL) + return true; + + /* Search to see if there's an open request to write this database. */ + if (list_member_oid(pending_write_requests, databaseid)) + return true; + + return false; } +/* ------------------------------------------------------------ + * stats collector message processing functions + * ------------------------------------------------------------ + */ + /* ---------- * pgstat_recv_inquiry() - * @@ -3357,7 +3563,6 @@ pgstat_recv_inquiry(PgStat_MsgInquiry *msg, int len) msg->databaseid); } - /* ---------- * pgstat_recv_tabstat() - * @@ -3475,7 +3680,6 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len) } } - /* ---------- * pgstat_recv_tabpurge() - * @@ -3508,7 +3712,6 @@ pgstat_recv_tabpurge(PgStat_MsgTabpurge *msg, int len) } } - /* ---------- * pgstat_recv_dropdb() - * @@ -3551,7 +3754,6 @@ pgstat_recv_dropdb(PgStat_MsgDropdb *msg, int len) } } - /* ---------- * pgstat_recv_resetcounter() - * @@ -3772,7 +3974,6 @@ pgstat_recv_resetsubcounter(PgStat_MsgResetsubcounter *msg, int len) } } - /* ---------- * pgstat_recv_autovac() - * @@ -3880,7 +4081,6 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len) } } - /* ---------- * pgstat_recv_archiver() - * @@ -4282,183 +4482,3 @@ pgstat_recv_subscription_error(PgStat_MsgSubscriptionError *msg, int len) else subentry->sync_error_count++; } - -/* ---------- - * pgstat_write_statsfile_needed() - - * - * Do we need to write out any stats files? - * ---------- - */ -static bool -pgstat_write_statsfile_needed(void) -{ - if (pending_write_requests != NIL) - return true; - - /* Everything was written recently */ - return false; -} - -/* ---------- - * pgstat_db_requested() - - * - * Checks whether stats for a particular DB need to be written to a file. - * ---------- - */ -static bool -pgstat_db_requested(Oid databaseid) -{ - /* - * If any requests are outstanding at all, we should write the stats for - * shared catalogs (the "database" with OID 0). This ensures that - * backends will see up-to-date stats for shared catalogs, even though - * they send inquiry messages mentioning only their own DB. - */ - if (databaseid == InvalidOid && pending_write_requests != NIL) - return true; - - /* Search to see if there's an open request to write this database. */ - if (list_member_oid(pending_write_requests, databaseid)) - return true; - - return false; -} - -/* ---------- - * pgstat_replslot_entry - * - * Return the entry of replication slot stats with the given name. Return - * NULL if not found and the caller didn't request to create it. - * - * create tells whether to create the new slot entry if it is not found. - * ---------- - */ -static PgStat_StatReplSlotEntry * -pgstat_get_replslot_entry(NameData name, bool create) -{ - PgStat_StatReplSlotEntry *slotent; - bool found; - - if (replSlotStatHash == NULL) - { - HASHCTL hash_ctl; - - /* - * Quick return NULL if the hash table is empty and the caller didn't - * request to create the entry. - */ - if (!create) - return NULL; - - hash_ctl.keysize = sizeof(NameData); - hash_ctl.entrysize = sizeof(PgStat_StatReplSlotEntry); - replSlotStatHash = hash_create("Replication slots hash", - PGSTAT_REPLSLOT_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS); - } - - slotent = (PgStat_StatReplSlotEntry *) hash_search(replSlotStatHash, - (void *) &name, - create ? HASH_ENTER : HASH_FIND, - &found); - - if (!slotent) - { - /* not found */ - Assert(!create && !found); - return NULL; - } - - /* initialize the entry */ - if (create && !found) - { - namestrcpy(&(slotent->slotname), NameStr(name)); - pgstat_reset_replslot(slotent, 0); - } - - return slotent; -} - -/* ---------- - * pgstat_reset_replslot - * - * Reset the given replication slot stats. - * ---------- - */ -static void -pgstat_reset_replslot(PgStat_StatReplSlotEntry *slotent, TimestampTz ts) -{ - /* reset only counters. Don't clear slot name */ - slotent->spill_txns = 0; - slotent->spill_count = 0; - slotent->spill_bytes = 0; - slotent->stream_txns = 0; - slotent->stream_count = 0; - slotent->stream_bytes = 0; - slotent->total_txns = 0; - slotent->total_bytes = 0; - slotent->stat_reset_timestamp = ts; -} - -/* ---------- - * pgstat_get_subscription_entry - * - * Return the subscription statistics entry with the given subscription OID. - * If no subscription entry exists, initialize it, if the create parameter is - * true. Else, return NULL. - * ---------- - */ -static PgStat_StatSubEntry * -pgstat_get_subscription_entry(Oid subid, bool create) -{ - PgStat_StatSubEntry *subentry; - bool found; - HASHACTION action = (create ? HASH_ENTER : HASH_FIND); - - if (subscriptionStatHash == NULL) - { - HASHCTL hash_ctl; - - /* - * Quick return NULL if the hash table is empty and the caller didn't - * request to create the entry. - */ - if (!create) - return NULL; - - hash_ctl.keysize = sizeof(Oid); - hash_ctl.entrysize = sizeof(PgStat_StatSubEntry); - subscriptionStatHash = hash_create("Subscription hash", - PGSTAT_SUBSCRIPTION_HASH_SIZE, - &hash_ctl, - HASH_ELEM | HASH_BLOBS); - } - - subentry = (PgStat_StatSubEntry *) hash_search(subscriptionStatHash, - (void *) &subid, - action, &found); - - if (!create && !found) - return NULL; - - /* If not found, initialize the new one */ - if (!found) - pgstat_reset_subscription(subentry, 0); - - return subentry; -} - -/* ---------- - * pgstat_reset_subscription - * - * Reset the given subscription stats. - * ---------- - */ -static void -pgstat_reset_subscription(PgStat_StatSubEntry *subentry, TimestampTz ts) -{ - subentry->apply_error_count = 0; - subentry->sync_error_count = 0; - subentry->stat_reset_timestamp = ts; -} diff --git a/src/include/pgstat.h b/src/include/pgstat.h index cfb00ba65a5..534d595ca08 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,76 @@ 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_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; + /* ---------- * PgStat_TableCounts The actual per-table counts kept by a backend * @@ -137,27 +164,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 * @@ -210,6 +216,43 @@ typedef struct PgStat_TableXactStatus * ------------------------------------------------------------ */ +/* ---------- + * 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 @@ -241,7 +284,6 @@ typedef struct PgStat_MsgDummy PgStat_MsgHdr m_hdr; } PgStat_MsgDummy; - /* ---------- * PgStat_MsgInquiry Sent by a backend to ask the collector * to write the stats file(s). @@ -260,7 +302,6 @@ typedef struct PgStat_MsgDummy * effect unless that occurs. We assume clock_time >= cutoff_time, though. * ---------- */ - typedef struct PgStat_MsgInquiry { PgStat_MsgHdr m_hdr; @@ -269,7 +310,6 @@ typedef struct PgStat_MsgInquiry Oid databaseid; /* requested DB (InvalidOid => shared only) */ } PgStat_MsgInquiry; - /* ---------- * PgStat_TableEntry Per-table info in a MsgTabstat * ---------- @@ -304,7 +344,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 +361,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 +372,6 @@ typedef struct PgStat_MsgDropdb Oid m_databaseid; } PgStat_MsgDropdb; - /* ---------- * PgStat_MsgResetcounter Sent by the backend to tell the collector * to reset counters @@ -405,7 +442,6 @@ typedef struct PgStat_MsgResetsubcounter * stats */ } PgStat_MsgResetsubcounter; - /* ---------- * PgStat_MsgAutovacStart Sent by the autovacuum daemon to signal * that a database is going to be processed @@ -418,7 +454,6 @@ typedef struct PgStat_MsgAutovacStart TimestampTz m_start_time; } PgStat_MsgAutovacStart; - /* ---------- * PgStat_MsgVacuum Sent by the backend or autovacuum daemon * after VACUUM @@ -435,7 +470,6 @@ typedef struct PgStat_MsgVacuum PgStat_Counter m_dead_tuples; } PgStat_MsgVacuum; - /* ---------- * PgStat_MsgAnalyze Sent by the backend or autovacuum daemon * after ANALYZE @@ -453,7 +487,6 @@ typedef struct PgStat_MsgAnalyze PgStat_Counter m_dead_tuples; } PgStat_MsgAnalyze; - /* ---------- * PgStat_MsgArchiver Sent by the archiver to update statistics. * ---------- @@ -601,33 +634,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 * ---------- @@ -770,6 +776,48 @@ typedef union PgStat_Msg #define PGSTAT_FILE_FORMAT_ID 0x01A5BCA6 +/* + * Archiver statistics kept in the stats collector + */ +typedef struct PgStat_ArchiverStats +{ + PgStat_Counter archived_count; /* archival successes */ + char last_archived_wal[MAX_XFN_CHARS + 1]; /* last WAL file + * archived */ + TimestampTz last_archived_timestamp; /* last archival success time */ + PgStat_Counter failed_count; /* failed archival attempts */ + char last_failed_wal[MAX_XFN_CHARS + 1]; /* WAL file involved in + * last failure */ + TimestampTz last_failed_timestamp; /* last archival failure time */ + TimestampTz stat_reset_timestamp; +} PgStat_ArchiverStats; + +/* + * Background writer statistics kept in the stats collector + */ +typedef struct PgStat_BgWriterStats +{ + PgStat_Counter buf_written_clean; + PgStat_Counter maxwritten_clean; + PgStat_Counter buf_alloc; + TimestampTz stat_reset_timestamp; +} PgStat_BgWriterStats; + +/* + * Checkpointer statistics kept in the stats collector + */ +typedef struct PgStat_CheckpointerStats +{ + TimestampTz stats_timestamp; /* time of stats file update */ + PgStat_Counter timed_checkpoints; + PgStat_Counter requested_checkpoints; + PgStat_Counter checkpoint_write_time; /* times in milliseconds */ + PgStat_Counter checkpoint_sync_time; + PgStat_Counter buf_written_checkpoints; + PgStat_Counter buf_written_backend; + PgStat_Counter buf_fsync_backend; +} PgStat_CheckpointerStats; + /* ---------- * PgStat_StatDBEntry The collector's data per database * ---------- @@ -818,6 +866,74 @@ typedef struct PgStat_StatDBEntry HTAB *functions; } PgStat_StatDBEntry; +/* ---------- + * PgStat_StatFuncEntry The collector's data per function + * ---------- + */ +typedef struct PgStat_StatFuncEntry +{ + Oid functionid; + + PgStat_Counter f_numcalls; + + PgStat_Counter f_total_time; /* times in microseconds */ + PgStat_Counter f_self_time; +} PgStat_StatFuncEntry; + +/* + * Global statistics kept in the stats collector + */ +typedef struct PgStat_GlobalStats +{ + TimestampTz stats_timestamp; /* time of stats file update */ + + PgStat_CheckpointerStats checkpointer; + PgStat_BgWriterStats bgwriter; +} PgStat_GlobalStats; + +/* + * Replication slot statistics kept in the stats collector + */ +typedef struct PgStat_StatReplSlotEntry +{ + NameData slotname; + PgStat_Counter spill_txns; + PgStat_Counter spill_count; + PgStat_Counter spill_bytes; + PgStat_Counter stream_txns; + PgStat_Counter stream_count; + PgStat_Counter stream_bytes; + PgStat_Counter total_txns; + PgStat_Counter total_bytes; + TimestampTz stat_reset_timestamp; +} PgStat_StatReplSlotEntry; + +/* + * SLRU statistics kept in the stats collector + */ +typedef struct PgStat_SLRUStats +{ + PgStat_Counter blocks_zeroed; + PgStat_Counter blocks_hit; + PgStat_Counter blocks_read; + PgStat_Counter blocks_written; + PgStat_Counter blocks_exists; + PgStat_Counter flush; + PgStat_Counter truncate; + TimestampTz stat_reset_timestamp; +} PgStat_SLRUStats; + +/* + * Subscription statistics kept in the stats collector. + */ +typedef struct PgStat_StatSubEntry +{ + Oid subid; /* hash key (must be first) */ + + PgStat_Counter apply_error_count; + PgStat_Counter sync_error_count; + TimestampTz stat_reset_timestamp; +} PgStat_StatSubEntry; /* ---------- * PgStat_StatTabEntry The collector's data per table (or index) @@ -855,75 +971,6 @@ typedef struct PgStat_StatTabEntry PgStat_Counter autovac_analyze_count; } PgStat_StatTabEntry; - -/* ---------- - * PgStat_StatFuncEntry The collector's data per function - * ---------- - */ -typedef struct PgStat_StatFuncEntry -{ - Oid functionid; - - PgStat_Counter f_numcalls; - - PgStat_Counter f_total_time; /* times in microseconds */ - PgStat_Counter f_self_time; -} PgStat_StatFuncEntry; - - -/* - * Archiver statistics kept in the stats collector - */ -typedef struct PgStat_ArchiverStats -{ - PgStat_Counter archived_count; /* archival successes */ - char last_archived_wal[MAX_XFN_CHARS + 1]; /* last WAL file - * archived */ - TimestampTz last_archived_timestamp; /* last archival success time */ - PgStat_Counter failed_count; /* failed archival attempts */ - char last_failed_wal[MAX_XFN_CHARS + 1]; /* WAL file involved in - * last failure */ - TimestampTz last_failed_timestamp; /* last archival failure time */ - TimestampTz stat_reset_timestamp; -} PgStat_ArchiverStats; - -/* - * Background writer statistics kept in the stats collector - */ -typedef struct PgStat_BgWriterStats -{ - PgStat_Counter buf_written_clean; - PgStat_Counter maxwritten_clean; - PgStat_Counter buf_alloc; - TimestampTz stat_reset_timestamp; -} PgStat_BgWriterStats; - -/* - * Checkpointer statistics kept in the stats collector - */ -typedef struct PgStat_CheckpointerStats -{ - TimestampTz stats_timestamp; /* time of stats file update */ - PgStat_Counter timed_checkpoints; - PgStat_Counter requested_checkpoints; - PgStat_Counter checkpoint_write_time; /* times in milliseconds */ - PgStat_Counter checkpoint_sync_time; - PgStat_Counter buf_written_checkpoints; - PgStat_Counter buf_written_backend; - PgStat_Counter buf_fsync_backend; -} PgStat_CheckpointerStats; - -/* - * Global statistics kept in the stats collector - */ -typedef struct PgStat_GlobalStats -{ - TimestampTz stats_timestamp; /* time of stats file update */ - - PgStat_CheckpointerStats checkpointer; - PgStat_BgWriterStats bgwriter; -} PgStat_GlobalStats; - /* * WAL statistics kept in the stats collector */ @@ -940,145 +987,115 @@ typedef struct PgStat_WalStats TimestampTz stat_reset_timestamp; } PgStat_WalStats; -/* - * SLRU statistics kept in the stats collector - */ -typedef struct PgStat_SLRUStats -{ - PgStat_Counter blocks_zeroed; - PgStat_Counter blocks_hit; - PgStat_Counter blocks_read; - PgStat_Counter blocks_written; - PgStat_Counter blocks_exists; - PgStat_Counter flush; - PgStat_Counter truncate; - TimestampTz stat_reset_timestamp; -} PgStat_SLRUStats; /* - * Replication slot statistics kept in the stats collector + * Functions in pgstat.c */ -typedef struct PgStat_StatReplSlotEntry -{ - NameData slotname; - PgStat_Counter spill_txns; - PgStat_Counter spill_count; - PgStat_Counter spill_bytes; - PgStat_Counter stream_txns; - PgStat_Counter stream_count; - PgStat_Counter stream_bytes; - PgStat_Counter total_txns; - PgStat_Counter total_bytes; - TimestampTz stat_reset_timestamp; -} PgStat_StatReplSlotEntry; -/* - * Subscription statistics kept in the stats collector. - */ -typedef struct PgStat_StatSubEntry -{ - Oid subid; /* hash key (must be first) */ - - PgStat_Counter apply_error_count; - PgStat_Counter sync_error_count; - TimestampTz stat_reset_timestamp; -} PgStat_StatSubEntry; - -/* - * 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; - - -/* ---------- - * 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; - -/* - * BgWriter statistics counters are updated directly by bgwriter and bufmgr - */ -extern PgStat_MsgBgWriter PendingBgWriterStats; - -/* - * Checkpointer statistics counters are updated directly by checkpointer and - * bufmgr. - */ -extern PgStat_MsgCheckpointer PendingCheckpointerStats; - -/* - * WAL statistics counter is updated by backends and background processes - */ -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 - * ---------- - */ +/* functions called from postmaster */ extern void pgstat_init(void); -extern int pgstat_start(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); -/* ---------- - * Functions called from backends - * ---------- - */ -extern void pgstat_ping(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_clear_snapshot(void); +/* Functions called from backends */ extern void pgstat_report_stat(bool force); extern void pgstat_vacuum_stat(void); -extern void pgstat_drop_database(Oid databaseid); +extern void pgstat_ping(void); -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_reset_shared_counters(const char *); +/* stats accessors */ +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_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid); +extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid); +extern PgStat_GlobalStats *pgstat_fetch_global(void); +extern PgStat_StatReplSlotEntry *pgstat_fetch_replslot(NameData slotname); +extern PgStat_StatSubEntry *pgstat_fetch_stat_subscription(Oid subid); +extern PgStat_SLRUStats *pgstat_fetch_slru(void); +extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid); +extern PgStat_WalStats *pgstat_fetch_stat_wal(void); + + +/* + * Functions in pgstat_archiver.c + */ + +extern void pgstat_send_archiver(const char *xlog, bool failed); + + +/* + * Functions in pgstat_bgwriter.c + */ + +extern void pgstat_send_bgwriter(void); + + +/* + * Functions in pgstat_checkpointer.c + */ + +extern void pgstat_send_checkpointer(void); + + +/* + * Functions in pgstat_database.c + */ + +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)) + + +/* + * Functions in pgstat_function.c + */ + +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_BackendFunctionEntry *find_funcstat_entry(Oid func_id); + + +/* + * Functions in pgstat_relation.c + */ + +extern void pgstat_relation_init(Relation rel); + extern void pgstat_report_autovac(Oid dboid); extern void pgstat_report_vacuum(Oid tableoid, bool shared, PgStat_Counter livetuples, PgStat_Counter deadtuples); @@ -1086,24 +1103,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); - #define pgstat_relation_should_count(rel) \ (likely((rel)->pgstat_info != NULL)) @@ -1144,14 +1143,6 @@ extern void pgstat_relation_init(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); @@ -1159,45 +1150,29 @@ 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 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); +extern PgStat_TableStatus *find_tabstat_entry(Oid rel_id); -/* ---------- - * Support functions for the SQL-callable functions to - * generate the pgstat* views. - * ---------- + +/* + * Functions in pgstat_replslot.c */ -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_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); + + +/* + * Functions in pgstat_slru.c + */ + +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); @@ -1208,4 +1183,79 @@ 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); + +/* + * Functions in pgstat_subscription.c + */ + +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); + + +/* + * Functions in pgstat_wal.c + */ + +extern void pgstat_send_wal(bool force); + + +/* + * Variables in pgstat.c + */ + +/* 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; + + +/* + * Variables in pgstat_bgwriter.c + */ + +/* updated directly by bgwriter and bufmgr */ +extern PgStat_MsgBgWriter PendingBgWriterStats; + + +/* + * Variables in pgstat_checkpointer.c + */ + +/* + * Checkpointer statistics counters are updated directly by checkpointer and + * bufmgr. + */ +extern PgStat_MsgCheckpointer PendingCheckpointerStats; + + +/* + * Variables in pgstat_database.c + */ + +/* 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; + + +/* + * Variables in pgstat_wal.c + */ + +/* updated directly by backends and background processes */ +extern PgStat_MsgWal WalStats; + + #endif /* PGSTAT_H */