/src/postgres/src/backend/utils/activity/pgstat_slru.c
Line | Count | Source |
1 | | /* ------------------------------------------------------------------------- |
2 | | * |
3 | | * pgstat_slru.c |
4 | | * Implementation of SLRU statistics. |
5 | | * |
6 | | * This file contains the implementation of SLRU statistics. It is kept |
7 | | * separate from pgstat.c to enforce the line between the statistics access / |
8 | | * storage implementation and the details about individual types of |
9 | | * statistics. |
10 | | * |
11 | | * Copyright (c) 2001-2026, PostgreSQL Global Development Group |
12 | | * |
13 | | * IDENTIFICATION |
14 | | * src/backend/utils/activity/pgstat_slru.c |
15 | | * ------------------------------------------------------------------------- |
16 | | */ |
17 | | |
18 | | #include "postgres.h" |
19 | | |
20 | | #include "utils/pgstat_internal.h" |
21 | | #include "utils/timestamp.h" |
22 | | |
23 | | |
24 | | static inline PgStat_SLRUStats *get_slru_entry(int slru_idx); |
25 | | static void pgstat_reset_slru_counter_internal(int index, TimestampTz ts); |
26 | | |
27 | | |
28 | | /* |
29 | | * SLRU statistics counts waiting to be flushed out. We assume this variable |
30 | | * inits to zeroes. Entries are one-to-one with slru_names[]. Changes of |
31 | | * SLRU counters are reported within critical sections so we use static memory |
32 | | * in order to avoid memory allocation. |
33 | | */ |
34 | | static PgStat_SLRUStats pending_SLRUStats[SLRU_NUM_ELEMENTS]; |
35 | | static bool have_slrustats = false; |
36 | | |
37 | | |
38 | | /* |
39 | | * Reset counters for a single SLRU. |
40 | | * |
41 | | * Permission checking for this function is managed through the normal |
42 | | * GRANT system. |
43 | | */ |
44 | | void |
45 | | pgstat_reset_slru(const char *name) |
46 | 0 | { |
47 | 0 | TimestampTz ts = GetCurrentTimestamp(); |
48 | |
|
49 | 0 | Assert(name != NULL); |
50 | |
|
51 | 0 | pgstat_reset_slru_counter_internal(pgstat_get_slru_index(name), ts); |
52 | 0 | } |
53 | | |
54 | | /* |
55 | | * SLRU statistics count accumulation functions --- called from slru.c |
56 | | */ |
57 | | |
58 | | #define PGSTAT_COUNT_SLRU(stat) \ |
59 | | void \ |
60 | 0 | CppConcat(pgstat_count_slru_,stat)(int slru_idx) \ |
61 | 0 | { \ |
62 | 0 | get_slru_entry(slru_idx)->stat += 1; \ |
63 | 0 | } Unexecuted instantiation: pgstat_count_slru_blocks_zeroed Unexecuted instantiation: pgstat_count_slru_blocks_hit Unexecuted instantiation: pgstat_count_slru_blocks_exists Unexecuted instantiation: pgstat_count_slru_blocks_read Unexecuted instantiation: pgstat_count_slru_blocks_written Unexecuted instantiation: pgstat_count_slru_flush Unexecuted instantiation: pgstat_count_slru_truncate |
64 | | |
65 | | /* pgstat_count_slru_blocks_zeroed */ |
66 | | PGSTAT_COUNT_SLRU(blocks_zeroed) |
67 | | |
68 | | /* pgstat_count_slru_blocks_hit */ |
69 | | PGSTAT_COUNT_SLRU(blocks_hit) |
70 | | |
71 | | /* pgstat_count_slru_blocks_exists */ |
72 | | PGSTAT_COUNT_SLRU(blocks_exists) |
73 | | |
74 | | /* pgstat_count_slru_blocks_read */ |
75 | | PGSTAT_COUNT_SLRU(blocks_read) |
76 | | |
77 | | /* pgstat_count_slru_blocks_written */ |
78 | | PGSTAT_COUNT_SLRU(blocks_written) |
79 | | |
80 | | /* pgstat_count_slru_flush */ |
81 | | PGSTAT_COUNT_SLRU(flush) |
82 | | |
83 | | /* pgstat_count_slru_truncate */ |
84 | | PGSTAT_COUNT_SLRU(truncate) |
85 | | |
86 | | /* |
87 | | * Support function for the SQL-callable pgstat* functions. Returns |
88 | | * a pointer to the slru statistics struct. |
89 | | */ |
90 | | PgStat_SLRUStats * |
91 | | pgstat_fetch_slru(void) |
92 | 0 | { |
93 | 0 | pgstat_snapshot_fixed(PGSTAT_KIND_SLRU); |
94 | |
|
95 | 0 | return pgStatLocal.snapshot.slru; |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * Returns SLRU name for an index. The index may be above SLRU_NUM_ELEMENTS, |
100 | | * in which case this returns NULL. This allows writing code that does not |
101 | | * know the number of entries in advance. |
102 | | */ |
103 | | const char * |
104 | | pgstat_get_slru_name(int slru_idx) |
105 | 0 | { |
106 | 0 | if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS) |
107 | 0 | return NULL; |
108 | | |
109 | 0 | return slru_names[slru_idx]; |
110 | 0 | } |
111 | | |
112 | | /* |
113 | | * Determine index of entry for a SLRU with a given name. If there's no exact |
114 | | * match, returns index of the last "other" entry used for SLRUs defined in |
115 | | * external projects. |
116 | | */ |
117 | | int |
118 | | pgstat_get_slru_index(const char *name) |
119 | 0 | { |
120 | 0 | int i; |
121 | |
|
122 | 0 | Assert(name); |
123 | 0 | for (i = 0; i < SLRU_NUM_ELEMENTS; i++) |
124 | 0 | { |
125 | 0 | if (strcmp(slru_names[i], name) == 0) |
126 | 0 | return i; |
127 | 0 | } |
128 | | |
129 | | /* return index of the last entry (which is the "other" one) */ |
130 | 0 | return (SLRU_NUM_ELEMENTS - 1); |
131 | 0 | } |
132 | | |
133 | | /* |
134 | | * Flush out locally pending SLRU stats entries |
135 | | * |
136 | | * If nowait is true, this function returns true if the lock could not be |
137 | | * acquired. Otherwise return false. |
138 | | */ |
139 | | bool |
140 | | pgstat_slru_flush_cb(bool nowait) |
141 | 0 | { |
142 | 0 | PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; |
143 | 0 | int i; |
144 | |
|
145 | 0 | if (!have_slrustats) |
146 | 0 | return false; |
147 | | |
148 | 0 | if (!nowait) |
149 | 0 | LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); |
150 | 0 | else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) |
151 | 0 | return true; |
152 | | |
153 | 0 | for (i = 0; i < SLRU_NUM_ELEMENTS; i++) |
154 | 0 | { |
155 | 0 | PgStat_SLRUStats *sharedent = &stats_shmem->stats[i]; |
156 | 0 | PgStat_SLRUStats *pendingent = &pending_SLRUStats[i]; |
157 | |
|
158 | 0 | #define SLRU_ACC(fld) sharedent->fld += pendingent->fld |
159 | 0 | SLRU_ACC(blocks_zeroed); |
160 | 0 | SLRU_ACC(blocks_hit); |
161 | 0 | SLRU_ACC(blocks_read); |
162 | 0 | SLRU_ACC(blocks_written); |
163 | 0 | SLRU_ACC(blocks_exists); |
164 | 0 | SLRU_ACC(flush); |
165 | 0 | SLRU_ACC(truncate); |
166 | 0 | #undef SLRU_ACC |
167 | 0 | } |
168 | | |
169 | | /* done, clear the pending entry */ |
170 | 0 | MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats)); |
171 | |
|
172 | 0 | LWLockRelease(&stats_shmem->lock); |
173 | |
|
174 | 0 | have_slrustats = false; |
175 | |
|
176 | 0 | return false; |
177 | 0 | } |
178 | | |
179 | | void |
180 | | pgstat_slru_init_shmem_cb(void *stats) |
181 | 0 | { |
182 | 0 | PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats; |
183 | |
|
184 | 0 | LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); |
185 | 0 | } |
186 | | |
187 | | void |
188 | | pgstat_slru_reset_all_cb(TimestampTz ts) |
189 | 0 | { |
190 | 0 | for (int i = 0; i < SLRU_NUM_ELEMENTS; i++) |
191 | 0 | pgstat_reset_slru_counter_internal(i, ts); |
192 | 0 | } |
193 | | |
194 | | void |
195 | | pgstat_slru_snapshot_cb(void) |
196 | 0 | { |
197 | 0 | PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; |
198 | |
|
199 | 0 | LWLockAcquire(&stats_shmem->lock, LW_SHARED); |
200 | |
|
201 | 0 | memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats, |
202 | 0 | sizeof(stats_shmem->stats)); |
203 | |
|
204 | 0 | LWLockRelease(&stats_shmem->lock); |
205 | 0 | } |
206 | | |
207 | | /* |
208 | | * Returns pointer to entry with counters for given SLRU (based on the name |
209 | | * stored in SlruCtl as lwlock tranche name). |
210 | | */ |
211 | | static inline PgStat_SLRUStats * |
212 | | get_slru_entry(int slru_idx) |
213 | 0 | { |
214 | 0 | pgstat_assert_is_up(); |
215 | | |
216 | | /* |
217 | | * The postmaster should never register any SLRU statistics counts; if it |
218 | | * did, the counts would be duplicated into child processes via fork(). |
219 | | */ |
220 | 0 | Assert(IsUnderPostmaster || !IsPostmasterEnvironment); |
221 | |
|
222 | 0 | Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); |
223 | |
|
224 | 0 | have_slrustats = true; |
225 | 0 | pgstat_report_fixed = true; |
226 | |
|
227 | 0 | return &pending_SLRUStats[slru_idx]; |
228 | 0 | } |
229 | | |
230 | | static void |
231 | | pgstat_reset_slru_counter_internal(int index, TimestampTz ts) |
232 | 0 | { |
233 | 0 | PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; |
234 | |
|
235 | 0 | LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); |
236 | |
|
237 | 0 | memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats)); |
238 | 0 | stats_shmem->stats[index].stat_reset_timestamp = ts; |
239 | |
|
240 | 0 | LWLockRelease(&stats_shmem->lock); |
241 | 0 | } |