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 42050 : pgstat_report_wal(bool force) 49 : { 50 : bool nowait; 51 : 52 : /* like in pgstat.c, don't wait for lock acquisition when !force */ 53 42050 : nowait = !force; 54 : 55 : /* flush wal stats */ 56 42050 : pgstat_flush_wal(nowait); 57 : 58 : /* flush IO stats */ 59 42050 : pgstat_flush_io(nowait); 60 42050 : } 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 42050 : pgstat_flush_wal(bool nowait) 79 : { 80 42050 : (void) pgstat_wal_flush_cb(nowait); 81 42050 : } 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 104260 : pgstat_wal_flush_cb(bool nowait) 92 : { 93 104260 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 94 104260 : 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 104260 : if (!pgstat_wal_have_pending_cb()) 105 79880 : 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 24380 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage); 113 : 114 24380 : if (!nowait) 115 15348 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 116 9032 : 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 24380 : WALSTAT_ACC(wal_records, wal_usage_diff); 124 24380 : WALSTAT_ACC(wal_fpi, wal_usage_diff); 125 24380 : WALSTAT_ACC(wal_bytes, wal_usage_diff); 126 24380 : WALSTAT_ACC(wal_buffers_full, PendingWalStats); 127 24380 : WALSTAT_ACC(wal_write, PendingWalStats); 128 24380 : WALSTAT_ACC(wal_sync, PendingWalStats); 129 24380 : WALSTAT_ACC_INSTR_TIME(wal_write_time); 130 24380 : WALSTAT_ACC_INSTR_TIME(wal_sync_time); 131 : #undef WALSTAT_ACC_INSTR_TIME 132 : #undef WALSTAT_ACC 133 : 134 24380 : LWLockRelease(&stats_shmem->lock); 135 : 136 : /* 137 : * Save the current counters for the subsequent calculation of WAL usage. 138 : */ 139 24380 : prevWalUsage = pgWalUsage; 140 : 141 : /* 142 : * Clear out the statistics buffer, so it can be re-used. 143 : */ 144 146280 : MemSet(&PendingWalStats, 0, sizeof(PendingWalStats)); 145 : 146 24380 : return false; 147 : } 148 : 149 : void 150 35586 : 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 35586 : prevWalUsage = pgWalUsage; 158 35586 : } 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 114590 : pgstat_wal_have_pending_cb(void) 169 : { 170 211746 : return pgWalUsage.wal_records != prevWalUsage.wal_records || 171 204790 : PendingWalStats.wal_write != 0 || 172 90200 : PendingWalStats.wal_sync != 0; 173 : } 174 : 175 : void 176 1902 : pgstat_wal_init_shmem_cb(void *stats) 177 : { 178 1902 : PgStatShared_Wal *stats_shmem = (PgStatShared_Wal *) stats; 179 : 180 1902 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 181 1902 : } 182 : 183 : void 184 466 : pgstat_wal_reset_all_cb(TimestampTz ts) 185 : { 186 466 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 187 : 188 466 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 189 466 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); 190 466 : stats_shmem->stats.stat_reset_timestamp = ts; 191 466 : LWLockRelease(&stats_shmem->lock); 192 466 : } 193 : 194 : void 195 1204 : pgstat_wal_snapshot_cb(void) 196 : { 197 1204 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 198 : 199 1204 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 200 1204 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, 201 : sizeof(pgStatLocal.snapshot.wal)); 202 1204 : LWLockRelease(&stats_shmem->lock); 203 1204 : }