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