PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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-2025, 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/procsignal.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
45{
47}
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;
58 PgStatShared_Database *dbentry;
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
71 dbentry = (PgStatShared_Database *) entry_ref->shared_stats;
73
74 pgstat_unlock_entry(entry_ref);
75}
76
77/*
78 * Report a Hot Standby recovery conflict.
79 */
80void
82{
83 PgStat_StatDBEntry *dbentry;
84
87 return;
88
90
91 switch (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;
118 }
119}
120
121/*
122 * Report a detected deadlock.
123 */
124void
126{
127 PgStat_StatDBEntry *dbent;
128
130 return;
131
133 dbent->deadlocks++;
134}
135
136/*
137 * Allow this backend to later report checksum failures for dboid, even if in
138 * a critical section at the time of the report.
139 *
140 * Without this function having been called first, the backend might need to
141 * allocate an EntryRef or might need to map in DSM segments. Neither should
142 * happen in a critical section.
143 */
144void
146{
148
149 /*
150 * Just need to ensure this backend has an entry ref for the database.
151 * That will allows us to report checksum failures without e.g. needing to
152 * map in DSM segments.
153 */
155 true, NULL);
156}
157
158/*
159 * Report one or more checksum failures.
160 *
161 * To be allowed to report checksum failures in critical sections, we require
162 * pgstat_prepare_report_checksum_failure() to have been called before this
163 * function is called.
164 */
165void
167{
168 PgStat_EntryRef *entry_ref;
169 PgStatShared_Database *sharedent;
170
172 return;
173
174 /*
175 * Update the shared stats directly - checksum failures should never be
176 * common enough for that to be a problem. Note that we pass create=false
177 * here, as we want to be sure to not require memory allocations, so this
178 * can be called in critical sections.
179 */
181 false, NULL);
182
183 /*
184 * Should always have been created by
185 * pgstat_prepare_report_checksum_failure().
186 *
187 * When not using assertions, we don't want to crash should something have
188 * gone wrong, so just return.
189 */
190 Assert(entry_ref);
191 if (!entry_ref)
192 {
193 elog(WARNING, "could not report %d conflicts for DB %u",
194 failurecount, dboid);
195 return;
196 }
197
198 (void) pgstat_lock_entry(entry_ref, false);
199
200 sharedent = (PgStatShared_Database *) entry_ref->shared_stats;
201 sharedent->stats.checksum_failures += failurecount;
203
204 pgstat_unlock_entry(entry_ref);
205}
206
207/*
208 * Report creation of temporary file.
209 */
210void
212{
213 PgStat_StatDBEntry *dbent;
214
216 return;
217
219 dbent->temp_bytes += filesize;
220 dbent->temp_files++;
221}
222
223/*
224 * Notify stats system of a new connection.
225 */
226void
228{
229 PgStat_StatDBEntry *dbentry;
230
232 return;
233
235
237 dbentry->sessions++;
238}
239
240/*
241 * Notify the stats system of a disconnect.
242 */
243void
245{
246 PgStat_StatDBEntry *dbentry;
247
249 return;
250
252
253 switch (pgStatSessionEndCause)
254 {
257 /* we don't collect these */
258 break;
260 dbentry->sessions_abandoned++;
261 break;
262 case DISCONNECT_FATAL:
263 dbentry->sessions_fatal++;
264 break;
266 dbentry->sessions_killed++;
267 break;
268 }
269}
270
271/*
272 * Support function for the SQL-callable pgstat* functions. Returns
273 * the collected statistics for one database or NULL. NULL doesn't mean
274 * that the database doesn't exist, just that there are no statistics, so the
275 * caller is better off to report ZERO instead.
276 */
279{
280 return (PgStat_StatDBEntry *)
282}
283
284void
285AtEOXact_PgStat_Database(bool isCommit, bool parallel)
286{
287 /* Don't count parallel worker transaction stats */
288 if (!parallel)
289 {
290 /*
291 * Count transaction commit or abort. (We use counters, not just
292 * bools, in case the reporting message isn't sent right away.)
293 */
294 if (isCommit)
296 else
298 }
299}
300
301/*
302 * Notify the stats system about parallel worker information.
303 */
304void
306 PgStat_Counter workers_launched)
307{
308 PgStat_StatDBEntry *dbentry;
309
311 return;
312
314 dbentry->parallel_workers_to_launch += workers_to_launch;
315 dbentry->parallel_workers_launched += workers_launched;
316}
317
318/*
319 * Subroutine for pgstat_report_stat(): Handle xact commit/rollback and I/O
320 * timings.
321 */
322void
324{
325 PgStat_StatDBEntry *dbentry;
326
327 /*
328 * If not connected to a database yet, don't attribute time to "shared
329 * state" (InvalidOid is used to track stats for shared relations, etc.).
330 */
332 return;
333
335
336 /*
337 * Accumulate xact commit/rollback and I/O timings to stats entry of the
338 * current database.
339 */
340 dbentry->xact_commit += pgStatXactCommit;
344
346 {
347 long secs;
348 int usecs;
349
350 /*
351 * pgLastSessionReportTime is initialized to MyStartTimestamp by
352 * pgstat_report_connect().
353 */
356 dbentry->session_time += (PgStat_Counter) secs * 1000000 + usecs;
357 dbentry->active_time += pgStatActiveTime;
359 }
360
367}
368
369/*
370 * We report session statistics only for normal backend processes. Parallel
371 * workers run in parallel, so they don't contribute to session times, even
372 * though they use CPU time. Walsender processes could be considered here,
373 * but they have different session characteristics from normal backends (for
374 * example, they are always "active"), so they would skew session statistics.
375 */
376static bool
378{
379 return MyBackendType == B_BACKEND;
380}
381
382/*
383 * Find or create a local PgStat_StatDBEntry entry for dboid.
384 */
387{
388 PgStat_EntryRef *entry_ref;
389
390 /*
391 * This should not report stats on database objects before having
392 * connected to a database.
393 */
395
397 NULL);
398
399 return entry_ref->pending;
400}
401
402/*
403 * Reset the database's reset timestamp, without resetting the contents of the
404 * database stats.
405 */
406void
408{
409 PgStat_EntryRef *dbref;
410 PgStatShared_Database *dbentry;
411
413 false);
414
415 dbentry = (PgStatShared_Database *) dbref->shared_stats;
416 dbentry->stats.stat_reset_timestamp = ts;
417
418 pgstat_unlock_entry(dbref);
419}
420
421/*
422 * Flush out pending stats for the entry
423 *
424 * If nowait is true, this function returns false if lock could not
425 * immediately acquired, otherwise true is returned.
426 */
427bool
429{
430 PgStatShared_Database *sharedent;
431 PgStat_StatDBEntry *pendingent;
432
433 pendingent = (PgStat_StatDBEntry *) entry_ref->pending;
434 sharedent = (PgStatShared_Database *) entry_ref->shared_stats;
435
436 if (!pgstat_lock_entry(entry_ref, nowait))
437 return false;
438
439#define PGSTAT_ACCUM_DBCOUNT(item) \
440 (sharedent)->stats.item += (pendingent)->item
441
442 PGSTAT_ACCUM_DBCOUNT(xact_commit);
443 PGSTAT_ACCUM_DBCOUNT(xact_rollback);
444 PGSTAT_ACCUM_DBCOUNT(blocks_fetched);
445 PGSTAT_ACCUM_DBCOUNT(blocks_hit);
446
447 PGSTAT_ACCUM_DBCOUNT(tuples_returned);
448 PGSTAT_ACCUM_DBCOUNT(tuples_fetched);
449 PGSTAT_ACCUM_DBCOUNT(tuples_inserted);
450 PGSTAT_ACCUM_DBCOUNT(tuples_updated);
451 PGSTAT_ACCUM_DBCOUNT(tuples_deleted);
452
453 /* last_autovac_time is reported immediately */
454 Assert(pendingent->last_autovac_time == 0);
455
456 PGSTAT_ACCUM_DBCOUNT(conflict_tablespace);
457 PGSTAT_ACCUM_DBCOUNT(conflict_lock);
458 PGSTAT_ACCUM_DBCOUNT(conflict_snapshot);
459 PGSTAT_ACCUM_DBCOUNT(conflict_logicalslot);
460 PGSTAT_ACCUM_DBCOUNT(conflict_bufferpin);
461 PGSTAT_ACCUM_DBCOUNT(conflict_startup_deadlock);
462
463 PGSTAT_ACCUM_DBCOUNT(temp_bytes);
464 PGSTAT_ACCUM_DBCOUNT(temp_files);
465 PGSTAT_ACCUM_DBCOUNT(deadlocks);
466
467 /* checksum failures are reported immediately */
468 Assert(pendingent->checksum_failures == 0);
469 Assert(pendingent->last_checksum_failure == 0);
470
471 PGSTAT_ACCUM_DBCOUNT(blk_read_time);
472 PGSTAT_ACCUM_DBCOUNT(blk_write_time);
473
474 PGSTAT_ACCUM_DBCOUNT(sessions);
475 PGSTAT_ACCUM_DBCOUNT(session_time);
476 PGSTAT_ACCUM_DBCOUNT(active_time);
477 PGSTAT_ACCUM_DBCOUNT(idle_in_transaction_time);
478 PGSTAT_ACCUM_DBCOUNT(sessions_abandoned);
479 PGSTAT_ACCUM_DBCOUNT(sessions_fatal);
480 PGSTAT_ACCUM_DBCOUNT(sessions_killed);
481 PGSTAT_ACCUM_DBCOUNT(parallel_workers_to_launch);
482 PGSTAT_ACCUM_DBCOUNT(parallel_workers_launched);
483#undef PGSTAT_ACCUM_DBCOUNT
484
485 pgstat_unlock_entry(entry_ref);
486
487 memset(pendingent, 0, sizeof(*pendingent));
488
489 return true;
490}
491
492void
494{
495 ((PgStatShared_Database *) header)->stats.stat_reset_timestamp = ts;
496}
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1721
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
#define OidIsValid(objectId)
Definition: c.h:746
int64 TimestampTz
Definition: timestamp.h:39
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:225
bool IsUnderPostmaster
Definition: globals.c:121
volatile uint32 CritSectionCount
Definition: globals.c:46
TimestampTz MyStartTimestamp
Definition: globals.c:50
Oid MyDatabaseId
Definition: globals.c:95
Assert(PointerIsAligned(start, uint64))
@ 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:1280
bool pgstat_track_counts
Definition: pgstat.c:203
void * pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat.c:946
SessionEndType
Definition: pgstat.h:53
@ DISCONNECT_NOT_YET
Definition: pgstat.h:54
@ DISCONNECT_FATAL
Definition: pgstat.h:57
@ DISCONNECT_KILLED
Definition: pgstat.h:58
@ DISCONNECT_CLIENT_EOF
Definition: pgstat.h:56
@ DISCONNECT_NORMAL
Definition: pgstat.h:55
int64 PgStat_Counter
Definition: pgstat.h:65
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)
Definition: pgstat_shmem.c:444
void pgstat_unlock_entry(PgStat_EntryRef *entry_ref)
Definition: pgstat_shmem.c:684
bool pgstat_lock_entry(PgStat_EntryRef *entry_ref, bool nowait)
Definition: pgstat_shmem.c:654
PgStat_EntryRef * pgstat_get_entry_ref_locked(PgStat_Kind kind, Oid dboid, uint64 objid, bool nowait)
Definition: pgstat_shmem.c:693
void pgstat_drop_transactional(PgStat_Kind kind, Oid dboid, uint64 objid)
Definition: pgstat_xact.c:384
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
@ PROCSIG_RECOVERY_CONFLICT_BUFFERPIN
Definition: procsignal.h:48
@ PROCSIG_RECOVERY_CONFLICT_LOCK
Definition: procsignal.h:45
@ PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT
Definition: procsignal.h:47
@ PROCSIG_RECOVERY_CONFLICT_DATABASE
Definition: procsignal.h:43
@ PROCSIG_RECOVERY_CONFLICT_SNAPSHOT
Definition: procsignal.h:46
@ PROCSIG_RECOVERY_CONFLICT_TABLESPACE
Definition: procsignal.h:44
@ PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK
Definition: procsignal.h:49
PgStat_StatDBEntry stats
PgStatShared_Common * shared_stats
PgStat_Counter blk_write_time
Definition: pgstat.h:366
PgStat_Counter xact_rollback
Definition: pgstat.h:345
PgStat_Counter conflict_startup_deadlock
Definition: pgstat.h:359
PgStat_Counter conflict_lock
Definition: pgstat.h:355
PgStat_Counter parallel_workers_to_launch
Definition: pgstat.h:374
TimestampTz stat_reset_timestamp
Definition: pgstat.h:377
PgStat_Counter conflict_snapshot
Definition: pgstat.h:356
PgStat_Counter sessions_fatal
Definition: pgstat.h:372
TimestampTz last_checksum_failure
Definition: pgstat.h:364
PgStat_Counter blk_read_time
Definition: pgstat.h:365
PgStat_Counter parallel_workers_launched
Definition: pgstat.h:375
PgStat_Counter xact_commit
Definition: pgstat.h:344
TimestampTz last_autovac_time
Definition: pgstat.h:353
PgStat_Counter deadlocks
Definition: pgstat.h:362
PgStat_Counter temp_bytes
Definition: pgstat.h:361
PgStat_Counter session_time
Definition: pgstat.h:368
PgStat_Counter temp_files
Definition: pgstat.h:360
PgStat_Counter sessions_abandoned
Definition: pgstat.h:371
PgStat_Counter sessions
Definition: pgstat.h:367
PgStat_Counter active_time
Definition: pgstat.h:369
PgStat_Counter conflict_bufferpin
Definition: pgstat.h:358
PgStat_Counter idle_in_transaction_time
Definition: pgstat.h:370
PgStat_Counter conflict_logicalslot
Definition: pgstat.h:357
PgStat_Counter sessions_killed
Definition: pgstat.h:373
PgStat_Counter checksum_failures
Definition: pgstat.h:363
PgStat_Counter conflict_tablespace
Definition: pgstat.h:354