Age Owner Branch data 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-2024, 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 : : 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 : : * "force" set to true ensures that the statistics are flushed; note that
43 : : * this needs to acquire the pgstat shmem LWLock, waiting on it. When
44 : : * set to false, the statistics may not be flushed if the lock could not
45 : : * be acquired.
46 : : */
47 : : void
739 andres@anarazel.de 48 :CBC 38712 : pgstat_report_wal(bool force)
49 : : {
50 : : bool nowait;
51 : :
52 : : /* like in pgstat.c, don't wait for lock acquisition when !force */
201 michael@paquier.xyz 53 : 38712 : nowait = !force;
54 : :
55 : : /* flush wal stats */
56 : 38712 : pgstat_flush_wal(nowait);
57 : :
58 : : /* flush IO stats */
59 : 38712 : pgstat_flush_io(nowait);
739 andres@anarazel.de 60 : 38712 : }
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 : : * 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 : 68694 : pgstat_flush_wal(bool nowait)
83 : : {
84 : 68694 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
381 85 : 68694 : WalUsage wal_usage_diff = {0};
86 : :
739 87 [ + + - + ]: 68694 : Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
88 [ + - - + ]: 68694 : 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 [ + + ]: 68694 : if (!pgstat_have_pending_wal())
96 : 55826 : 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 : : */
381 103 : 12868 : WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage);
104 : :
739 105 [ + + ]: 12868 : if (!nowait)
106 : 7528 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
107 [ - + ]: 5340 : else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
739 andres@anarazel.de 108 :UBC 0 : return true;
109 : :
110 : : #define WALSTAT_ACC(fld, var_to_add) \
111 : : (stats_shmem->stats.fld += var_to_add.fld)
112 : : #define WALSTAT_ACC_INSTR_TIME(fld) \
113 : : (stats_shmem->stats.fld += INSTR_TIME_GET_MICROSEC(PendingWalStats.fld))
381 andres@anarazel.de 114 :CBC 12868 : WALSTAT_ACC(wal_records, wal_usage_diff);
115 : 12868 : WALSTAT_ACC(wal_fpi, wal_usage_diff);
116 : 12868 : WALSTAT_ACC(wal_bytes, wal_usage_diff);
117 : 12868 : WALSTAT_ACC(wal_buffers_full, PendingWalStats);
118 : 12868 : WALSTAT_ACC(wal_write, PendingWalStats);
119 : 12868 : WALSTAT_ACC(wal_sync, PendingWalStats);
120 : 12868 : WALSTAT_ACC_INSTR_TIME(wal_write_time);
121 : 12868 : WALSTAT_ACC_INSTR_TIME(wal_sync_time);
122 : : #undef WALSTAT_ACC_INSTR_TIME
123 : : #undef WALSTAT_ACC
124 : :
739 125 : 12868 : LWLockRelease(&stats_shmem->lock);
126 : :
127 : : /*
128 : : * Save the current counters for the subsequent calculation of WAL usage.
129 : : */
130 : 12868 : prevWalUsage = pgWalUsage;
131 : :
132 : : /*
133 : : * Clear out the statistics buffer, so it can be re-used.
134 : : */
135 [ + - + - : 77208 : MemSet(&PendingWalStats, 0, sizeof(PendingWalStats));
+ - + - +
+ ]
136 : :
137 : 12868 : return false;
138 : : }
139 : :
140 : : void
141 : 19579 : pgstat_init_wal(void)
142 : : {
143 : : /*
144 : : * Initialize prevWalUsage with pgWalUsage so that pgstat_flush_wal() can
145 : : * calculate how much pgWalUsage counters are increased by subtracting
146 : : * prevWalUsage from pgWalUsage.
147 : : */
755 148 : 19579 : prevWalUsage = pgWalUsage;
149 : 19579 : }
150 : :
151 : : /*
152 : : * To determine whether any WAL activity has occurred since last time, not
153 : : * only the number of generated WAL records but also the numbers of WAL
154 : : * writes and syncs need to be checked. Because even transaction that
155 : : * generates no WAL records can write or sync WAL data when flushing the
156 : : * data pages.
157 : : */
158 : : bool
739 159 : 74355 : pgstat_have_pending_wal(void)
160 : : {
755 161 : 139608 : return pgWalUsage.wal_records != prevWalUsage.wal_records ||
739 162 [ + + + + ]: 135837 : PendingWalStats.wal_write != 0 ||
163 [ - + ]: 61482 : PendingWalStats.wal_sync != 0;
164 : : }
165 : :
166 : : void
167 : 247 : pgstat_wal_reset_all_cb(TimestampTz ts)
168 : : {
169 : 247 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
170 : :
171 : 247 : LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
172 : 247 : memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats));
173 : 247 : stats_shmem->stats.stat_reset_timestamp = ts;
174 : 247 : LWLockRelease(&stats_shmem->lock);
175 : 247 : }
176 : :
177 : : void
178 : 572 : pgstat_wal_snapshot_cb(void)
179 : : {
180 : 572 : PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
181 : :
182 : 572 : LWLockAcquire(&stats_shmem->lock, LW_SHARED);
183 : 572 : memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats,
184 : : sizeof(pgStatLocal.snapshot.wal));
185 : 572 : LWLockRelease(&stats_shmem->lock);
755 186 : 572 : }
|