Age Owner 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-2023, 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 : 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
368 andres 45 CBC 3 : pgstat_reset_slru(const char *name)
46 : {
47 3 : TimestampTz ts = GetCurrentTimestamp();
48 :
163 peter 49 GNC 3 : Assert(name != NULL);
50 :
368 andres 51 CBC 3 : pgstat_reset_slru_counter_internal(pgstat_get_slru_index(name), ts);
384 52 3 : }
53 :
54 : /*
55 : * SLRU statistics count accumulation functions --- called from slru.c
56 : */
57 :
58 : void
59 3160 : pgstat_count_slru_page_zeroed(int slru_idx)
60 : {
368 61 3160 : get_slru_entry(slru_idx)->blocks_zeroed += 1;
384 62 3160 : }
63 :
64 : void
65 2129208 : pgstat_count_slru_page_hit(int slru_idx)
66 : {
368 67 2129208 : get_slru_entry(slru_idx)->blocks_hit += 1;
384 68 2129208 : }
69 :
70 : void
71 38 : pgstat_count_slru_page_exists(int slru_idx)
72 : {
368 73 38 : get_slru_entry(slru_idx)->blocks_exists += 1;
384 74 38 : }
75 :
76 : void
77 1715 : pgstat_count_slru_page_read(int slru_idx)
78 : {
368 79 1715 : get_slru_entry(slru_idx)->blocks_read += 1;
384 80 1715 : }
81 :
82 : void
83 4983 : pgstat_count_slru_page_written(int slru_idx)
84 : {
368 85 4983 : get_slru_entry(slru_idx)->blocks_written += 1;
384 86 4983 : }
87 :
88 : void
89 11830 : pgstat_count_slru_flush(int slru_idx)
90 : {
368 91 11830 : get_slru_entry(slru_idx)->flush += 1;
384 92 11830 : }
93 :
94 : void
95 2337 : pgstat_count_slru_truncate(int slru_idx)
96 : {
368 97 2337 : get_slru_entry(slru_idx)->truncate += 1;
98 2337 : }
99 :
100 : /*
101 : * Support function for the SQL-callable pgstat* functions. Returns
102 : * a pointer to the slru statistics struct.
103 : */
104 : PgStat_SLRUStats *
105 56 : pgstat_fetch_slru(void)
106 : {
107 56 : pgstat_snapshot_fixed(PGSTAT_KIND_SLRU);
108 :
109 56 : return pgStatLocal.snapshot.slru;
110 : }
111 :
112 : /*
113 : * Returns SLRU name for an index. The index may be above SLRU_NUM_ELEMENTS,
114 : * in which case this returns NULL. This allows writing code that does not
115 : * know the number of entries in advance.
116 : */
117 : const char *
118 504 : pgstat_get_slru_name(int slru_idx)
119 : {
384 120 504 : if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS)
121 56 : return NULL;
122 :
123 448 : return slru_names[slru_idx];
124 : }
125 :
126 : /*
127 : * Determine index of entry for a SLRU with a given name. If there's no exact
128 : * match, returns index of the last "other" entry used for SLRUs defined in
129 : * external projects.
130 : */
131 : int
368 132 12786 : pgstat_get_slru_index(const char *name)
133 : {
134 : int i;
135 :
384 136 51140 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
137 : {
138 51139 : if (strcmp(slru_names[i], name) == 0)
139 12785 : return i;
140 : }
141 :
142 : /* return index of the last entry (which is the "other" one) */
143 1 : return (SLRU_NUM_ELEMENTS - 1);
144 : }
145 :
146 : /*
147 : * Flush out locally pending SLRU stats entries
148 : *
149 : * If nowait is true, this function returns false on lock failure. Otherwise
150 : * this function always returns true.
151 : *
152 : * If nowait is true, this function returns true if the lock could not be
153 : * acquired. Otherwise return false.
154 : */
155 : bool
368 156 24456 : pgstat_slru_flush(bool nowait)
157 : {
158 24456 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
159 : int i;
160 :
161 24456 : if (!have_slrustats)
162 13687 : return false;
163 :
164 10769 : if (!nowait)
165 7740 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
166 3029 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
368 andres 167 UBC 0 : return true;
168 :
368 andres 169 CBC 96921 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
170 : {
171 86152 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i];
172 86152 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i];
173 :
174 : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld
175 86152 : SLRU_ACC(blocks_zeroed);
176 86152 : SLRU_ACC(blocks_hit);
177 86152 : SLRU_ACC(blocks_read);
178 86152 : SLRU_ACC(blocks_written);
179 86152 : SLRU_ACC(blocks_exists);
180 86152 : SLRU_ACC(flush);
181 86152 : SLRU_ACC(truncate);
182 : #undef SLRU_ACC
183 : }
184 :
185 : /* done, clear the pending entry */
186 699985 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats));
187 :
188 10769 : LWLockRelease(&stats_shmem->lock);
189 :
190 10769 : have_slrustats = false;
191 :
192 10769 : return false;
193 : }
194 :
195 : void
196 441 : pgstat_slru_reset_all_cb(TimestampTz ts)
197 : {
198 3969 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++)
199 3528 : pgstat_reset_slru_counter_internal(i, ts);
200 441 : }
201 :
202 : void
203 1034 : pgstat_slru_snapshot_cb(void)
204 : {
205 1034 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
206 :
207 1034 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
208 :
209 1034 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats,
210 : sizeof(stats_shmem->stats));
211 :
212 1034 : LWLockRelease(&stats_shmem->lock);
384 213 1034 : }
214 :
215 : /*
216 : * Returns pointer to entry with counters for given SLRU (based on the name
217 : * stored in SlruCtl as lwlock tranche name).
218 : */
219 : static inline PgStat_SLRUStats *
368 220 2153271 : get_slru_entry(int slru_idx)
221 : {
384 222 2153271 : pgstat_assert_is_up();
223 :
224 : /*
225 : * The postmaster should never register any SLRU statistics counts; if it
226 : * did, the counts would be duplicated into child processes via fork().
227 : */
228 2153271 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
229 :
230 2153271 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS));
231 :
368 232 2153271 : have_slrustats = true;
233 :
234 2153271 : return &pending_SLRUStats[slru_idx];
235 : }
236 :
237 : static void
238 3531 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts)
239 : {
240 3531 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
241 :
242 3531 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
243 :
244 3531 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats));
245 3531 : stats_shmem->stats[index].stat_reset_timestamp = ts;
246 :
247 3531 : LWLockRelease(&stats_shmem->lock);
384 248 3531 : }
|