Age Owner Branch data TLA 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
1490 andres@anarazel.de 45 :CBC 4 : pgstat_reset_slru(const char *name)
46 : : {
47 : 4 : TimestampTz ts = GetCurrentTimestamp();
48 : :
1285 peter@eisentraut.org 49 [ - + ]: 4 : Assert(name != NULL);
50 : :
1490 andres@anarazel.de 51 : 4 : pgstat_reset_slru_counter_internal(pgstat_get_slru_index(name), ts);
1506 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; \
1506 andres@anarazel.de 63 :ECB (1433) : }
64 : :
65 : : /* pgstat_count_slru_blocks_zeroed */
245 michael@paquier.xyz 66 :GNC 2688 : PGSTAT_COUNT_SLRU(blocks_zeroed)
67 : :
68 : : /* pgstat_count_slru_blocks_hit */
69 : 1300526 : PGSTAT_COUNT_SLRU(blocks_hit)
70 : :
71 : : /* pgstat_count_slru_blocks_exists */
72 : 65 : PGSTAT_COUNT_SLRU(blocks_exists)
73 : :
74 : : /* pgstat_count_slru_blocks_read */
75 : 17369 : PGSTAT_COUNT_SLRU(blocks_read)
76 : :
77 : : /* pgstat_count_slru_blocks_written */
78 : 3369 : PGSTAT_COUNT_SLRU(blocks_written)
79 : :
80 : : /* pgstat_count_slru_flush */
81 : 9762 : PGSTAT_COUNT_SLRU(flush)
82 : :
83 : : /* pgstat_count_slru_truncate */
84 : 1917 : 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 *
1490 andres@anarazel.de 91 :CBC 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 : : {
1506 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
1490 118 : 8695 : pgstat_get_slru_index(const char *name)
119 : : {
120 : : int i;
121 : :
29 heikki.linnakangas@i 122 [ - + ]:GNC 8695 : Assert(name);
1506 andres@anarazel.de 123 [ + + ]:CBC 34788 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
124 : : {
125 [ + + ]: 34784 : if (strcmp(slru_names[i], name) == 0)
126 : 8691 : 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
603 michael@paquier.xyz 143 : 39145 : pgstat_slru_flush_cb(bool nowait)
144 : : {
1490 andres@anarazel.de 145 : 39145 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
146 : : int i;
147 : :
148 [ + + ]: 39145 : if (!have_slrustats)
149 : 23689 : return false;
150 : :
151 [ + + ]: 15456 : if (!nowait)
152 : 11637 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
153 [ - + ]: 3819 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
1490 andres@anarazel.de 154 :UBC 0 : return true;
155 : :
1490 andres@anarazel.de 156 [ + + ]:CBC 139104 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
157 : : {
158 : 123648 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i];
159 : 123648 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i];
160 : :
161 : : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld
162 : 123648 : SLRU_ACC(blocks_zeroed);
163 : 123648 : SLRU_ACC(blocks_hit);
164 : 123648 : SLRU_ACC(blocks_read);
165 : 123648 : SLRU_ACC(blocks_written);
166 : 123648 : SLRU_ACC(blocks_exists);
167 : 123648 : SLRU_ACC(flush);
168 : 123648 : SLRU_ACC(truncate);
169 : : #undef SLRU_ACC
170 : : }
171 : :
172 : : /* done, clear the pending entry */
173 [ + - + - : 1004640 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats));
+ - + - +
+ ]
174 : :
175 : 15456 : LWLockRelease(&stats_shmem->lock);
176 : :
177 : 15456 : have_slrustats = false;
178 : :
179 : 15456 : return false;
180 : : }
181 : :
182 : : void
663 michael@paquier.xyz 183 : 1241 : pgstat_slru_init_shmem_cb(void *stats)
184 : : {
185 : 1241 : PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats;
186 : :
187 : 1241 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
188 : 1241 : }
189 : :
190 : : void
1490 andres@anarazel.de 191 : 258 : pgstat_slru_reset_all_cb(TimestampTz ts)
192 : : {
193 [ + + ]: 2322 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++)
194 : 2064 : pgstat_reset_slru_counter_internal(i, ts);
195 : 258 : }
196 : :
197 : : void
198 : 853 : pgstat_slru_snapshot_cb(void)
199 : : {
200 : 853 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
201 : :
202 : 853 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
203 : :
204 : 853 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats,
205 : : sizeof(stats_shmem->stats));
206 : :
207 : 853 : LWLockRelease(&stats_shmem->lock);
1506 208 : 853 : }
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 *
1490 215 : 1335696 : get_slru_entry(int slru_idx)
216 : : {
1506 217 : 1335696 : 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 [ + + - + ]: 1335696 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
224 : :
225 [ + - - + ]: 1335696 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS));
226 : :
1490 227 : 1335696 : have_slrustats = true;
281 michael@paquier.xyz 228 : 1335696 : pgstat_report_fixed = true;
229 : :
1490 andres@anarazel.de 230 : 1335696 : return &pending_SLRUStats[slru_idx];
231 : : }
232 : :
233 : : static void
234 : 2068 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts)
235 : : {
236 : 2068 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
237 : :
238 : 2068 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
239 : :
240 : 2068 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats));
241 : 2068 : stats_shmem->stats[index].stat_reset_timestamp = ts;
242 : :
243 : 2068 : LWLockRelease(&stats_shmem->lock);
1506 244 : 2068 : }
|