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-2025, 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 6 : pgstat_reset_slru(const char *name) 46 : { 47 6 : TimestampTz ts = GetCurrentTimestamp(); 48 : 49 : Assert(name != NULL); 50 : 51 6 : pgstat_reset_slru_counter_internal(pgstat_get_slru_index(name), ts); 52 6 : } 53 : 54 : /* 55 : * SLRU statistics count accumulation functions --- called from slru.c 56 : */ 57 : 58 : void 59 14679164 : pgstat_count_slru_page_zeroed(int slru_idx) 60 : { 61 14679164 : get_slru_entry(slru_idx)->blocks_zeroed += 1; 62 14679164 : } 63 : 64 : void 65 1758922 : pgstat_count_slru_page_hit(int slru_idx) 66 : { 67 1758922 : get_slru_entry(slru_idx)->blocks_hit += 1; 68 1758922 : } 69 : 70 : void 71 212 : pgstat_count_slru_page_exists(int slru_idx) 72 : { 73 212 : get_slru_entry(slru_idx)->blocks_exists += 1; 74 212 : } 75 : 76 : void 77 3950 : pgstat_count_slru_page_read(int slru_idx) 78 : { 79 3950 : get_slru_entry(slru_idx)->blocks_read += 1; 80 3950 : } 81 : 82 : void 83 14682000 : pgstat_count_slru_page_written(int slru_idx) 84 : { 85 14682000 : get_slru_entry(slru_idx)->blocks_written += 1; 86 14682000 : } 87 : 88 : void 89 16870 : pgstat_count_slru_flush(int slru_idx) 90 : { 91 16870 : get_slru_entry(slru_idx)->flush += 1; 92 16870 : } 93 : 94 : void 95 3510 : pgstat_count_slru_truncate(int slru_idx) 96 : { 97 3510 : get_slru_entry(slru_idx)->truncate += 1; 98 3510 : } 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 124 : pgstat_fetch_slru(void) 106 : { 107 124 : pgstat_snapshot_fixed(PGSTAT_KIND_SLRU); 108 : 109 124 : 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 1116 : pgstat_get_slru_name(int slru_idx) 119 : { 120 1116 : if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS) 121 124 : return NULL; 122 : 123 992 : 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 132 14906 : pgstat_get_slru_index(const char *name) 133 : { 134 : int i; 135 : 136 59626 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 137 : { 138 59622 : if (strcmp(slru_names[i], name) == 0) 139 14902 : return i; 140 : } 141 : 142 : /* return index of the last entry (which is the "other" one) */ 143 4 : 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 156 67516 : pgstat_slru_flush_cb(bool nowait) 157 : { 158 67516 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 159 : int i; 160 : 161 67516 : if (!have_slrustats) 162 43284 : return false; 163 : 164 24232 : if (!nowait) 165 20160 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 166 4072 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 167 0 : return true; 168 : 169 218088 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 170 : { 171 193856 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i]; 172 193856 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i]; 173 : 174 : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld 175 193856 : SLRU_ACC(blocks_zeroed); 176 193856 : SLRU_ACC(blocks_hit); 177 193856 : SLRU_ACC(blocks_read); 178 193856 : SLRU_ACC(blocks_written); 179 193856 : SLRU_ACC(blocks_exists); 180 193856 : SLRU_ACC(flush); 181 193856 : SLRU_ACC(truncate); 182 : #undef SLRU_ACC 183 : } 184 : 185 : /* done, clear the pending entry */ 186 1575080 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats)); 187 : 188 24232 : LWLockRelease(&stats_shmem->lock); 189 : 190 24232 : have_slrustats = false; 191 : 192 24232 : return false; 193 : } 194 : 195 : void 196 2128 : pgstat_slru_init_shmem_cb(void *stats) 197 : { 198 2128 : PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats; 199 : 200 2128 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 201 2128 : } 202 : 203 : void 204 470 : pgstat_slru_reset_all_cb(TimestampTz ts) 205 : { 206 4230 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++) 207 3760 : pgstat_reset_slru_counter_internal(i, ts); 208 470 : } 209 : 210 : void 211 1392 : pgstat_slru_snapshot_cb(void) 212 : { 213 1392 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 214 : 215 1392 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 216 : 217 1392 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats, 218 : sizeof(stats_shmem->stats)); 219 : 220 1392 : LWLockRelease(&stats_shmem->lock); 221 1392 : } 222 : 223 : /* 224 : * Returns pointer to entry with counters for given SLRU (based on the name 225 : * stored in SlruCtl as lwlock tranche name). 226 : */ 227 : static inline PgStat_SLRUStats * 228 31144628 : get_slru_entry(int slru_idx) 229 : { 230 : pgstat_assert_is_up(); 231 : 232 : /* 233 : * The postmaster should never register any SLRU statistics counts; if it 234 : * did, the counts would be duplicated into child processes via fork(). 235 : */ 236 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 237 : 238 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); 239 : 240 31144628 : have_slrustats = true; 241 31144628 : pgstat_report_fixed = true; 242 : 243 31144628 : return &pending_SLRUStats[slru_idx]; 244 : } 245 : 246 : static void 247 3766 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts) 248 : { 249 3766 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 250 : 251 3766 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 252 : 253 3766 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats)); 254 3766 : stats_shmem->stats[index].stat_reset_timestamp = ts; 255 : 256 3766 : LWLockRelease(&stats_shmem->lock); 257 3766 : }