/*-------------------------------------------------------------------------- * * injection_stats.c * Code for statistics of injection points. * * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION * src/test/modules/injection_points/injection_stats.c * * ------------------------------------------------------------------------- */ #include "postgres.h" #include "fmgr.h" #include "common/hashfn.h" #include "injection_stats.h" #include "pgstat.h" #include "utils/builtins.h" #include "utils/pgstat_internal.h" /* Structures for statistics of injection points */ typedef struct PgStat_StatInjEntry { PgStat_Counter numcalls; /* number of times point has been run */ } PgStat_StatInjEntry; typedef struct PgStatShared_InjectionPoint { PgStatShared_Common header; PgStat_StatInjEntry stats; } PgStatShared_InjectionPoint; static bool injection_stats_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); static const PgStat_KindInfo injection_stats = { .name = "injection_points", .fixed_amount = false, /* Bounded by the number of points */ .write_to_file = true, /* Injection points are system-wide */ .accessed_across_databases = true, .shared_size = sizeof(PgStatShared_InjectionPoint), .shared_data_off = offsetof(PgStatShared_InjectionPoint, stats), .shared_data_len = sizeof(((PgStatShared_InjectionPoint *) 0)->stats), .pending_size = sizeof(PgStat_StatInjEntry), .flush_pending_cb = injection_stats_flush_cb, }; /* * Compute stats entry idx from point name with an 8-byte hash. */ #define PGSTAT_INJ_IDX(name) hash_bytes_extended((const unsigned char *) name, strlen(name), 0) /* * Kind ID reserved for statistics of injection points. */ #define PGSTAT_KIND_INJECTION 129 /* Track if stats are loaded */ static bool inj_stats_loaded = false; /* * Callback for stats handling */ static bool injection_stats_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) { PgStat_StatInjEntry *localent; PgStatShared_InjectionPoint *shfuncent; localent = (PgStat_StatInjEntry *) entry_ref->pending; shfuncent = (PgStatShared_InjectionPoint *) entry_ref->shared_stats; if (!pgstat_lock_entry(entry_ref, nowait)) return false; shfuncent->stats.numcalls += localent->numcalls; pgstat_unlock_entry(entry_ref); return true; } /* * Support function for the SQL-callable pgstat* functions. Returns * a pointer to the injection point statistics struct. */ static PgStat_StatInjEntry * pgstat_fetch_stat_injentry(const char *name) { PgStat_StatInjEntry *entry = NULL; if (!inj_stats_loaded || !inj_stats_enabled) return NULL; /* Compile the lookup key as a hash of the point name */ entry = (PgStat_StatInjEntry *) pgstat_fetch_entry(PGSTAT_KIND_INJECTION, InvalidOid, PGSTAT_INJ_IDX(name)); return entry; } /* * Workhorse to do the registration work, called in _PG_init(). */ void pgstat_register_inj(void) { pgstat_register_kind(PGSTAT_KIND_INJECTION, &injection_stats); /* mark stats as loaded */ inj_stats_loaded = true; } /* * Report injection point creation. */ void pgstat_create_inj(const char *name) { PgStat_EntryRef *entry_ref; PgStatShared_InjectionPoint *shstatent; /* leave if disabled */ if (!inj_stats_loaded || !inj_stats_enabled) return; entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_INJECTION, InvalidOid, PGSTAT_INJ_IDX(name), NULL); shstatent = (PgStatShared_InjectionPoint *) entry_ref->shared_stats; /* initialize shared memory data */ memset(&shstatent->stats, 0, sizeof(shstatent->stats)); } /* * Report injection point drop. */ void pgstat_drop_inj(const char *name) { /* leave if disabled */ if (!inj_stats_loaded || !inj_stats_enabled) return; if (!pgstat_drop_entry(PGSTAT_KIND_INJECTION, InvalidOid, PGSTAT_INJ_IDX(name))) pgstat_request_entry_refs_gc(); } /* * Report statistics for injection point. * * This is simple because the set of stats to report currently is simple: * track the number of times a point has been run. */ void pgstat_report_inj(const char *name) { PgStat_EntryRef *entry_ref; PgStatShared_InjectionPoint *shstatent; PgStat_StatInjEntry *statent; /* leave if disabled */ if (!inj_stats_loaded || !inj_stats_enabled) return; entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_INJECTION, InvalidOid, PGSTAT_INJ_IDX(name), NULL); shstatent = (PgStatShared_InjectionPoint *) entry_ref->shared_stats; statent = &shstatent->stats; /* Update the injection point statistics */ statent->numcalls++; } /* * SQL function returning the number of times an injection point * has been called. */ PG_FUNCTION_INFO_V1(injection_points_stats_numcalls); Datum injection_points_stats_numcalls(PG_FUNCTION_ARGS) { char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); PgStat_StatInjEntry *entry = pgstat_fetch_stat_injentry(name); if (entry == NULL) PG_RETURN_NULL(); PG_RETURN_INT64(entry->numcalls); } /* Only used by injection_points_stats_drop() */ static bool match_inj_entries(PgStatShared_HashEntry *entry, Datum match_data) { return entry->key.kind == PGSTAT_KIND_INJECTION; } /* * SQL function that drops all injection point statistics. */ PG_FUNCTION_INFO_V1(injection_points_stats_drop); Datum injection_points_stats_drop(PG_FUNCTION_ARGS) { pgstat_drop_matching_entries(match_inj_entries, 0); PG_RETURN_VOID(); }