Age Owner Branch data TLA Line data Source code
1 : : /*--------------------------------------------------------------------------
2 : : *
3 : : * test_custom_fixed_stats.c
4 : : * Test module for fixed-sized custom pgstats
5 : : *
6 : : * Copyright (c) 2025, PostgreSQL Global Development Group
7 : : *
8 : : * IDENTIFICATION
9 : : * src/test/modules/test_custom_stats/test_custom_fixed_stats.c
10 : : *
11 : : * -------------------------------------------------------------------------
12 : : */
13 : :
14 : : #include "postgres.h"
15 : :
16 : : #include "access/htup_details.h"
17 : : #include "funcapi.h"
18 : : #include "pgstat.h"
19 : : #include "utils/builtins.h"
20 : : #include "utils/pgstat_internal.h"
21 : :
9 michael@paquier.xyz 22 :GNC 3 : PG_MODULE_MAGIC_EXT(
23 : : .name = "test_custom_fixed_stats",
24 : : .version = PG_VERSION
25 : : );
26 : :
27 : : /* Fixed-amount custom statistics entry */
28 : : typedef struct PgStat_StatCustomFixedEntry
29 : : {
30 : : PgStat_Counter numcalls; /* # of times update function called */
31 : : TimestampTz stat_reset_timestamp;
32 : : } PgStat_StatCustomFixedEntry;
33 : :
34 : : typedef struct PgStatShared_CustomFixedEntry
35 : : {
36 : : LWLock lock; /* protects counters */
37 : : uint32 changecount; /* for atomic reads */
38 : : PgStat_StatCustomFixedEntry stats; /* current counters */
39 : : PgStat_StatCustomFixedEntry reset_offset; /* reset baseline */
40 : : } PgStatShared_CustomFixedEntry;
41 : :
42 : : /* Callbacks for fixed-amount statistics */
43 : : static void test_custom_stats_fixed_init_shmem_cb(void *stats);
44 : : static void test_custom_stats_fixed_reset_all_cb(TimestampTz ts);
45 : : static void test_custom_stats_fixed_snapshot_cb(void);
46 : :
47 : : static const PgStat_KindInfo custom_stats = {
48 : : .name = "test_custom_fixed_stats",
49 : : .fixed_amount = true, /* exactly one entry */
50 : : .write_to_file = true, /* persist to stats file */
51 : :
52 : : .shared_size = sizeof(PgStat_StatCustomFixedEntry),
53 : : .shared_data_off = offsetof(PgStatShared_CustomFixedEntry, stats),
54 : : .shared_data_len = sizeof(((PgStatShared_CustomFixedEntry *) 0)->stats),
55 : :
56 : : .init_shmem_cb = test_custom_stats_fixed_init_shmem_cb,
57 : : .reset_all_cb = test_custom_stats_fixed_reset_all_cb,
58 : : .snapshot_cb = test_custom_stats_fixed_snapshot_cb,
59 : : };
60 : :
61 : : /*
62 : : * Kind ID for test_custom_fixed_stats.
63 : : */
64 : : #define PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS 26
65 : :
66 : : /*--------------------------------------------------------------------------
67 : : * Module initialization
68 : : *--------------------------------------------------------------------------
69 : : */
70 : :
71 : : void
72 : 3 : _PG_init(void)
73 : : {
74 : : /* Must be loaded via shared_preload_libraries */
75 [ - + ]: 3 : if (!process_shared_preload_libraries_in_progress)
9 michael@paquier.xyz 76 :UNC 0 : return;
77 : :
78 : : /* Register custom statistics kind */
9 michael@paquier.xyz 79 :GNC 3 : pgstat_register_kind(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS, &custom_stats);
80 : : }
81 : :
82 : : /*
83 : : * test_custom_stats_fixed_init_shmem_cb
84 : : * Initialize shared memory structure
85 : : */
86 : : static void
87 : 3 : test_custom_stats_fixed_init_shmem_cb(void *stats)
88 : : {
89 : 3 : PgStatShared_CustomFixedEntry *stats_shmem =
90 : : (PgStatShared_CustomFixedEntry *) stats;
91 : :
92 : 3 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
93 : 3 : }
94 : :
95 : : /*
96 : : * test_custom_stats_fixed_reset_all_cb
97 : : * Reset the fixed-sized stats
98 : : */
99 : : static void
100 : 1 : test_custom_stats_fixed_reset_all_cb(TimestampTz ts)
101 : : {
102 : : PgStatShared_CustomFixedEntry *stats_shmem =
103 : 1 : pgstat_get_custom_shmem_data(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
104 : :
105 : : /* see explanation above PgStatShared_Archiver for the reset protocol */
106 : 1 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
107 : 1 : pgstat_copy_changecounted_stats(&stats_shmem->reset_offset,
108 : 1 : &stats_shmem->stats,
109 : : sizeof(stats_shmem->stats),
110 : : &stats_shmem->changecount);
111 : 1 : stats_shmem->stats.stat_reset_timestamp = ts;
112 : 1 : LWLockRelease(&stats_shmem->lock);
113 : 1 : }
114 : :
115 : : /*
116 : : * test_custom_stats_fixed_snapshot_cb
117 : : * Copy current stats to snapshot area
118 : : */
119 : : static void
120 : 4 : test_custom_stats_fixed_snapshot_cb(void)
121 : : {
122 : : PgStatShared_CustomFixedEntry *stats_shmem =
123 : 4 : pgstat_get_custom_shmem_data(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
124 : : PgStat_StatCustomFixedEntry *stat_snap =
125 : 4 : pgstat_get_custom_snapshot_data(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
126 : 4 : PgStat_StatCustomFixedEntry *reset_offset = &stats_shmem->reset_offset;
127 : : PgStat_StatCustomFixedEntry reset;
128 : :
129 : 4 : pgstat_copy_changecounted_stats(stat_snap,
130 : 4 : &stats_shmem->stats,
131 : : sizeof(stats_shmem->stats),
132 : : &stats_shmem->changecount);
133 : :
134 : 4 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
135 : 4 : memcpy(&reset, reset_offset, sizeof(stats_shmem->stats));
136 : 4 : LWLockRelease(&stats_shmem->lock);
137 : :
138 : : /* Apply reset offsets */
139 : : #define FIXED_COMP(fld) stat_snap->fld -= reset.fld;
140 : 4 : FIXED_COMP(numcalls);
141 : : #undef FIXED_COMP
142 : 4 : }
143 : :
144 : : /*--------------------------------------------------------------------------
145 : : * SQL-callable functions
146 : : *--------------------------------------------------------------------------
147 : : */
148 : :
149 : : /*
150 : : * test_custom_stats_fixed_update
151 : : * Increment call counter
152 : : */
153 : 7 : PG_FUNCTION_INFO_V1(test_custom_stats_fixed_update);
154 : : Datum
155 : 6 : test_custom_stats_fixed_update(PG_FUNCTION_ARGS)
156 : : {
157 : : PgStatShared_CustomFixedEntry *stats_shmem;
158 : :
159 : 6 : stats_shmem = pgstat_get_custom_shmem_data(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
160 : :
161 : 6 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
162 : :
163 : 6 : pgstat_begin_changecount_write(&stats_shmem->changecount);
164 : 6 : stats_shmem->stats.numcalls++;
165 : 6 : pgstat_end_changecount_write(&stats_shmem->changecount);
166 : :
167 : 6 : LWLockRelease(&stats_shmem->lock);
168 : :
169 : 6 : PG_RETURN_VOID();
170 : : }
171 : :
172 : : /*
173 : : * test_custom_stats_fixed_reset
174 : : * Reset statistics by calling pgstat system
175 : : */
176 : 1 : PG_FUNCTION_INFO_V1(test_custom_stats_fixed_reset);
177 : : Datum
9 michael@paquier.xyz 178 :UNC 0 : test_custom_stats_fixed_reset(PG_FUNCTION_ARGS)
179 : : {
180 : 0 : pgstat_reset_of_kind(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
181 : :
182 : 0 : PG_RETURN_VOID();
183 : : }
184 : :
185 : : /*
186 : : * test_custom_stats_fixed_report
187 : : * Return current counter values
188 : : */
9 michael@paquier.xyz 189 :GNC 4 : PG_FUNCTION_INFO_V1(test_custom_stats_fixed_report);
190 : : Datum
191 : 3 : test_custom_stats_fixed_report(PG_FUNCTION_ARGS)
192 : : {
193 : : TupleDesc tupdesc;
194 : 3 : Datum values[2] = {0};
195 : 3 : bool nulls[2] = {false};
196 : : PgStat_StatCustomFixedEntry *stats;
197 : :
198 : : /* Take snapshot (applies reset offsets) */
199 : 3 : pgstat_snapshot_fixed(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
200 : 3 : stats = pgstat_get_custom_snapshot_data(PGSTAT_KIND_TEST_CUSTOM_FIXED_STATS);
201 : :
202 : : /* Build return tuple */
203 : 3 : tupdesc = CreateTemplateTupleDesc(2);
204 : 3 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "numcalls",
205 : : INT8OID, -1, 0);
206 : 3 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "stats_reset",
207 : : TIMESTAMPTZOID, -1, 0);
208 : 3 : BlessTupleDesc(tupdesc);
209 : :
210 : 3 : values[0] = Int64GetDatum(stats->numcalls);
211 : :
212 : : /* Handle uninitialized timestamp (no reset yet) */
213 [ + + ]: 3 : if (stats->stat_reset_timestamp == 0)
214 : : {
215 : 1 : nulls[1] = true;
216 : : }
217 : : else
218 : : {
219 : 2 : values[1] = TimestampTzGetDatum(stats->stat_reset_timestamp);
220 : : }
221 : :
222 : : /* Return as tuple */
223 : 3 : PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
224 : : }
|