Line data Source code
1 : /*--------------------------------------------------------------------------
2 : *
3 : * injection_stats_fixed.c
4 : * Code for fixed-numbered statistics of injection points.
5 : *
6 : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : * IDENTIFICATION
10 : * src/test/modules/injection_points/injection_stats_fixed.c
11 : *
12 : * -------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres.h"
16 :
17 : #include "fmgr.h"
18 :
19 : #include "access/htup_details.h"
20 : #include "common/hashfn.h"
21 : #include "funcapi.h"
22 : #include "injection_stats.h"
23 : #include "pgstat.h"
24 : #include "utils/builtins.h"
25 : #include "utils/pgstat_internal.h"
26 :
27 : /* Structures for statistics of injection points, fixed-size */
28 : typedef struct PgStat_StatInjFixedEntry
29 : {
30 : PgStat_Counter numattach; /* number of points attached */
31 : PgStat_Counter numdetach; /* number of points detached */
32 : PgStat_Counter numrun; /* number of points run */
33 : PgStat_Counter numcached; /* number of points cached */
34 : PgStat_Counter numloaded; /* number of points loaded */
35 : TimestampTz stat_reset_timestamp;
36 : } PgStat_StatInjFixedEntry;
37 :
38 : typedef struct PgStatShared_InjectionPointFixed
39 : {
40 : LWLock lock; /* protects all the counters */
41 : uint32 changecount;
42 : PgStat_StatInjFixedEntry stats;
43 : PgStat_StatInjFixedEntry reset_offset;
44 : } PgStatShared_InjectionPointFixed;
45 :
46 : /* Callbacks for fixed-numbered stats */
47 : static void injection_stats_fixed_init_shmem_cb(void *stats);
48 : static void injection_stats_fixed_reset_all_cb(TimestampTz ts);
49 : static void injection_stats_fixed_snapshot_cb(void);
50 :
51 : static const PgStat_KindInfo injection_stats_fixed = {
52 : .name = "injection_points_fixed",
53 : .fixed_amount = true,
54 : .write_to_file = true,
55 :
56 : .shared_size = sizeof(PgStat_StatInjFixedEntry),
57 : .shared_data_off = offsetof(PgStatShared_InjectionPointFixed, stats),
58 : .shared_data_len = sizeof(((PgStatShared_InjectionPointFixed *) 0)->stats),
59 :
60 : .init_shmem_cb = injection_stats_fixed_init_shmem_cb,
61 : .reset_all_cb = injection_stats_fixed_reset_all_cb,
62 : .snapshot_cb = injection_stats_fixed_snapshot_cb,
63 : };
64 :
65 : /*
66 : * Kind ID reserved for statistics of injection points.
67 : */
68 : #define PGSTAT_KIND_INJECTION_FIXED 26
69 :
70 : /* Track if fixed-numbered stats are loaded */
71 : static bool inj_fixed_loaded = false;
72 :
73 : static void
74 10 : injection_stats_fixed_init_shmem_cb(void *stats)
75 : {
76 10 : PgStatShared_InjectionPointFixed *stats_shmem =
77 : (PgStatShared_InjectionPointFixed *) stats;
78 :
79 10 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
80 10 : }
81 :
82 : static void
83 2 : injection_stats_fixed_reset_all_cb(TimestampTz ts)
84 : {
85 : PgStatShared_InjectionPointFixed *stats_shmem =
86 2 : pgstat_get_custom_shmem_data(PGSTAT_KIND_INJECTION_FIXED);
87 :
88 2 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
89 2 : pgstat_copy_changecounted_stats(&stats_shmem->reset_offset,
90 2 : &stats_shmem->stats,
91 : sizeof(stats_shmem->stats),
92 : &stats_shmem->changecount);
93 2 : stats_shmem->stats.stat_reset_timestamp = ts;
94 2 : LWLockRelease(&stats_shmem->lock);
95 2 : }
96 :
97 : static void
98 12 : injection_stats_fixed_snapshot_cb(void)
99 : {
100 : PgStatShared_InjectionPointFixed *stats_shmem =
101 12 : pgstat_get_custom_shmem_data(PGSTAT_KIND_INJECTION_FIXED);
102 : PgStat_StatInjFixedEntry *stat_snap =
103 12 : pgstat_get_custom_snapshot_data(PGSTAT_KIND_INJECTION_FIXED);
104 12 : PgStat_StatInjFixedEntry *reset_offset = &stats_shmem->reset_offset;
105 : PgStat_StatInjFixedEntry reset;
106 :
107 12 : pgstat_copy_changecounted_stats(stat_snap,
108 12 : &stats_shmem->stats,
109 : sizeof(stats_shmem->stats),
110 : &stats_shmem->changecount);
111 :
112 12 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
113 12 : memcpy(&reset, reset_offset, sizeof(stats_shmem->stats));
114 12 : LWLockRelease(&stats_shmem->lock);
115 :
116 : /* compensate by reset offsets */
117 : #define FIXED_COMP(fld) stat_snap->fld -= reset.fld;
118 12 : FIXED_COMP(numattach);
119 12 : FIXED_COMP(numdetach);
120 12 : FIXED_COMP(numrun);
121 12 : FIXED_COMP(numcached);
122 12 : FIXED_COMP(numloaded);
123 : #undef FIXED_COMP
124 12 : }
125 :
126 : /*
127 : * Workhorse to do the registration work, called in _PG_init().
128 : */
129 : void
130 10 : pgstat_register_inj_fixed(void)
131 : {
132 10 : pgstat_register_kind(PGSTAT_KIND_INJECTION_FIXED, &injection_stats_fixed);
133 :
134 : /* mark stats as loaded */
135 10 : inj_fixed_loaded = true;
136 10 : }
137 :
138 : /*
139 : * Report fixed number of statistics for an injection point.
140 : */
141 : void
142 284 : pgstat_report_inj_fixed(uint32 numattach,
143 : uint32 numdetach,
144 : uint32 numrun,
145 : uint32 numcached,
146 : uint32 numloaded)
147 : {
148 : PgStatShared_InjectionPointFixed *stats_shmem;
149 :
150 : /* leave if disabled */
151 284 : if (!inj_fixed_loaded || !inj_stats_enabled)
152 268 : return;
153 :
154 16 : stats_shmem = pgstat_get_custom_shmem_data(PGSTAT_KIND_INJECTION_FIXED);
155 :
156 16 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
157 :
158 16 : pgstat_begin_changecount_write(&stats_shmem->changecount);
159 16 : stats_shmem->stats.numattach += numattach;
160 16 : stats_shmem->stats.numdetach += numdetach;
161 16 : stats_shmem->stats.numrun += numrun;
162 16 : stats_shmem->stats.numcached += numcached;
163 16 : stats_shmem->stats.numloaded += numloaded;
164 16 : pgstat_end_changecount_write(&stats_shmem->changecount);
165 :
166 16 : LWLockRelease(&stats_shmem->lock);
167 : }
168 :
169 : /*
170 : * SQL function returning fixed-numbered statistics for injection points.
171 : */
172 70 : PG_FUNCTION_INFO_V1(injection_points_stats_fixed);
173 : Datum
174 6 : injection_points_stats_fixed(PG_FUNCTION_ARGS)
175 : {
176 : TupleDesc tupdesc;
177 6 : Datum values[5] = {0};
178 6 : bool nulls[5] = {0};
179 : PgStat_StatInjFixedEntry *stats;
180 :
181 6 : if (!inj_fixed_loaded || !inj_stats_enabled)
182 0 : PG_RETURN_NULL();
183 :
184 6 : pgstat_snapshot_fixed(PGSTAT_KIND_INJECTION_FIXED);
185 6 : stats = pgstat_get_custom_snapshot_data(PGSTAT_KIND_INJECTION_FIXED);
186 :
187 : /* Initialise attributes information in the tuple descriptor */
188 6 : tupdesc = CreateTemplateTupleDesc(5);
189 6 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "numattach",
190 : INT8OID, -1, 0);
191 6 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "numdetach",
192 : INT8OID, -1, 0);
193 6 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "numrun",
194 : INT8OID, -1, 0);
195 6 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "numcached",
196 : INT8OID, -1, 0);
197 6 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "numloaded",
198 : INT8OID, -1, 0);
199 6 : BlessTupleDesc(tupdesc);
200 :
201 6 : values[0] = Int64GetDatum(stats->numattach);
202 6 : values[1] = Int64GetDatum(stats->numdetach);
203 6 : values[2] = Int64GetDatum(stats->numrun);
204 6 : values[3] = Int64GetDatum(stats->numcached);
205 6 : values[4] = Int64GetDatum(stats->numloaded);
206 6 : nulls[0] = false;
207 6 : nulls[1] = false;
208 6 : nulls[2] = false;
209 6 : nulls[3] = false;
210 6 : nulls[4] = false;
211 :
212 : /* Returns the record as Datum */
213 6 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
214 : }
|