Fix use-after-free in parallel_vacuum_reset_dead_items
[pgsql.git] / src / test / modules / injection_points / injection_stats.c
blobe16b9db284519201f1f982e30452fd5329c6db27
1 /*--------------------------------------------------------------------------
3 * injection_stats.c
4 * Code for statistics of injection points.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
9 * IDENTIFICATION
10 * src/test/modules/injection_points/injection_stats.c
12 * -------------------------------------------------------------------------
15 #include "postgres.h"
17 #include "fmgr.h"
19 #include "common/hashfn.h"
20 #include "injection_stats.h"
21 #include "pgstat.h"
22 #include "utils/builtins.h"
23 #include "utils/pgstat_internal.h"
25 /* Structures for statistics of injection points */
26 typedef struct PgStat_StatInjEntry
28 PgStat_Counter numcalls; /* number of times point has been run */
29 } PgStat_StatInjEntry;
31 typedef struct PgStatShared_InjectionPoint
33 PgStatShared_Common header;
34 PgStat_StatInjEntry stats;
35 } PgStatShared_InjectionPoint;
37 static bool injection_stats_flush_cb(PgStat_EntryRef *entry_ref, bool nowait);
39 static const PgStat_KindInfo injection_stats = {
40 .name = "injection_points",
41 .fixed_amount = false, /* Bounded by the number of points */
42 .write_to_file = true,
44 /* Injection points are system-wide */
45 .accessed_across_databases = true,
47 .shared_size = sizeof(PgStatShared_InjectionPoint),
48 .shared_data_off = offsetof(PgStatShared_InjectionPoint, stats),
49 .shared_data_len = sizeof(((PgStatShared_InjectionPoint *) 0)->stats),
50 .pending_size = sizeof(PgStat_StatInjEntry),
51 .flush_pending_cb = injection_stats_flush_cb,
55 * Compute stats entry idx from point name with an 8-byte hash.
57 #define PGSTAT_INJ_IDX(name) hash_bytes_extended((const unsigned char *) name, strlen(name), 0)
60 * Kind ID reserved for statistics of injection points.
62 #define PGSTAT_KIND_INJECTION 129
64 /* Track if stats are loaded */
65 static bool inj_stats_loaded = false;
68 * Callback for stats handling
70 static bool
71 injection_stats_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
73 PgStat_StatInjEntry *localent;
74 PgStatShared_InjectionPoint *shfuncent;
76 localent = (PgStat_StatInjEntry *) entry_ref->pending;
77 shfuncent = (PgStatShared_InjectionPoint *) entry_ref->shared_stats;
79 if (!pgstat_lock_entry(entry_ref, nowait))
80 return false;
82 shfuncent->stats.numcalls += localent->numcalls;
83 return true;
87 * Support function for the SQL-callable pgstat* functions. Returns
88 * a pointer to the injection point statistics struct.
90 static PgStat_StatInjEntry *
91 pgstat_fetch_stat_injentry(const char *name)
93 PgStat_StatInjEntry *entry = NULL;
95 if (!inj_stats_loaded || !inj_stats_enabled)
96 return NULL;
98 /* Compile the lookup key as a hash of the point name */
99 entry = (PgStat_StatInjEntry *) pgstat_fetch_entry(PGSTAT_KIND_INJECTION,
100 InvalidOid,
101 PGSTAT_INJ_IDX(name));
102 return entry;
106 * Workhorse to do the registration work, called in _PG_init().
108 void
109 pgstat_register_inj(void)
111 pgstat_register_kind(PGSTAT_KIND_INJECTION, &injection_stats);
113 /* mark stats as loaded */
114 inj_stats_loaded = true;
118 * Report injection point creation.
120 void
121 pgstat_create_inj(const char *name)
123 PgStat_EntryRef *entry_ref;
124 PgStatShared_InjectionPoint *shstatent;
126 /* leave if disabled */
127 if (!inj_stats_loaded || !inj_stats_enabled)
128 return;
130 entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_INJECTION, InvalidOid,
131 PGSTAT_INJ_IDX(name), false);
132 shstatent = (PgStatShared_InjectionPoint *) entry_ref->shared_stats;
134 /* initialize shared memory data */
135 memset(&shstatent->stats, 0, sizeof(shstatent->stats));
136 pgstat_unlock_entry(entry_ref);
140 * Report injection point drop.
142 void
143 pgstat_drop_inj(const char *name)
145 /* leave if disabled */
146 if (!inj_stats_loaded || !inj_stats_enabled)
147 return;
149 if (!pgstat_drop_entry(PGSTAT_KIND_INJECTION, InvalidOid,
150 PGSTAT_INJ_IDX(name)))
151 pgstat_request_entry_refs_gc();
155 * Report statistics for injection point.
157 * This is simple because the set of stats to report currently is simple:
158 * track the number of times a point has been run.
160 void
161 pgstat_report_inj(const char *name)
163 PgStat_EntryRef *entry_ref;
164 PgStatShared_InjectionPoint *shstatent;
165 PgStat_StatInjEntry *statent;
167 /* leave if disabled */
168 if (!inj_stats_loaded || !inj_stats_enabled)
169 return;
171 entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_INJECTION, InvalidOid,
172 PGSTAT_INJ_IDX(name), false);
174 shstatent = (PgStatShared_InjectionPoint *) entry_ref->shared_stats;
175 statent = &shstatent->stats;
177 /* Update the injection point statistics */
178 statent->numcalls++;
180 pgstat_unlock_entry(entry_ref);
184 * SQL function returning the number of times an injection point
185 * has been called.
187 PG_FUNCTION_INFO_V1(injection_points_stats_numcalls);
188 Datum
189 injection_points_stats_numcalls(PG_FUNCTION_ARGS)
191 char *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
192 PgStat_StatInjEntry *entry = pgstat_fetch_stat_injentry(name);
194 if (entry == NULL)
195 PG_RETURN_NULL();
197 PG_RETURN_INT64(entry->numcalls);