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-2023, 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 "utils/pgstat_internal.h" 21 : #include "executor/instrument.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 : void 43 33070 : pgstat_report_wal(bool force) 44 : { 45 33070 : pgstat_flush_wal(force); 46 : 47 33070 : pgstat_flush_io(force); 48 33070 : } 49 : 50 : /* 51 : * Support function for the SQL-callable pgstat* functions. Returns 52 : * a pointer to the WAL statistics struct. 53 : */ 54 : PgStat_WalStats * 55 82 : pgstat_fetch_stat_wal(void) 56 : { 57 82 : pgstat_snapshot_fixed(PGSTAT_KIND_WAL); 58 : 59 82 : return &pgStatLocal.snapshot.wal; 60 : } 61 : 62 : /* 63 : * Calculate how much WAL usage counters have increased by subtracting the 64 : * previous counters from the current ones. 65 : * 66 : * If nowait is true, this function returns true if the lock could not be 67 : * acquired. Otherwise return false. 68 : */ 69 : bool 70 80708 : pgstat_flush_wal(bool nowait) 71 : { 72 80708 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 73 80708 : WalUsage wal_usage_diff = {0}; 74 : 75 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment); 76 : Assert(pgStatLocal.shmem != NULL && 77 : !pgStatLocal.shmem->is_shutdown); 78 : 79 : /* 80 : * This function can be called even if nothing at all has happened. Avoid 81 : * taking lock for nothing in that case. 82 : */ 83 80708 : if (!pgstat_have_pending_wal()) 84 57316 : return false; 85 : 86 : /* 87 : * We don't update the WAL usage portion of the local WalStats elsewhere. 88 : * Calculate how much WAL usage counters were increased by subtracting the 89 : * previous counters from the current ones. 90 : */ 91 23392 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage); 92 : 93 23392 : if (!nowait) 94 20552 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 95 2840 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) 96 0 : return true; 97 : 98 : #define WALSTAT_ACC(fld, var_to_add) \ 99 : (stats_shmem->stats.fld += var_to_add.fld) 100 : #define WALSTAT_ACC_INSTR_TIME(fld) \ 101 : (stats_shmem->stats.fld += INSTR_TIME_GET_MICROSEC(PendingWalStats.fld)) 102 23392 : WALSTAT_ACC(wal_records, wal_usage_diff); 103 23392 : WALSTAT_ACC(wal_fpi, wal_usage_diff); 104 23392 : WALSTAT_ACC(wal_bytes, wal_usage_diff); 105 23392 : WALSTAT_ACC(wal_buffers_full, PendingWalStats); 106 23392 : WALSTAT_ACC(wal_write, PendingWalStats); 107 23392 : WALSTAT_ACC(wal_sync, PendingWalStats); 108 23392 : WALSTAT_ACC_INSTR_TIME(wal_write_time); 109 23392 : WALSTAT_ACC_INSTR_TIME(wal_sync_time); 110 : #undef WALSTAT_ACC_INSTR_TIME 111 : #undef WALSTAT_ACC 112 : 113 23392 : LWLockRelease(&stats_shmem->lock); 114 : 115 : /* 116 : * Save the current counters for the subsequent calculation of WAL usage. 117 : */ 118 23392 : prevWalUsage = pgWalUsage; 119 : 120 : /* 121 : * Clear out the statistics buffer, so it can be re-used. 122 : */ 123 140352 : MemSet(&PendingWalStats, 0, sizeof(PendingWalStats)); 124 : 125 23392 : return false; 126 : } 127 : 128 : void 129 27420 : pgstat_init_wal(void) 130 : { 131 : /* 132 : * Initialize prevWalUsage with pgWalUsage so that pgstat_flush_wal() can 133 : * calculate how much pgWalUsage counters are increased by subtracting 134 : * prevWalUsage from pgWalUsage. 135 : */ 136 27420 : prevWalUsage = pgWalUsage; 137 27420 : } 138 : 139 : /* 140 : * To determine whether any WAL activity has occurred since last time, not 141 : * only the number of generated WAL records but also the numbers of WAL 142 : * writes and syncs need to be checked. Because even transaction that 143 : * generates no WAL records can write or sync WAL data when flushing the 144 : * data pages. 145 : */ 146 : bool 147 92944 : pgstat_have_pending_wal(void) 148 : { 149 170788 : return pgWalUsage.wal_records != prevWalUsage.wal_records || 150 162414 : PendingWalStats.wal_write != 0 || 151 69470 : PendingWalStats.wal_sync != 0; 152 : } 153 : 154 : void 155 890 : pgstat_wal_reset_all_cb(TimestampTz ts) 156 : { 157 890 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 158 : 159 890 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); 160 890 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); 161 890 : stats_shmem->stats.stat_reset_timestamp = ts; 162 890 : LWLockRelease(&stats_shmem->lock); 163 890 : } 164 : 165 : void 166 2048 : pgstat_wal_snapshot_cb(void) 167 : { 168 2048 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; 169 : 170 2048 : LWLockAcquire(&stats_shmem->lock, LW_SHARED); 171 2048 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, 172 : sizeof(pgStatLocal.snapshot.wal)); 173 2048 : LWLockRelease(&stats_shmem->lock); 174 2048 : }