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-2025, 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 : /* 25 : * WAL usage counters saved from pgWalUsage at the previous call to 26 : * pgstat_report_wal(). This is used to calculate how much WAL usage 27 : * happens between pgstat_report_wal() calls, by subtracting 28 : * the previous counters from the current ones. 29 : */ 30 : static WalUsage prevWalUsage; 31 : 32 : 33 : /* 34 : * Calculate how much WAL usage counters have increased and update 35 : * shared WAL and IO statistics. 36 : * 37 : * Must be called by processes that generate WAL, that do not call 38 : * pgstat_report_stat(), like walwriter. 39 : * 40 : * "force" set to true ensures that the statistics are flushed; note that 41 : * this needs to acquire the pgstat shmem LWLock, waiting on it. When 42 : * set to false, the statistics may not be flushed if the lock could not 43 : * be acquired. 44 : */ 45 : void 46 57348 : pgstat_report_wal(bool force) 47 : { 48 : bool nowait; 49 : 50 : /* like in pgstat.c, don't wait for lock acquisition when !force */ 51 57348 : nowait = !force; 52 : 53 : /* flush wal stats */ 54 57348 : (void) pgstat_wal_flush_cb(nowait); 55 57348 : pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_WAL); 56 : 57 : /* flush IO stats */ 58 57348 : pgstat_flush_io(nowait); 59 57348 : (void) pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_IO); 60 57348 : } 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 : * To determine whether WAL usage happened. 76 : */ 77 : static inline bool 78 124864 : pgstat_wal_have_pending(void) 79 : { 80 124864 : return pgWalUsage.wal_records != prevWalUsage.wal_records; 81 : } 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 124864 : pgstat_wal_flush_cb(bool nowait) 92 : { 93 124864 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 94 124864 : 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 124864 : if (!pgstat_wal_have_pending()) 105 103762 : 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 21102 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage); 113 : 114 21102 : if (!nowait) 115 17968 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 116 3134 : 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.wal_counters.fld += var_to_add.fld) 121 21102 : WALSTAT_ACC(wal_records, wal_usage_diff); 122 21102 : WALSTAT_ACC(wal_fpi, wal_usage_diff); 123 21102 : WALSTAT_ACC(wal_bytes, wal_usage_diff); 124 21102 : WALSTAT_ACC(wal_buffers_full, wal_usage_diff); 125 : #undef WALSTAT_ACC 126 : 127 21102 : LWLockRelease(&stats_shmem->lock); 128 : 129 : /* 130 : * Save the current counters for the subsequent calculation of WAL usage. 131 : */ 132 21102 : prevWalUsage = pgWalUsage; 133 : 134 21102 : return false; 135 : } 136 : 137 : void 138 43262 : pgstat_wal_init_backend_cb(void) 139 : { 140 : /* 141 : * Initialize prevWalUsage with pgWalUsage so that pgstat_wal_flush_cb() 142 : * can calculate how much pgWalUsage counters are increased by subtracting 143 : * prevWalUsage from pgWalUsage. 144 : */ 145 43262 : prevWalUsage = pgWalUsage; 146 43262 : } 147 : 148 : void 149 2128 : pgstat_wal_init_shmem_cb(void *stats) 150 : { 151 2128 : PgStatShared_Wal *stats_shmem = (PgStatShared_Wal *) stats; 152 : 153 2128 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 154 2128 : } 155 : 156 : void 157 466 : pgstat_wal_reset_all_cb(TimestampTz ts) 158 : { 159 466 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 160 : 161 466 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 162 466 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); 163 466 : stats_shmem->stats.stat_reset_timestamp = ts; 164 466 : LWLockRelease(&stats_shmem->lock); 165 466 : } 166 : 167 : void 168 1366 : pgstat_wal_snapshot_cb(void) 169 : { 170 1366 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 171 : 172 1366 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 173 1366 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, 174 : sizeof(pgStatLocal.snapshot.wal)); 175 1366 : LWLockRelease(&stats_shmem->lock); 176 1366 : }