Coverage Report

Created: 2026-08-13 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/utils/activity/pgstat_slru.c
Line
Count
Source
1
/* -------------------------------------------------------------------------
2
 *
3
 * pgstat_slru.c
4
 *    Implementation of SLRU statistics.
5
 *
6
 * This file contains the implementation of SLRU 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_slru.c
15
 * -------------------------------------------------------------------------
16
 */
17
18
#include "postgres.h"
19
20
#include "utils/pgstat_internal.h"
21
#include "utils/timestamp.h"
22
23
24
static inline PgStat_SLRUStats *get_slru_entry(int slru_idx);
25
static void pgstat_reset_slru_counter_internal(int index, TimestampTz ts);
26
27
28
/*
29
 * SLRU statistics counts waiting to be flushed out.  We assume this variable
30
 * inits to zeroes.  Entries are one-to-one with slru_names[].  Changes of
31
 * SLRU counters are reported within critical sections so we use static memory
32
 * in order to avoid memory allocation.
33
 */
34
static PgStat_SLRUStats pending_SLRUStats[SLRU_NUM_ELEMENTS];
35
static bool have_slrustats = false;
36
37
38
/*
39
 * Reset counters for a single SLRU.
40
 *
41
 * Permission checking for this function is managed through the normal
42
 * GRANT system.
43
 */
44
void
45
pgstat_reset_slru(const char *name)
46
0
{
47
0
  TimestampTz ts = GetCurrentTimestamp();
48
49
0
  Assert(name != NULL);
50
51
0
  pgstat_reset_slru_counter_internal(pgstat_get_slru_index(name), ts);
52
0
}
53
54
/*
55
 * SLRU statistics count accumulation functions --- called from slru.c
56
 */
57
58
#define PGSTAT_COUNT_SLRU(stat)           \
59
void                        \
60
0
CppConcat(pgstat_count_slru_,stat)(int slru_idx)  \
61
0
{                         \
62
0
  get_slru_entry(slru_idx)->stat += 1;      \
63
0
}
Unexecuted instantiation: pgstat_count_slru_blocks_zeroed
Unexecuted instantiation: pgstat_count_slru_blocks_hit
Unexecuted instantiation: pgstat_count_slru_blocks_exists
Unexecuted instantiation: pgstat_count_slru_blocks_read
Unexecuted instantiation: pgstat_count_slru_blocks_written
Unexecuted instantiation: pgstat_count_slru_flush
Unexecuted instantiation: pgstat_count_slru_truncate
64
65
/* pgstat_count_slru_blocks_zeroed */
66
PGSTAT_COUNT_SLRU(blocks_zeroed)
67
68
/* pgstat_count_slru_blocks_hit */
69
PGSTAT_COUNT_SLRU(blocks_hit)
70
71
/* pgstat_count_slru_blocks_exists */
72
PGSTAT_COUNT_SLRU(blocks_exists)
73
74
/* pgstat_count_slru_blocks_read */
75
PGSTAT_COUNT_SLRU(blocks_read)
76
77
/* pgstat_count_slru_blocks_written */
78
PGSTAT_COUNT_SLRU(blocks_written)
79
80
/* pgstat_count_slru_flush */
81
PGSTAT_COUNT_SLRU(flush)
82
83
/* pgstat_count_slru_truncate */
84
PGSTAT_COUNT_SLRU(truncate)
85
86
/*
87
 * Support function for the SQL-callable pgstat* functions. Returns
88
 * a pointer to the slru statistics struct.
89
 */
90
PgStat_SLRUStats *
91
pgstat_fetch_slru(void)
92
0
{
93
0
  pgstat_snapshot_fixed(PGSTAT_KIND_SLRU);
94
95
0
  return pgStatLocal.snapshot.slru;
96
0
}
97
98
/*
99
 * Returns SLRU name for an index. The index may be above SLRU_NUM_ELEMENTS,
100
 * in which case this returns NULL. This allows writing code that does not
101
 * know the number of entries in advance.
102
 */
103
const char *
104
pgstat_get_slru_name(int slru_idx)
105
0
{
106
0
  if (slru_idx < 0 || slru_idx >= SLRU_NUM_ELEMENTS)
107
0
    return NULL;
108
109
0
  return slru_names[slru_idx];
110
0
}
111
112
/*
113
 * Determine index of entry for a SLRU with a given name. If there's no exact
114
 * match, returns index of the last "other" entry used for SLRUs defined in
115
 * external projects.
116
 */
117
int
118
pgstat_get_slru_index(const char *name)
119
0
{
120
0
  int     i;
121
122
0
  Assert(name);
123
0
  for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
124
0
  {
125
0
    if (strcmp(slru_names[i], name) == 0)
126
0
      return i;
127
0
  }
128
129
  /* return index of the last entry (which is the "other" one) */
130
0
  return (SLRU_NUM_ELEMENTS - 1);
131
0
}
132
133
/*
134
 * Flush out locally pending SLRU stats entries
135
 *
136
 * If nowait is true, this function returns true if the lock could not be
137
 * acquired. Otherwise return false.
138
 */
139
bool
140
pgstat_slru_flush_cb(bool nowait)
141
0
{
142
0
  PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
143
0
  int     i;
144
145
0
  if (!have_slrustats)
146
0
    return false;
147
148
0
  if (!nowait)
149
0
    LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
150
0
  else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
151
0
    return true;
152
153
0
  for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
154
0
  {
155
0
    PgStat_SLRUStats *sharedent = &stats_shmem->stats[i];
156
0
    PgStat_SLRUStats *pendingent = &pending_SLRUStats[i];
157
158
0
#define SLRU_ACC(fld) sharedent->fld += pendingent->fld
159
0
    SLRU_ACC(blocks_zeroed);
160
0
    SLRU_ACC(blocks_hit);
161
0
    SLRU_ACC(blocks_read);
162
0
    SLRU_ACC(blocks_written);
163
0
    SLRU_ACC(blocks_exists);
164
0
    SLRU_ACC(flush);
165
0
    SLRU_ACC(truncate);
166
0
#undef SLRU_ACC
167
0
  }
168
169
  /* done, clear the pending entry */
170
0
  MemSet(pending_SLRUStats, 0, sizeof(pending_SLRUStats));
171
172
0
  LWLockRelease(&stats_shmem->lock);
173
174
0
  have_slrustats = false;
175
176
0
  return false;
177
0
}
178
179
void
180
pgstat_slru_init_shmem_cb(void *stats)
181
0
{
182
0
  PgStatShared_SLRU *stats_shmem = (PgStatShared_SLRU *) stats;
183
184
0
  LWLockInitialize(&stats_shmem->lock, LWTRANCHE_PGSTATS_DATA);
185
0
}
186
187
void
188
pgstat_slru_reset_all_cb(TimestampTz ts)
189
0
{
190
0
  for (int i = 0; i < SLRU_NUM_ELEMENTS; i++)
191
0
    pgstat_reset_slru_counter_internal(i, ts);
192
0
}
193
194
void
195
pgstat_slru_snapshot_cb(void)
196
0
{
197
0
  PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
198
199
0
  LWLockAcquire(&stats_shmem->lock, LW_SHARED);
200
201
0
  memcpy(pgStatLocal.snapshot.slru, &stats_shmem->stats,
202
0
       sizeof(stats_shmem->stats));
203
204
0
  LWLockRelease(&stats_shmem->lock);
205
0
}
206
207
/*
208
 * Returns pointer to entry with counters for given SLRU (based on the name
209
 * stored in SlruCtl as lwlock tranche name).
210
 */
211
static inline PgStat_SLRUStats *
212
get_slru_entry(int slru_idx)
213
0
{
214
0
  pgstat_assert_is_up();
215
216
  /*
217
   * The postmaster should never register any SLRU statistics counts; if it
218
   * did, the counts would be duplicated into child processes via fork().
219
   */
220
0
  Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
221
222
0
  Assert((slru_idx >= 0) && (slru_idx < SLRU_NUM_ELEMENTS));
223
224
0
  have_slrustats = true;
225
0
  pgstat_report_fixed = true;
226
227
0
  return &pending_SLRUStats[slru_idx];
228
0
}
229
230
static void
231
pgstat_reset_slru_counter_internal(int index, TimestampTz ts)
232
0
{
233
0
  PgStatShared_SLRU *stats_shmem = &pgStatLocal.shmem->slru;
234
235
0
  LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
236
237
0
  memset(&stats_shmem->stats[index], 0, sizeof(PgStat_SLRUStats));
238
0
  stats_shmem->stats[index].stat_reset_timestamp = ts;
239
240
0
  LWLockRelease(&stats_shmem->lock);
241
0
}