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 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 6282 : pgstat_count_slru_page_zeroed(int slru_idx) 60 : { 61 6282 : get_slru_entry(slru_idx)->blocks_zeroed += 1; 62 6282 : } 63 : 64 : void 65 4231462 : pgstat_count_slru_page_hit(int slru_idx) 66 : { 67 4231462 : get_slru_entry(slru_idx)->blocks_hit += 1; 68 4231462 : } 69 : 70 : void 71 76 : pgstat_count_slru_page_exists(int slru_idx) 72 : { 73 76 : get_slru_entry(slru_idx)->blocks_exists += 1; 74 76 : } 75 : 76 : void 77 3410 : pgstat_count_slru_page_read(int slru_idx) 78 : { 79 3410 : get_slru_entry(slru_idx)->blocks_read += 1; 80 3410 : } 81 : 82 : void 83 9876 : pgstat_count_slru_page_written(int slru_idx) 84 : { 85 9876 : get_slru_entry(slru_idx)->blocks_written += 1; 86 9876 : } 87 : 88 : void 89 23480 : pgstat_count_slru_flush(int slru_idx) 90 : { 91 23480 : get_slru_entry(slru_idx)->flush += 1; 92 23480 : } 93 : 94 : void 95 4638 : pgstat_count_slru_truncate(int slru_idx) 96 : { 97 4638 : get_slru_entry(slru_idx)->truncate += 1; 98 4638 : } 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 112 : pgstat_fetch_slru(void) 106 : { 107 112 : pgstat_snapshot_fixed(PGSTAT_KIND_SLRU); 108 : 109 112 : 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 1008 : pgstat_get_slru_name(int slru_idx) 119 : { 120 1008 : if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS) 121 112 : return NULL; 122 : 123 896 : 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 25460 : pgstat_get_slru_index(const char *name) 133 : { 134 : int i; 135 : 136 101832 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 137 : { 138 101830 : if (strcmp(slru_names[i], name) == 0) 139 25458 : 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 : * 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 47638 : pgstat_slru_flush(bool nowait) 157 : { 158 47638 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 159 : int i; 160 : 161 47638 : if (!have_slrustats) 162 28992 : return false; 163 : 164 18646 : if (!nowait) 165 15572 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 166 3074 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 167 0 : return true; 168 : 169 167814 : for (i = 0; i < SLRU_NUM_ELEMENTS; i++) 170 : { 171 149168 : PgStat_SLRUStats *sharedent = &stats_shmem->stats[i]; 172 149168 : PgStat_SLRUStats *pendingent = &pending_SLRUStats[i]; 173 : 174 : #define SLRU_ACC(fld) sharedent->fld += pendingent->fld 175 149168 : SLRU_ACC(blocks_zeroed); 176 149168 : SLRU_ACC(blocks_hit); 177 149168 : SLRU_ACC(blocks_read); 178 149168 : SLRU_ACC(blocks_written); 179 149168 : SLRU_ACC(blocks_exists); 180 149168 : SLRU_ACC(flush); 181 149168 : SLRU_ACC(truncate); 182 : #undef SLRU_ACC 183 : } 184 : 185 : /* done, clear the pending entry */ 186 1211990 : MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats)); 187 : 188 18646 : LWLockRelease(&stats_shmem->lock); 189 : 190 18646 : have_slrustats = false; 191 : 192 18646 : return false; 193 : } 194 : 195 : void 196 888 : pgstat_slru_reset_all_cb(TimestampTz ts) 197 : { 198 7992 : for (int i = 0; i < SLRU_NUM_ELEMENTS; i++) 199 7104 : pgstat_reset_slru_counter_internal(i, ts); 200 888 : } 201 : 202 : void 203 2050 : pgstat_slru_snapshot_cb(void) 204 : { 205 2050 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 206 : 207 2050 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 208 : 209 2050 : memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats, 210 : sizeof(stats_shmem->stats)); 211 : 212 2050 : LWLockRelease(&stats_shmem->lock); 213 2050 : } 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 * 220 4279224 : get_slru_entry(int slru_idx) 221 : { 222 : 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 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 229 : 230 : Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS)); 231 : 232 4279224 : have_slrustats = true; 233 : 234 4279224 : return &pending_SLRUStats[slru_idx]; 235 : } 236 : 237 : static void 238 7110 : pgstat_reset_slru_counter_internal(int index, TimestampTz ts) 239 : { 240 7110 : PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru; 241 : 242 7110 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 243 : 244 7110 : memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats)); 245 7110 : stats_shmem->stats[index].stat_reset_timestamp = ts; 246 : 247 7110 : LWLockRelease(&stats_shmem->lock); 248 7110 : }