Line data Source code
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 4 : pgstat_reset_slru(const char *name)
46 : {
47 4 : TimestampTz ts = GetCurrentTimestamp();
48 :
49 : Assert(name != NULL);
50 :
51 4 : pgstat_reset_slru_counter_internal(pgstat_get_slru_index(name), ts);
52 4 : }
53 :
54 : /*
55 : * SLRU statistics count accumulation functions --- called from slru.c
56 : */
57 :
58 : #define PGSTAT_COUNT_SLRU(stat) \
59 : void \
60 : CppConcat(pgstat_count_slru_,stat)(int slru_idx) \
61 : { \
62 : get_slru_entry(slru_idx)->stat += 1; \
63 : }
64 :
65 : /* pgstat_count_slru_blocks_zeroed */
66 7346006 : PGSTAT_COUNT_SLRU(blocks_zeroed)
67 :
68 : /* pgstat_count_slru_blocks_hit */
69 1277121 : PGSTAT_COUNT_SLRU(blocks_hit)
70 :
71 : /* pgstat_count_slru_blocks_exists */
72 66 : PGSTAT_COUNT_SLRU(blocks_exists)
73 :
74 : /* pgstat_count_slru_blocks_read */
75 17625 : PGSTAT_COUNT_SLRU(blocks_read)
76 :
77 : /* pgstat_count_slru_blocks_written */
78 7346767 : PGSTAT_COUNT_SLRU(blocks_written)
79 :
80 : /* pgstat_count_slru_flush */
81 9697 : PGSTAT_COUNT_SLRU(flush)
82 :
83 : /* pgstat_count_slru_truncate */
84 2007 : 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 71 : pgstat_fetch_slru(void)
92 : {
93 71 : pgstat_snapshot_fixed(PGSTAT_KIND_SLRU);
94 :
95 71 : return pgStatLocal.snapshot.slru;
96 : }
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 639 : pgstat_get_slru_name(int slru_idx)
105 : {
106 639 : if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS)
107 71 : return NULL;
108 :
109 568 : return slru_names[slru_idx];
110 : }
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 8625 : pgstat_get_slru_index(const char *name)
119 : {
120 : int i;
121 :
122 : Assert(name);
123 34508 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
124 : {
125 34504 : if (strcmp(slru_names[i], name) == 0)
126 8621 : return i;
127 : }
128 :
129 : /* return index of the last entry (which is the "other" one) */
130 4 : return (SLRU_NUM_ELEMENTS - 1);
131 : }
132 :
133 : /*
134 : * Flush out locally pending SLRU stats entries
135 : *
136 : * If nowait is true, this function returns false on lock failure. Otherwise
137 : * this function always returns true.
138 : *
139 : * If nowait is true, this function returns true if the lock could not be
140 : * acquired. Otherwise return false.
141 : */
142 : bool
143 39332 : pgstat_slru_flush_cb(bool nowait)
144 : {
145 39332 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
146 : int i;
147 :
148 39332 : if (!have_slrustats)
149 24527 : return false;
150 :
151 14805 : if (!nowait)
152 11763 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
153 3042 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
154 0 : return true;
155 :
156 133245 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
157 : {
158 118440 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i];
159 118440 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i];
160 :
161 : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld
162 118440 : SLRU_ACC(blocks_zeroed);
163 118440 : SLRU_ACC(blocks_hit);
164 118440 : SLRU_ACC(blocks_read);
165 118440 : SLRU_ACC(blocks_written);
166 118440 : SLRU_ACC(blocks_exists);
167 118440 : SLRU_ACC(flush);
168 118440 : SLRU_ACC(truncate);
169 : #undef SLRU_ACC
170 : }
171 :
172 : /* done, clear the pending entry */
173 962325 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats));
174 :
175 14805 : LWLockRelease(&stats_shmem->lock);
176 :
177 14805 : have_slrustats = false;
178 :
179 14805 : return false;
180 : }
181 :
182 : void
183 1231 : pgstat_slru_init_shmem_cb(void *stats)
184 : {
185 1231 : PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats;
186 :
187 1231 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
188 1231 : }
189 :
190 : void
191 254 : pgstat_slru_reset_all_cb(TimestampTz ts)
192 : {
193 2286 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++)
194 2032 : pgstat_reset_slru_counter_internal(i, ts);
195 254 : }
196 :
197 : void
198 844 : pgstat_slru_snapshot_cb(void)
199 : {
200 844 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
201 :
202 844 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
203 :
204 844 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats,
205 : sizeof(stats_shmem->stats));
206 :
207 844 : LWLockRelease(&stats_shmem->lock);
208 844 : }
209 :
210 : /*
211 : * Returns pointer to entry with counters for given SLRU (based on the name
212 : * stored in SlruCtl as lwlock tranche name).
213 : */
214 : static inline PgStat_SLRUStats *
215 15999289 : get_slru_entry(int slru_idx)
216 : {
217 : pgstat_assert_is_up();
218 :
219 : /*
220 : * The postmaster should never register any SLRU statistics counts; if it
221 : * did, the counts would be duplicated into child processes via fork().
222 : */
223 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
224 :
225 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS));
226 :
227 15999289 : have_slrustats = true;
228 15999289 : pgstat_report_fixed = true;
229 :
230 15999289 : return &pending_SLRUStats[slru_idx];
231 : }
232 :
233 : static void
234 2036 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts)
235 : {
236 2036 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
237 :
238 2036 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
239 :
240 2036 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats));
241 2036 : stats_shmem->stats[index].stat_reset_timestamp = ts;
242 :
243 2036 : LWLockRelease(&stats_shmem->lock);
244 2036 : }
|