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 44938 : pgstat_report_wal(bool force) 47 : { 48 : bool nowait; 49 : 50 : /* like in pgstat.c, don't wait for lock acquisition when !force */ 51 44938 : nowait = !force; 52 : 53 : /* flush wal stats */ 54 44938 : (void) pgstat_wal_flush_cb(nowait); 55 44938 : pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_WAL); 56 : 57 : /* flush IO stats */ 58 44938 : pgstat_flush_io(nowait); 59 44938 : (void) pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_IO); 60 44938 : } 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 72 : pgstat_fetch_stat_wal(void) 68 : { 69 72 : pgstat_snapshot_fixed(PGSTAT_KIND_WAL); 70 : 71 72 : 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 113636 : pgstat_wal_flush_cb(bool nowait) 83 : { 84 113636 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 85 113636 : 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 113636 : if (!pgstat_wal_have_pending_cb()) 96 94518 : 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 19118 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage); 104 : 105 19118 : if (!nowait) 106 16576 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 107 2542 : 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.wal_counters.fld += var_to_add.fld) 112 19118 : WALSTAT_ACC(wal_records, wal_usage_diff); 113 19118 : WALSTAT_ACC(wal_fpi, wal_usage_diff); 114 19118 : WALSTAT_ACC(wal_bytes, wal_usage_diff); 115 19118 : WALSTAT_ACC(wal_buffers_full, wal_usage_diff); 116 : #undef WALSTAT_ACC 117 : 118 19118 : LWLockRelease(&stats_shmem->lock); 119 : 120 : /* 121 : * Save the current counters for the subsequent calculation of WAL usage. 122 : */ 123 19118 : prevWalUsage = pgWalUsage; 124 : 125 19118 : return false; 126 : } 127 : 128 : void 129 42300 : pgstat_wal_init_backend_cb(void) 130 : { 131 : /* 132 : * Initialize prevWalUsage with pgWalUsage so that pgstat_wal_flush_cb() 133 : * can calculate how much pgWalUsage counters are increased by subtracting 134 : * prevWalUsage from pgWalUsage. 135 : */ 136 42300 : prevWalUsage = pgWalUsage; 137 42300 : } 138 : 139 : /* 140 : * To determine whether WAL usage happened. 141 : */ 142 : bool 143 126534 : pgstat_wal_have_pending_cb(void) 144 : { 145 126534 : return pgWalUsage.wal_records != prevWalUsage.wal_records; 146 : } 147 : 148 : void 149 2032 : pgstat_wal_init_shmem_cb(void *stats) 150 : { 151 2032 : PgStatShared_Wal *stats_shmem = (PgStatShared_Wal *) stats; 152 : 153 2032 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA); 154 2032 : } 155 : 156 : void 157 448 : pgstat_wal_reset_all_cb(TimestampTz ts) 158 : { 159 448 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 160 : 161 448 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 162 448 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); 163 448 : stats_shmem->stats.stat_reset_timestamp = ts; 164 448 : LWLockRelease(&stats_shmem->lock); 165 448 : } 166 : 167 : void 168 1298 : pgstat_wal_snapshot_cb(void) 169 : { 170 1298 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 171 : 172 1298 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 173 1298 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, 174 : sizeof(pgStatLocal.snapshot.wal)); 175 1298 : LWLockRelease(&stats_shmem->lock); 176 1298 : }