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 37128 : pgstat_report_wal(bool force) 49 : { 50 : bool nowait; 51 : 52 : /* like in pgstat.c, don't wait for lock acquisition when !force */ 53 37128 : nowait = !force; 54 : 55 : /* flush wal stats */ 56 37128 : pgstat_flush_wal(nowait); 57 : 58 : /* flush IO stats */ 59 37128 : pgstat_flush_io(nowait); 60 37128 : } 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 : * Calculate how much WAL usage counters have increased by subtracting the 76 : * previous counters from the current ones. 77 : * 78 : * If nowait is true, this function returns true if the lock could not be 79 : * acquired. Otherwise return false. 80 : */ 81 : bool 82 88812 : pgstat_flush_wal(bool nowait) 83 : { 84 88812 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 85 88812 : WalUsage wal_usage_diff = {0}; 86 : 87 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 88 : Assert(pgStatLocal.shmem != NULL && 89 : !pgStatLocal.shmem->is_shutdown); 90 : 91 : /* 92 : * This function can be called even if nothing at all has happened. Avoid 93 : * taking lock for nothing in that case. 94 : */ 95 88812 : if (!pgstat_have_pending_wal()) 96 70912 : return false; 97 : 98 : /* 99 : * We don't update the WAL usage portion of the local WalStats elsewhere. 100 : * Calculate how much WAL usage counters were increased by subtracting the 101 : * previous counters from the current ones. 102 : */ 103 17900 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage); 104 : 105 17900 : if (!nowait) 106 13676 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 107 4224 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 108 0 : return true; 109 : 110 : #define WALSTAT_ACC(fld, var_to_add) \ 111 : (stats_shmem->stats.fld += var_to_add.fld) 112 : #define WALSTAT_ACC_INSTR_TIME(fld) \ 113 : (stats_shmem->stats.fld += INSTR_TIME_GET_MICROSEC(PendingWalStats.fld)) 114 17900 : WALSTAT_ACC(wal_records, wal_usage_diff); 115 17900 : WALSTAT_ACC(wal_fpi, wal_usage_diff); 116 17900 : WALSTAT_ACC(wal_bytes, wal_usage_diff); 117 17900 : WALSTAT_ACC(wal_buffers_full, PendingWalStats); 118 17900 : WALSTAT_ACC(wal_write, PendingWalStats); 119 17900 : WALSTAT_ACC(wal_sync, PendingWalStats); 120 17900 : WALSTAT_ACC_INSTR_TIME(wal_write_time); 121 17900 : WALSTAT_ACC_INSTR_TIME(wal_sync_time); 122 : #undef WALSTAT_ACC_INSTR_TIME 123 : #undef WALSTAT_ACC 124 : 125 17900 : LWLockRelease(&stats_shmem->lock); 126 : 127 : /* 128 : * Save the current counters for the subsequent calculation of WAL usage. 129 : */ 130 17900 : prevWalUsage = pgWalUsage; 131 : 132 : /* 133 : * Clear out the statistics buffer, so it can be re-used. 134 : */ 135 107400 : MemSet(&PendingWalStats, 0, sizeof(PendingWalStats)); 136 : 137 17900 : return false; 138 : } 139 : 140 : void 141 29854 : pgstat_init_wal(void) 142 : { 143 : /* 144 : * Initialize prevWalUsage with pgWalUsage so that pgstat_flush_wal() can 145 : * calculate how much pgWalUsage counters are increased by subtracting 146 : * prevWalUsage from pgWalUsage. 147 : */ 148 29854 : prevWalUsage = pgWalUsage; 149 29854 : } 150 : 151 : /* 152 : * To determine whether any WAL activity has occurred since last time, not 153 : * only the number of generated WAL records but also the numbers of WAL 154 : * writes and syncs need to be checked. Because even transaction that 155 : * generates no WAL records can write or sync WAL data when flushing the 156 : * data pages. 157 : */ 158 : bool 159 98100 : pgstat_have_pending_wal(void) 160 : { 161 180920 : return pgWalUsage.wal_records != prevWalUsage.wal_records || 162 178290 : PendingWalStats.wal_write != 0 || 163 80190 : PendingWalStats.wal_sync != 0; 164 : } 165 : 166 : void 167 420 : pgstat_wal_reset_all_cb(TimestampTz ts) 168 : { 169 420 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 170 : 171 420 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 172 420 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); 173 420 : stats_shmem->stats.stat_reset_timestamp = ts; 174 420 : LWLockRelease(&stats_shmem->lock); 175 420 : } 176 : 177 : void 178 1118 : pgstat_wal_snapshot_cb(void) 179 : { 180 1118 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 181 : 182 1118 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 183 1118 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, 184 : sizeof(pgStatLocal.snapshot.wal)); 185 1118 : LWLockRelease(&stats_shmem->lock); 186 1118 : }