Age Owner TLA 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
368 andres 43 CBC 19881 : pgstat_report_wal(bool force)
44 : {
45 19881 : pgstat_flush_wal(force);
46 :
60 andres 47 GNC 19881 : pgstat_flush_io(force);
368 andres 48 GIC 19881 : }
368 andres 49 ECB :
50 : /*
51 : * Support function for the SQL-callable pgstat* functions. Returns
52 : * a pointer to the WAL statistics struct.
53 : */
54 : PgStat_WalStats *
368 andres 55 GIC 41 : pgstat_fetch_stat_wal(void)
56 : {
368 andres 57 CBC 41 : pgstat_snapshot_fixed(PGSTAT_KIND_WAL);
58 :
59 41 : return &pgStatLocal.snapshot.wal;
60 : }
368 andres 61 ECB :
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
368 andres 70 GIC 44337 : pgstat_flush_wal(bool nowait)
71 : {
368 andres 72 CBC 44337 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
10 andres 73 GNC 44337 : WalUsage wal_usage_diff = {0};
368 andres 74 ECB :
368 andres 75 CBC 44337 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
368 andres 76 GIC 44337 : Assert(pgStatLocal.shmem != NULL &&
368 andres 77 ECB : !pgStatLocal.shmem->is_shutdown);
384 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 : */
368 andres 83 GIC 44337 : if (!pgstat_have_pending_wal())
84 30513 : return false;
384 andres 85 ECB :
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 : */
10 andres 91 GNC 13824 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage);
368 andres 92 ECB :
368 andres 93 CBC 13824 : if (!nowait)
94 10931 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
368 andres 95 GBC 2893 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
368 andres 96 UIC 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))
10 andres 102 GNC 13824 : WALSTAT_ACC(wal_records, wal_usage_diff);
103 13824 : WALSTAT_ACC(wal_fpi, wal_usage_diff);
104 13824 : WALSTAT_ACC(wal_bytes, wal_usage_diff);
105 13824 : WALSTAT_ACC(wal_buffers_full, PendingWalStats);
106 13824 : WALSTAT_ACC(wal_write, PendingWalStats);
107 13824 : WALSTAT_ACC(wal_sync, PendingWalStats);
108 13824 : WALSTAT_ACC_INSTR_TIME(wal_write_time);
109 13824 : WALSTAT_ACC_INSTR_TIME(wal_sync_time);
110 : #undef WALSTAT_ACC_INSTR_TIME
368 andres 111 ECB : #undef WALSTAT_ACC
112 :
368 andres 113 GIC 13824 : LWLockRelease(&stats_shmem->lock);
114 :
115 : /*
368 andres 116 ECB : * Save the current counters for the subsequent calculation of WAL usage.
117 : */
368 andres 118 GIC 13824 : prevWalUsage = pgWalUsage;
119 :
120 : /*
384 andres 121 ECB : * Clear out the statistics buffer, so it can be re-used.
122 : */
368 andres 123 GIC 82944 : MemSet(&PendingWalStats, 0, sizeof(PendingWalStats));
124 :
125 13824 : return false;
384 andres 126 ECB : }
127 :
128 : void
368 andres 129 GIC 13302 : pgstat_init_wal(void)
130 : {
131 : /*
368 andres 132 ECB : * 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 : */
384 andres 136 GIC 13302 : prevWalUsage = pgWalUsage;
137 13302 : }
138 :
384 andres 139 ECB : /*
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
368 andres 147 GIC 50685 : pgstat_have_pending_wal(void)
148 : {
384 149 92438 : return pgWalUsage.wal_records != prevWalUsage.wal_records ||
368 andres 150 CBC 87488 : PendingWalStats.wal_write != 0 ||
368 andres 151 GIC 36803 : PendingWalStats.wal_sync != 0;
368 andres 152 ECB : }
153 :
154 : void
368 andres 155 GIC 442 : pgstat_wal_reset_all_cb(TimestampTz ts)
156 : {
157 442 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
368 andres 158 ECB :
368 andres 159 GIC 442 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
368 andres 160 CBC 442 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats));
368 andres 161 GIC 442 : stats_shmem->stats.stat_reset_timestamp = ts;
368 andres 162 CBC 442 : LWLockRelease(&stats_shmem->lock);
163 442 : }
368 andres 164 ECB :
165 : void
368 andres 166 CBC 1033 : pgstat_wal_snapshot_cb(void)
167 : {
368 andres 168 GIC 1033 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
368 andres 169 ECB :
368 andres 170 GIC 1033 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
368 andres 171 CBC 1033 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats,
172 : sizeof(pgStatLocal.snapshot.wal));
173 1033 : LWLockRelease(&stats_shmem->lock);
384 174 1033 : }
|