Coverage Report

Created: 2025-06-13 06:06

/src/postgres/src/backend/utils/activity/pgstat_wal.c
Line
Count
Source (jump to first uncovered line)
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-2025, 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
pgstat_report_wal(bool force)
47
0
{
48
0
  bool    nowait;
49
50
  /* like in pgstat.c, don't wait for lock acquisition when !force */
51
0
  nowait = !force;
52
53
  /* flush wal stats */
54
0
  (void) pgstat_wal_flush_cb(nowait);
55
0
  pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_WAL);
56
57
  /* flush IO stats */
58
0
  pgstat_flush_io(nowait);
59
0
  (void) pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_IO);
60
0
}
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
pgstat_fetch_stat_wal(void)
68
0
{
69
0
  pgstat_snapshot_fixed(PGSTAT_KIND_WAL);
70
71
0
  return &pgStatLocal.snapshot.wal;
72
0
}
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
pgstat_wal_flush_cb(bool nowait)
83
0
{
84
0
  PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
85
0
  WalUsage  wal_usage_diff = {0};
86
87
0
  Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
88
0
  Assert(pgStatLocal.shmem != NULL &&
89
0
       !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
0
  if (!pgstat_wal_have_pending_cb())
96
0
    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
   */
103
0
  WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevWalUsage);
104
105
0
  if (!nowait)
106
0
    LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
107
0
  else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
108
0
    return true;
109
110
0
#define WALSTAT_ACC(fld, var_to_add) \
111
0
  (stats_shmem->stats.wal_counters.fld += var_to_add.fld)
112
0
  WALSTAT_ACC(wal_records, wal_usage_diff);
113
0
  WALSTAT_ACC(wal_fpi, wal_usage_diff);
114
0
  WALSTAT_ACC(wal_bytes, wal_usage_diff);
115
0
  WALSTAT_ACC(wal_buffers_full, wal_usage_diff);
116
0
#undef WALSTAT_ACC
117
118
0
  LWLockRelease(&stats_shmem->lock);
119
120
  /*
121
   * Save the current counters for the subsequent calculation of WAL usage.
122
   */
123
0
  prevWalUsage = pgWalUsage;
124
125
0
  return false;
126
0
}
127
128
void
129
pgstat_wal_init_backend_cb(void)
130
0
{
131
  /*
132
   * Initialize prevWalUsage with pgWalUsage so that pgstat_wal_flush_cb()
133
   * can calculate how much pgWalUsage counters are increased by subtracting
134
   * prevWalUsage from pgWalUsage.
135
   */
136
0
  prevWalUsage = pgWalUsage;
137
0
}
138
139
/*
140
 * To determine whether WAL usage happened.
141
 */
142
bool
143
pgstat_wal_have_pending_cb(void)
144
0
{
145
0
  return pgWalUsage.wal_records != prevWalUsage.wal_records;
146
0
}
147
148
void
149
pgstat_wal_init_shmem_cb(void *stats)
150
0
{
151
0
  PgStatShared_Wal *stats_shmem = (PgStatShared_Wal *) stats;
152
153
0
  LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
154
0
}
155
156
void
157
pgstat_wal_reset_all_cb(TimestampTz ts)
158
0
{
159
0
  PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
160
161
0
  LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
162
0
  memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats));
163
0
  stats_shmem->stats.stat_reset_timestamp = ts;
164
0
  LWLockRelease(&stats_shmem->lock);
165
0
}
166
167
void
168
pgstat_wal_snapshot_cb(void)
169
0
{
170
0
  PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
171
172
0
  LWLockAcquire(&stats_shmem->lock, LW_SHARED);
173
0
  memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats,
174
0
       sizeof(pgStatLocal.snapshot.wal));
175
0
  LWLockRelease(&stats_shmem->lock);
176
0
}