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 : #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 14679210 : PGSTAT_COUNT_SLRU(blocks_zeroed) 67 : 68 : /* pgstat_count_slru_blocks_hit */ 69 1708154 : PGSTAT_COUNT_SLRU(blocks_hit) 70 : 71 : /* pgstat_count_slru_blocks_exists */ 72 214 : PGSTAT_COUNT_SLRU(blocks_exists) 73 : 74 : /* pgstat_count_slru_blocks_read */ 75 4086 : PGSTAT_COUNT_SLRU(blocks_read) 76 : 77 : /* pgstat_count_slru_blocks_written */ 78 14682176 : PGSTAT_COUNT_SLRU(blocks_written) 79 : 80 : /* pgstat_count_slru_flush */ 81 17130 : PGSTAT_COUNT_SLRU(flush) 82 : 83 : /* pgstat_count_slru_truncate */ 84 3562 : 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 124 : pgstat_fetch_slru(void) 92 : { 93 124 : pgstat_snapshot_fixed(PGSTAT_KIND_SLRU); 94 : 95 124 : 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 1116 : pgstat_get_slru_name(int slru_idx) 105 : { 106 1116 : if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS) 107 124 : return NULL; 108 : 109 992 : 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 15228 : pgstat_get_slru_index(const char *name) 119 : { 120 : int i; 121 : 122 60914 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 123 : { 124 60910 : if (strcmp(slru_names[i], name) == 0) 125 15224 : return i; 126 : } 127 : 128 : /* return index of the last entry (which is the "other" one) */ 129 4 : return (SLRU_NUM_ELEMENTS - 1); 130 : } 131 : 132 : /* 133 : * Flush out locally pending SLRU stats entries 134 : * 135 : * If nowait is true, this function returns false on lock failure. Otherwise 136 : * this function always returns true. 137 : * 138 : * If nowait is true, this function returns true if the lock could not be 139 : * acquired. Otherwise return false. 140 : */ 141 : bool 142 69088 : pgstat_slru_flush_cb(bool nowait) 143 : { 144 69088 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 145 : int i; 146 : 147 69088 : if (!have_slrustats) 148 44466 : return false; 149 : 150 24622 : if (!nowait) 151 20512 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 152 4110 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 153 0 : return true; 154 : 155 221598 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 156 : { 157 196976 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i]; 158 196976 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i]; 159 : 160 : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld 161 196976 : SLRU_ACC(blocks_zeroed); 162 196976 : SLRU_ACC(blocks_hit); 163 196976 : SLRU_ACC(blocks_read); 164 196976 : SLRU_ACC(blocks_written); 165 196976 : SLRU_ACC(blocks_exists); 166 196976 : SLRU_ACC(flush); 167 196976 : SLRU_ACC(truncate); 168 : #undef SLRU_ACC 169 : } 170 : 171 : /* done, clear the pending entry */ 172 1600430 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats)); 173 : 174 24622 : LWLockRelease(&stats_shmem->lock); 175 : 176 24622 : have_slrustats = false; 177 : 178 24622 : return false; 179 : } 180 : 181 : void 182 2174 : pgstat_slru_init_shmem_cb(void *stats) 183 : { 184 2174 : PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats; 185 : 186 2174 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 187 2174 : } 188 : 189 : void 190 470 : pgstat_slru_reset_all_cb(TimestampTz ts) 191 : { 192 4230 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++) 193 3760 : pgstat_reset_slru_counter_internal(i, ts); 194 470 : } 195 : 196 : void 197 1438 : pgstat_slru_snapshot_cb(void) 198 : { 199 1438 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 200 : 201 1438 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 202 : 203 1438 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats, 204 : sizeof(stats_shmem->stats)); 205 : 206 1438 : LWLockRelease(&stats_shmem->lock); 207 1438 : } 208 : 209 : /* 210 : * Returns pointer to entry with counters for given SLRU (based on the name 211 : * stored in SlruCtl as lwlock tranche name). 212 : */ 213 : static inline PgStat_SLRUStats * 214 31094532 : get_slru_entry(int slru_idx) 215 : { 216 : pgstat_assert_is_up(); 217 : 218 : /* 219 : * The postmaster should never register any SLRU statistics counts; if it 220 : * did, the counts would be duplicated into child processes via fork(). 221 : */ 222 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 223 : 224 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); 225 : 226 31094532 : have_slrustats = true; 227 31094532 : pgstat_report_fixed = true; 228 : 229 31094532 : return &pending_SLRUStats[slru_idx]; 230 : } 231 : 232 : static void 233 3766 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts) 234 : { 235 3766 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 236 : 237 3766 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 238 : 239 3766 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats)); 240 3766 : stats_shmem->stats[index].stat_reset_timestamp = ts; 241 : 242 3766 : LWLockRelease(&stats_shmem->lock); 243 3766 : }