Line data Source code
1 : /* ------------------------------------------------------------------------- 2 : * 3 : * pgstat_wal.c 4 : * Implementation of WAL statistics. 5 : * 6 : * This file contains the implementation of WAL 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_wal.c 15 : * ------------------------------------------------------------------------- 16 : */ 17 : 18 : #include "postgres.h" 19 : 20 : #include "executor/instrument.h" 21 : #include "utils/pgstat_internal.h" 22 : 23 : 24 : PgStat_PendingWalStats PendingWalStats = {0}; 25 : 26 : /* 27 : * WAL usage counters saved from pgWalUsage at the previous call to 28 : * pgstat_report_wal(). This is used to calculate how much WAL usage 29 : * happens between pgstat_report_wal() calls, by subtracting 30 : * the previous counters from the current ones. 31 : */ 32 : static WalUsage prevWalUsage; 33 : 34 : 35 : /* 36 : * Calculate how much WAL usage counters have increased and update 37 : * shared WAL and IO statistics. 38 : * 39 : * Must be called by processes that generate WAL, that do not call 40 : * pgstat_report_stat(), like walwriter. 41 : * 42 : * "force" set to true ensures that the statistics are flushed; note that 43 : * this needs to acquire the pgstat shmem LWLock, waiting on it. When 44 : * set to false, the statistics may not be flushed if the lock could not 45 : * be acquired. 46 : */ 47 : void 48 40776 : pgstat_report_wal(bool force) 49 : { 50 : bool nowait; 51 : 52 : /* like in pgstat.c, don't wait for lock acquisition when !force */ 53 40776 : nowait = !force; 54 : 55 : /* flush wal stats */ 56 40776 : pgstat_flush_wal(nowait); 57 : 58 : /* flush IO stats */ 59 40776 : pgstat_flush_io(nowait); 60 40776 : } 61 : 62 : /* 63 : * Support function for the SQL-callable pgstat* functions. Returns 64 : * a pointer to the WAL statistics struct. 65 : */ 66 : PgStat_WalStats * 67 70 : pgstat_fetch_stat_wal(void) 68 : { 69 70 : pgstat_snapshot_fixed(PGSTAT_KIND_WAL); 70 : 71 70 : return &pgStatLocal.snapshot.wal; 72 : } 73 : 74 : /* 75 : * Simple wrapper of pgstat_wal_flush_cb() 76 : */ 77 : void 78 40776 : pgstat_flush_wal(bool nowait) 79 : { 80 40776 : (void) pgstat_wal_flush_cb(nowait); 81 40776 : } 82 : 83 : /* 84 : * Calculate how much WAL usage counters have increased by subtracting the 85 : * previous counters from the current ones. 86 : * 87 : * If nowait is true, this function returns true if the lock could not be 88 : * acquired. Otherwise return false. 89 : */ 90 : bool 91 102964 : pgstat_wal_flush_cb(bool nowait) 92 : { 93 102964 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 94 102964 : WalUsage wal_usage_diff = {0}; 95 : 96 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 97 : Assert(pgStatLocal.shmem != NULL && 98 : !pgStatLocal.shmem->is_shutdown); 99 : 100 : /* 101 : * This function can be called even if nothing at all has happened. Avoid 102 : * taking lock for nothing in that case. 103 : */ 104 102964 : if (!pgstat_wal_have_pending_cb()) 105 79314 : return false; 106 : 107 : /* 108 : * We don't update the WAL usage portion of the local WalStats elsewhere. 109 : * Calculate how much WAL usage counters were increased by subtracting the 110 : * previous counters from the current ones. 111 : */ 112 23650 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage); 113 : 114 23650 : if (!nowait) 115 14950 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 116 8700 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 117 0 : return true; 118 : 119 : #define WALSTAT_ACC(fld, var_to_add) \ 120 : (stats_shmem->stats.fld += var_to_add.fld) 121 : #define WALSTAT_ACC_INSTR_TIME(fld) \ 122 : (stats_shmem->stats.fld += INSTR_TIME_GET_MICROSEC(PendingWalStats.fld)) 123 23650 : WALSTAT_ACC(wal_records, wal_usage_diff); 124 23650 : WALSTAT_ACC(wal_fpi, wal_usage_diff); 125 23650 : WALSTAT_ACC(wal_bytes, wal_usage_diff); 126 23650 : WALSTAT_ACC(wal_buffers_full, PendingWalStats); 127 23650 : WALSTAT_ACC(wal_write, PendingWalStats); 128 23650 : WALSTAT_ACC(wal_sync, PendingWalStats); 129 23650 : WALSTAT_ACC_INSTR_TIME(wal_write_time); 130 23650 : WALSTAT_ACC_INSTR_TIME(wal_sync_time); 131 : #undef WALSTAT_ACC_INSTR_TIME 132 : #undef WALSTAT_ACC 133 : 134 23650 : LWLockRelease(&stats_shmem->lock); 135 : 136 : /* 137 : * Save the current counters for the subsequent calculation of WAL usage. 138 : */ 139 23650 : prevWalUsage = pgWalUsage; 140 : 141 : /* 142 : * Clear out the statistics buffer, so it can be re-used. 143 : */ 144 141900 : MemSet(&PendingWalStats, 0, sizeof(PendingWalStats)); 145 : 146 23650 : return false; 147 : } 148 : 149 : void 150 36122 : pgstat_wal_init_backend_cb(void) 151 : { 152 : /* 153 : * Initialize prevWalUsage with pgWalUsage so that pgstat_wal_flush_cb() 154 : * can calculate how much pgWalUsage counters are increased by subtracting 155 : * prevWalUsage from pgWalUsage. 156 : */ 157 36122 : prevWalUsage = pgWalUsage; 158 36122 : } 159 : 160 : /* 161 : * To determine whether any WAL activity has occurred since last time, not 162 : * only the number of generated WAL records but also the numbers of WAL 163 : * writes and syncs need to be checked. Because even transaction that 164 : * generates no WAL records can write or sync WAL data when flushing the 165 : * data pages. 166 : */ 167 : bool 168 113322 : pgstat_wal_have_pending_cb(void) 169 : { 170 209752 : return pgWalUsage.wal_records != prevWalUsage.wal_records || 171 202984 : PendingWalStats.wal_write != 0 || 172 89662 : PendingWalStats.wal_sync != 0; 173 : } 174 : 175 : void 176 1828 : pgstat_wal_init_shmem_cb(void *stats) 177 : { 178 1828 : PgStatShared_Wal *stats_shmem = (PgStatShared_Wal *) stats; 179 : 180 1828 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 181 1828 : } 182 : 183 : void 184 450 : pgstat_wal_reset_all_cb(TimestampTz ts) 185 : { 186 450 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 187 : 188 450 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 189 450 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); 190 450 : stats_shmem->stats.stat_reset_timestamp = ts; 191 450 : LWLockRelease(&stats_shmem->lock); 192 450 : } 193 : 194 : void 195 1162 : pgstat_wal_snapshot_cb(void) 196 : { 197 1162 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 198 : 199 1162 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 200 1162 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, 201 : sizeof(pgStatLocal.snapshot.wal)); 202 1162 : LWLockRelease(&stats_shmem->lock); 203 1162 : }