PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pgstat_database.c
Go to the documentation of this file.
1/* -------------------------------------------------------------------------
2 *
3 * pgstat_database.c
4 * Implementation of database statistics.
5 *
6 * This file contains the implementation of database 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_database.c
15 * -------------------------------------------------------------------------
16 */
17
18#include "postgres.h"
19
20#include "storage/standby.h"
22#include "utils/timestamp.h"
23
24
25static bool pgstat_should_report_connstat(void);
26
27
33
34
35static int pgStatXactCommit = 0;
36static int pgStatXactRollback = 0;
38
39
40/*
41 * Remove entry for the database being dropped.
42 */
43void
48
49/*
50 * Called from autovacuum.c to report startup of an autovacuum process.
51 * We are called before InitPostgres is done, so can't rely on MyDatabaseId;
52 * the db OID must be passed in, instead.
53 */
54void
56{
57 PgStat_EntryRef *entry_ref;
59
60 /* can't get here in single user mode */
62
63 /*
64 * End-of-vacuum is reported instantly. Report the start the same way for
65 * consistency. Vacuum doesn't run frequently and is a long-lasting
66 * operation so it doesn't matter if we get blocked here a little.
67 */
69 dboid, InvalidOid, false);
70
72 dbentry->stats.last_autovac_time = GetCurrentTimestamp();
73
74 pgstat_unlock_entry(entry_ref);
75}
76
77/*
78 * Report a Hot Standby recovery conflict.
79 */
80void
82{
84
87 return;
88
90
91 switch ((RecoveryConflictReason) reason)
92 {
94
95 /*
96 * Since we drop the information about the database as soon as it
97 * replicates, there is no point in counting these conflicts.
98 */
99 break;
101 dbentry->conflict_tablespace++;
102 break;
104 dbentry->conflict_lock++;
105 break;
107 dbentry->conflict_snapshot++;
108 break;
110 dbentry->conflict_bufferpin++;
111 break;
113 dbentry->conflict_logicalslot++;
114 break;
116 dbentry->conflict_startup_deadlock++;
117 break;
119
120 /*
121 * The difference between RECOVERY_CONFLICT_STARTUP_DEADLOCK and
122 * RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK is merely whether a buffer
123 * pin was part of the deadlock. We use the same counter for both
124 * reasons.
125 */
126 dbentry->conflict_startup_deadlock++;
127 break;
128 }
129}
130
131/*
132 * Report a detected deadlock.
133 */
134void
136{
138
140 return;
141
143 dbent->deadlocks++;
144}
145
146/*
147 * Allow this backend to later report checksum failures for dboid, even if in
148 * a critical section at the time of the report.
149 *
150 * Without this function having been called first, the backend might need to
151 * allocate an EntryRef or might need to map in DSM segments. Neither should
152 * happen in a critical section.
153 */
154void
156{
158
159 /*
160 * Just need to ensure this backend has an entry ref for the database.
161 * That will allows us to report checksum failures without e.g. needing to
162 * map in DSM segments.
163 */
165 true, NULL);
166}
167
168/*
169 * Report one or more checksum failures.
170 *
171 * To be allowed to report checksum failures in critical sections, we require
172 * pgstat_prepare_report_checksum_failure() to have been called before this
173 * function is called.
174 */
175void
177{
178 PgStat_EntryRef *entry_ref;
180
182 return;
183
184 /*
185 * Update the shared stats directly - checksum failures should never be
186 * common enough for that to be a problem. Note that we pass create=false
187 * here, as we want to be sure to not require memory allocations, so this
188 * can be called in critical sections.
189 */
191 false, NULL);
192
193 /*
194 * Should always have been created by
195 * pgstat_prepare_report_checksum_failure().
196 *
197 * When not using assertions, we don't want to crash should something have
198 * gone wrong, so just return.
199 */
200 Assert(entry_ref);
201 if (!entry_ref)
202 {
203 elog(WARNING, "could not report %d checksum failures for database %u",
204 failurecount, dboid);
205 return;
206 }
207
208 (void) pgstat_lock_entry(entry_ref, false);
209
211 sharedent->stats.checksum_failures += failurecount;
212 sharedent->stats.last_checksum_failure = GetCurrentTimestamp();
213
214 pgstat_unlock_entry(entry_ref);
215}
216
217/*
218 * Report creation of temporary file.
219 */
220void
222{
224
226 return;
227
229 dbent->temp_bytes += filesize;
230 dbent->temp_files++;
231}
232
233/*
234 * Notify stats system of a new connection.
235 */
236void
249
250/*
251 * Notify the stats system of a disconnect.
252 */
253void
255{
257
259 return;
260
262
263 switch (pgStatSessionEndCause)
264 {
267 /* we don't collect these */
268 break;
270 dbentry->sessions_abandoned++;
271 break;
272 case DISCONNECT_FATAL:
273 dbentry->sessions_fatal++;
274 break;
276 dbentry->sessions_killed++;
277 break;
278 }
279}
280
281/*
282 * Support function for the SQL-callable pgstat* functions. Returns
283 * the collected statistics for one database or NULL. NULL doesn't mean
284 * that the database doesn't exist, just that there are no statistics, so the
285 * caller is better off to report ZERO instead.
286 */
293
294void
296{
297 /* Don't count parallel worker transaction stats */
298 if (!parallel)
299 {
300 /*
301 * Count transaction commit or abort. (We use counters, not just
302 * bools, in case the reporting message isn't sent right away.)
303 */
304 if (isCommit)
306 else
308 }
309}
310
311/*
312 * Notify the stats system about parallel worker information.
313 */
314void
327
328/*
329 * Subroutine for pgstat_report_stat(): Handle xact commit/rollback and I/O
330 * timings.
331 */
332void
334{
336
337 /*
338 * If not connected to a database yet, don't attribute time to "shared
339 * state" (InvalidOid is used to track stats for shared relations, etc.).
340 */
342 return;
343
345
346 /*
347 * Accumulate xact commit/rollback and I/O timings to stats entry of the
348 * current database.
349 */
350 dbentry->xact_commit += pgStatXactCommit;
351 dbentry->xact_rollback += pgStatXactRollback;
352 dbentry->blk_read_time += pgStatBlockReadTime;
353 dbentry->blk_write_time += pgStatBlockWriteTime;
354
356 {
357 long secs;
358 int usecs;
359
360 /*
361 * pgLastSessionReportTime is initialized to MyStartTimestamp by
362 * pgstat_report_connect().
363 */
366 dbentry->session_time += (PgStat_Counter) secs * 1000000 + usecs;
367 dbentry->active_time += pgStatActiveTime;
368 dbentry->idle_in_transaction_time += pgStatTransactionIdleTime;
369 }
370
377}
378
379/*
380 * We report session statistics only for normal backend processes. Parallel
381 * workers run in parallel, so they don't contribute to session times, even
382 * though they use CPU time. Walsender processes could be considered here,
383 * but they have different session characteristics from normal backends (for
384 * example, they are always "active"), so they would skew session statistics.
385 */
386static bool
391
392/*
393 * Find or create a local PgStat_StatDBEntry entry for dboid.
394 */
397{
398 PgStat_EntryRef *entry_ref;
399
400 /*
401 * This should not report stats on database objects before having
402 * connected to a database.
403 */
405
407 NULL);
408
409 return entry_ref->pending;
410}
411
412/*
413 * Reset the database's reset timestamp, without resetting the contents of the
414 * database stats.
415 */
416void
430
431/*
432 * Flush out pending stats for the entry
433 *
434 * If nowait is true and the lock could not be immediately acquired, returns
435 * false without flushing the entry. Otherwise returns true.
436 */
437bool
439{
442
443 pendingent = (PgStat_StatDBEntry *) entry_ref->pending;
445
446 if (!pgstat_lock_entry(entry_ref, nowait))
447 return false;
448
449#define PGSTAT_ACCUM_DBCOUNT(item) \
450 (sharedent)->stats.item += (pendingent)->item
451
452 PGSTAT_ACCUM_DBCOUNT(xact_commit);
453 PGSTAT_ACCUM_DBCOUNT(xact_rollback);
454 PGSTAT_ACCUM_DBCOUNT(blocks_fetched);
455 PGSTAT_ACCUM_DBCOUNT(blocks_hit);
456
457 PGSTAT_ACCUM_DBCOUNT(tuples_returned);
458 PGSTAT_ACCUM_DBCOUNT(tuples_fetched);
459 PGSTAT_ACCUM_DBCOUNT(tuples_inserted);
460 PGSTAT_ACCUM_DBCOUNT(tuples_updated);
461 PGSTAT_ACCUM_DBCOUNT(tuples_deleted);
462
463 /* last_autovac_time is reported immediately */
464 Assert(pendingent->last_autovac_time == 0);
465
466 PGSTAT_ACCUM_DBCOUNT(conflict_tablespace);
467 PGSTAT_ACCUM_DBCOUNT(conflict_lock);
468 PGSTAT_ACCUM_DBCOUNT(conflict_snapshot);
469 PGSTAT_ACCUM_DBCOUNT(conflict_logicalslot);
470 PGSTAT_ACCUM_DBCOUNT(conflict_bufferpin);
471 PGSTAT_ACCUM_DBCOUNT(conflict_startup_deadlock);
472
473 PGSTAT_ACCUM_DBCOUNT(temp_bytes);
474 PGSTAT_ACCUM_DBCOUNT(temp_files);
475 PGSTAT_ACCUM_DBCOUNT(deadlocks);
476
477 /* checksum failures are reported immediately */
478 Assert(pendingent->checksum_failures == 0);
479 Assert(pendingent->last_checksum_failure == 0);
480
481 PGSTAT_ACCUM_DBCOUNT(blk_read_time);
482 PGSTAT_ACCUM_DBCOUNT(blk_write_time);
483
484 PGSTAT_ACCUM_DBCOUNT(sessions);
485 PGSTAT_ACCUM_DBCOUNT(session_time);
486 PGSTAT_ACCUM_DBCOUNT(active_time);
487 PGSTAT_ACCUM_DBCOUNT(idle_in_transaction_time);
488 PGSTAT_ACCUM_DBCOUNT(sessions_abandoned);
489 PGSTAT_ACCUM_DBCOUNT(sessions_fatal);
490 PGSTAT_ACCUM_DBCOUNT(sessions_killed);
491 PGSTAT_ACCUM_DBCOUNT(parallel_workers_to_launch);
492 PGSTAT_ACCUM_DBCOUNT(parallel_workers_launched);
493#undef PGSTAT_ACCUM_DBCOUNT
494
495 pgstat_unlock_entry(entry_ref);
496
497 memset(pendingent, 0, sizeof(*pendingent));
498
499 return true;
500}
501
502void
504{
505 ((PgStatShared_Database *) header)->stats.stat_reset_timestamp = ts;
506}
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition timestamp.c:1721
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1645
#define Assert(condition)
Definition c.h:885
#define OidIsValid(objectId)
Definition c.h:800
int64 TimestampTz
Definition timestamp.h:39
#define WARNING
Definition elog.h:36
#define elog(elevel,...)
Definition elog.h:226
bool IsUnderPostmaster
Definition globals.c:120
volatile uint32 CritSectionCount
Definition globals.c:45
TimestampTz MyStartTimestamp
Definition globals.c:49
Oid MyDatabaseId
Definition globals.c:94
@ B_BACKEND
Definition miscadmin.h:342
BackendType MyBackendType
Definition miscinit.c:64
PgStat_EntryRef * pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *created_entry)
Definition pgstat.c:1275
bool pgstat_track_counts
Definition pgstat.c:203
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition pgstat.c:944
SessionEndType
Definition pgstat.h:59
@ DISCONNECT_NOT_YET
Definition pgstat.h:60
@ DISCONNECT_FATAL
Definition pgstat.h:63
@ DISCONNECT_KILLED
Definition pgstat.h:64
@ DISCONNECT_CLIENT_EOF
Definition pgstat.h:62
@ DISCONNECT_NORMAL
Definition pgstat.h:61
int64 PgStat_Counter
Definition pgstat.h:71
static bool pgstat_should_report_connstat(void)
void pgstat_update_parallel_workers_stats(PgStat_Counter workers_to_launch, PgStat_Counter workers_launched)
PgStat_Counter pgStatActiveTime
PgStat_Counter pgStatBlockReadTime
void pgstat_report_autovac(Oid dboid)
void pgstat_database_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
void pgstat_prepare_report_checksum_failure(Oid dboid)
void pgstat_report_connect(Oid dboid)
PgStat_Counter pgStatBlockWriteTime
void pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount)
static PgStat_Counter pgLastSessionReportTime
static int pgStatXactCommit
void AtEOXact_PgStat_Database(bool isCommit, bool parallel)
PgStat_StatDBEntry * pgstat_prep_database_pending(Oid dboid)
void pgstat_report_deadlock(void)
void pgstat_report_recovery_conflict(int reason)
void pgstat_update_dbstats(TimestampTz ts)
PgStat_Counter pgStatTransactionIdleTime
SessionEndType pgStatSessionEndCause
void pgstat_drop_database(Oid databaseid)
void pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts)
void pgstat_report_disconnect(Oid dboid)
#define PGSTAT_ACCUM_DBCOUNT(item)
static int pgStatXactRollback
bool pgstat_database_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
PgStat_StatDBEntry * pgstat_fetch_stat_dbentry(Oid dboid)
void pgstat_report_tempfile(size_t filesize)
#define PGSTAT_KIND_DATABASE
Definition pgstat_kind.h:27
PgStat_EntryRef * pgstat_get_entry_ref(PgStat_Kind kind, Oid dboid, uint64 objid, bool create, bool *created_entry)
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait)
PgStat_EntryRef * pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, uint64 objid, bool nowait)
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
#define InvalidOid
unsigned int Oid
static int fb(int x)
RecoveryConflictReason
Definition standby.h:29
@ RECOVERY_CONFLICT_TABLESPACE
Definition standby.h:34
@ RECOVERY_CONFLICT_SNAPSHOT
Definition standby.h:40
@ RECOVERY_CONFLICT_LOCK
Definition standby.h:37
@ RECOVERY_CONFLICT_DATABASE
Definition standby.h:31
@ RECOVERY_CONFLICT_STARTUP_DEADLOCK
Definition standby.h:53
@ RECOVERY_CONFLICT_BUFFERPIN
Definition standby.h:46
@ RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK
Definition standby.h:61
@ RECOVERY_CONFLICT_LOGICALSLOT
Definition standby.h:43
PgStatShared_Common * shared_stats