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-2026, 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 32609 : pgstat_report_wal(bool force)
47 : {
48 : bool nowait;
49 :
50 : /* like in pgstat.c, don't wait for lock acquisition when !force */
51 32609 : nowait = !force;
52 :
53 : /* flush wal stats */
54 32609 : (void) pgstat_wal_flush_cb(nowait);
55 32609 : pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_WAL);
56 :
57 : /* flush IO stats */
58 32609 : pgstat_flush_io(nowait);
59 32609 : (void) pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_IO);
60 32609 : }
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 35 : pgstat_fetch_stat_wal(void)
68 : {
69 35 : pgstat_snapshot_fixed(PGSTAT_KIND_WAL);
70 :
71 35 : return &pgStatLocal.snapshot.wal;
72 : }
73 :
74 : /*
75 : * To determine whether WAL usage happened.
76 : */
77 : static inline bool
78 69323 : pgstat_wal_have_pending(void)
79 : {
80 69323 : 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 69323 : pgstat_wal_flush_cb(bool nowait)
92 : {
93 69323 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
94 69323 : 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 69323 : if (!pgstat_wal_have_pending())
105 57511 : 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 11812 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage);
113 :
114 11812 : if (!nowait)
115 9641 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
116 2171 : 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 11812 : WALSTAT_ACC(wal_records, wal_usage_diff);
122 11812 : WALSTAT_ACC(wal_fpi, wal_usage_diff);
123 11812 : WALSTAT_ACC(wal_bytes, wal_usage_diff);
124 11812 : WALSTAT_ACC(wal_fpi_bytes, wal_usage_diff);
125 11812 : WALSTAT_ACC(wal_buffers_full, wal_usage_diff);
126 : #undef WALSTAT_ACC
127 :
128 11812 : LWLockRelease(&stats_shmem->lock);
129 :
130 : /*
131 : * Save the current counters for the subsequent calculation of WAL usage.
132 : */
133 11812 : prevWalUsage = pgWalUsage;
134 :
135 11812 : return false;
136 : }
137 :
138 : void
139 23004 : pgstat_wal_init_backend_cb(void)
140 : {
141 : /*
142 : * Initialize prevWalUsage with pgWalUsage so that pgstat_wal_flush_cb()
143 : * can calculate how much pgWalUsage counters are increased by subtracting
144 : * prevWalUsage from pgWalUsage.
145 : */
146 23004 : prevWalUsage = pgWalUsage;
147 23004 : }
148 :
149 : void
150 1140 : pgstat_wal_init_shmem_cb(void *stats)
151 : {
152 1140 : PgStatShared_Wal *stats_shmem = (PgStatShared_Wal *) stats;
153 :
154 1140 : LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
155 1140 : }
156 :
157 : void
158 243 : pgstat_wal_reset_all_cb(TimestampTz ts)
159 : {
160 243 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
161 :
162 243 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
163 243 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats));
164 243 : stats_shmem->stats.stat_reset_timestamp = ts;
165 243 : LWLockRelease(&stats_shmem->lock);
166 243 : }
167 :
168 : void
169 745 : pgstat_wal_snapshot_cb(void)
170 : {
171 745 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
172 :
173 745 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
174 745 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats,
175 : sizeof(pgStatLocal.snapshot.wal));
176 745 : LWLockRelease(&stats_shmem->lock);
177 745 : }
|