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-2024, 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 14678774 : pgstat_count_slru_page_zeroed(int slru_idx) 60 : { 61 14678774 : get_slru_entry(slru_idx)->blocks_zeroed += 1; 62 14678774 : } 63 : 64 : void 65 1606586 : pgstat_count_slru_page_hit(int slru_idx) 66 : { 67 1606586 : get_slru_entry(slru_idx)->blocks_hit += 1; 68 1606586 : } 69 : 70 : void 71 154 : pgstat_count_slru_page_exists(int slru_idx) 72 : { 73 154 : get_slru_entry(slru_idx)->blocks_exists += 1; 74 154 : } 75 : 76 : void 77 3432 : pgstat_count_slru_page_read(int slru_idx) 78 : { 79 3432 : get_slru_entry(slru_idx)->blocks_read += 1; 80 3432 : } 81 : 82 : void 83 14681186 : pgstat_count_slru_page_written(int slru_idx) 84 : { 85 14681186 : get_slru_entry(slru_idx)->blocks_written += 1; 86 14681186 : } 87 : 88 : void 89 11926 : pgstat_count_slru_flush(int slru_idx) 90 : { 91 11926 : get_slru_entry(slru_idx)->flush += 1; 92 11926 : } 93 : 94 : void 95 2494 : pgstat_count_slru_truncate(int slru_idx) 96 : { 97 2494 : get_slru_entry(slru_idx)->truncate += 1; 98 2494 : } 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 12804 : pgstat_get_slru_index(const char *name) 133 : { 134 : int i; 135 : 136 51208 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 137 : { 138 51206 : if (strcmp(slru_names[i], name) == 0) 139 12802 : return i; 140 : } 141 : 142 : /* return index of the last entry (which is the "other" one) */ 143 2 : return (SLRU_NUM_ELEMENTS - 1); 144 : } 145 : 146 : /* 147 : * Check if there are any SLRU stats entries waiting for flush. 148 : */ 149 : bool 150 12530 : pgstat_slru_have_pending_cb(void) 151 : { 152 12530 : return have_slrustats; 153 : } 154 : 155 : /* 156 : * Flush out locally pending SLRU stats entries 157 : * 158 : * If nowait is true, this function returns false on lock failure. Otherwise 159 : * this function always returns true. 160 : * 161 : * If nowait is true, this function returns true if the lock could not be 162 : * acquired. Otherwise return false. 163 : */ 164 : bool 165 62184 : pgstat_slru_flush_cb(bool nowait) 166 : { 167 62184 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 168 : int i; 169 : 170 62184 : if (!have_slrustats) 171 41652 : return false; 172 : 173 20532 : if (!nowait) 174 17534 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 175 2998 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 176 0 : return true; 177 : 178 184788 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 179 : { 180 164256 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i]; 181 164256 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i]; 182 : 183 : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld 184 164256 : SLRU_ACC(blocks_zeroed); 185 164256 : SLRU_ACC(blocks_hit); 186 164256 : SLRU_ACC(blocks_read); 187 164256 : SLRU_ACC(blocks_written); 188 164256 : SLRU_ACC(blocks_exists); 189 164256 : SLRU_ACC(flush); 190 164256 : SLRU_ACC(truncate); 191 : #undef SLRU_ACC 192 : } 193 : 194 : /* done, clear the pending entry */ 195 1334580 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats)); 196 : 197 20532 : LWLockRelease(&stats_shmem->lock); 198 : 199 20532 : have_slrustats = false; 200 : 201 20532 : return false; 202 : } 203 : 204 : void 205 1828 : pgstat_slru_init_shmem_cb(void *stats) 206 : { 207 1828 : PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats; 208 : 209 1828 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 210 1828 : } 211 : 212 : void 213 454 : pgstat_slru_reset_all_cb(TimestampTz ts) 214 : { 215 4086 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++) 216 3632 : pgstat_reset_slru_counter_internal(i, ts); 217 454 : } 218 : 219 : void 220 1188 : pgstat_slru_snapshot_cb(void) 221 : { 222 1188 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 223 : 224 1188 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 225 : 226 1188 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats, 227 : sizeof(stats_shmem->stats)); 228 : 229 1188 : LWLockRelease(&stats_shmem->lock); 230 1188 : } 231 : 232 : /* 233 : * Returns pointer to entry with counters for given SLRU (based on the name 234 : * stored in SlruCtl as lwlock tranche name). 235 : */ 236 : static inline PgStat_SLRUStats * 237 30984552 : get_slru_entry(int slru_idx) 238 : { 239 : pgstat_assert_is_up(); 240 : 241 : /* 242 : * The postmaster should never register any SLRU statistics counts; if it 243 : * did, the counts would be duplicated into child processes via fork(). 244 : */ 245 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 246 : 247 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); 248 : 249 30984552 : have_slrustats = true; 250 : 251 30984552 : return &pending_SLRUStats[slru_idx]; 252 : } 253 : 254 : static void 255 3638 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts) 256 : { 257 3638 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 258 : 259 3638 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 260 : 261 3638 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats)); 262 3638 : stats_shmem->stats[index].stat_reset_timestamp = ts; 263 : 264 3638 : LWLockRelease(&stats_shmem->lock); 265 3638 : }