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