LCOV - code coverage report
Current view: top level - src/backend/utils/activity - pgstat_database.c (source / functions) Hit Total Coverage
Test: PostgreSQL 16devel Lines: 143 151 94.7 %
Date: 2022-08-17 05:10:35 Functions: 16 17 94.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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-2022, 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 "utils/pgstat_internal.h"
      21             : #include "utils/timestamp.h"
      22             : #include "storage/procsignal.h"
      23             : 
      24             : 
      25             : static bool pgstat_should_report_connstat(void);
      26             : 
      27             : 
      28             : PgStat_Counter pgStatBlockReadTime = 0;
      29             : PgStat_Counter pgStatBlockWriteTime = 0;
      30             : PgStat_Counter pgStatActiveTime = 0;
      31             : PgStat_Counter pgStatTransactionIdleTime = 0;
      32             : SessionEndType pgStatSessionEndCause = DISCONNECT_NORMAL;
      33             : 
      34             : 
      35             : static int  pgStatXactCommit = 0;
      36             : static int  pgStatXactRollback = 0;
      37             : static PgStat_Counter pgLastSessionReportTime = 0;
      38             : 
      39             : 
      40             : /*
      41             :  * Remove entry for the database being dropped.
      42             :  */
      43             : void
      44          38 : pgstat_drop_database(Oid databaseid)
      45             : {
      46          38 :     pgstat_drop_transactional(PGSTAT_KIND_DATABASE, databaseid, InvalidOid);
      47          38 : }
      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             :  */
      54             : void
      55          14 : pgstat_report_autovac(Oid dboid)
      56             : {
      57             :     PgStat_EntryRef *entry_ref;
      58             :     PgStatShared_Database *dbentry;
      59             : 
      60             :     /* can't get here in single user mode */
      61             :     Assert(IsUnderPostmaster);
      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             :      */
      68          14 :     entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE,
      69             :                                             dboid, InvalidOid, false);
      70             : 
      71          14 :     dbentry = (PgStatShared_Database *) entry_ref->shared_stats;
      72          14 :     dbentry->stats.last_autovac_time = GetCurrentTimestamp();
      73             : 
      74          14 :     pgstat_unlock_entry(entry_ref);
      75          14 : }
      76             : 
      77             : /*
      78             :  * Report a Hot Standby recovery conflict.
      79             :  */
      80             : void
      81          12 : pgstat_report_recovery_conflict(int reason)
      82             : {
      83             :     PgStat_StatDBEntry *dbentry;
      84             : 
      85             :     Assert(IsUnderPostmaster);
      86          12 :     if (!pgstat_track_counts)
      87           0 :         return;
      88             : 
      89          12 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
      90             : 
      91          12 :     switch (reason)
      92             :     {
      93           2 :         case PROCSIG_RECOVERY_CONFLICT_DATABASE:
      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           2 :             break;
     100           2 :         case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
     101           2 :             dbentry->n_conflict_tablespace++;
     102           2 :             break;
     103           2 :         case PROCSIG_RECOVERY_CONFLICT_LOCK:
     104           2 :             dbentry->n_conflict_lock++;
     105           2 :             break;
     106           2 :         case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
     107           2 :             dbentry->n_conflict_snapshot++;
     108           2 :             break;
     109           2 :         case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
     110           2 :             dbentry->n_conflict_bufferpin++;
     111           2 :             break;
     112           2 :         case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
     113           2 :             dbentry->n_conflict_startup_deadlock++;
     114           2 :             break;
     115             :     }
     116             : }
     117             : 
     118             : /*
     119             :  * Report a detected deadlock.
     120             :  */
     121             : void
     122           6 : pgstat_report_deadlock(void)
     123             : {
     124             :     PgStat_StatDBEntry *dbent;
     125             : 
     126           6 :     if (!pgstat_track_counts)
     127           0 :         return;
     128             : 
     129           6 :     dbent = pgstat_prep_database_pending(MyDatabaseId);
     130           6 :     dbent->n_deadlocks++;
     131             : }
     132             : 
     133             : /*
     134             :  * Report one or more checksum failures.
     135             :  */
     136             : void
     137           4 : pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount)
     138             : {
     139             :     PgStat_EntryRef *entry_ref;
     140             :     PgStatShared_Database *sharedent;
     141             : 
     142           4 :     if (!pgstat_track_counts)
     143           0 :         return;
     144             : 
     145             :     /*
     146             :      * Update the shared stats directly - checksum failures should never be
     147             :      * common enough for that to be a problem.
     148             :      */
     149             :     entry_ref =
     150           4 :         pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, dboid, InvalidOid, false);
     151             : 
     152           4 :     sharedent = (PgStatShared_Database *) entry_ref->shared_stats;
     153           4 :     sharedent->stats.n_checksum_failures += failurecount;
     154           4 :     sharedent->stats.last_checksum_failure = GetCurrentTimestamp();
     155             : 
     156           4 :     pgstat_unlock_entry(entry_ref);
     157             : }
     158             : 
     159             : /*
     160             :  * Report one checksum failure in the current database.
     161             :  */
     162             : void
     163           0 : pgstat_report_checksum_failure(void)
     164             : {
     165           0 :     pgstat_report_checksum_failures_in_db(MyDatabaseId, 1);
     166           0 : }
     167             : 
     168             : /*
     169             :  * Report creation of temporary file.
     170             :  */
     171             : void
     172        5240 : pgstat_report_tempfile(size_t filesize)
     173             : {
     174             :     PgStat_StatDBEntry *dbent;
     175             : 
     176        5240 :     if (!pgstat_track_counts)
     177           0 :         return;
     178             : 
     179        5240 :     dbent = pgstat_prep_database_pending(MyDatabaseId);
     180        5240 :     dbent->n_temp_bytes += filesize;
     181        5240 :     dbent->n_temp_files++;
     182             : }
     183             : 
     184             : /*
     185             :  * Notify stats system of a new connection.
     186             :  */
     187             : void
     188       15998 : pgstat_report_connect(Oid dboid)
     189             : {
     190             :     PgStat_StatDBEntry *dbentry;
     191             : 
     192       15998 :     if (!pgstat_should_report_connstat())
     193        1932 :         return;
     194             : 
     195       14066 :     pgLastSessionReportTime = MyStartTimestamp;
     196             : 
     197       14066 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
     198       14066 :     dbentry->n_sessions++;
     199             : }
     200             : 
     201             : /*
     202             :  * Notify the stats system of a disconnect.
     203             :  */
     204             : void
     205       19016 : pgstat_report_disconnect(Oid dboid)
     206             : {
     207             :     PgStat_StatDBEntry *dbentry;
     208             : 
     209       19016 :     if (!pgstat_should_report_connstat())
     210        4950 :         return;
     211             : 
     212       14066 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
     213             : 
     214       14066 :     switch (pgStatSessionEndCause)
     215             :     {
     216       13994 :         case DISCONNECT_NOT_YET:
     217             :         case DISCONNECT_NORMAL:
     218             :             /* we don't collect these */
     219       13994 :             break;
     220          40 :         case DISCONNECT_CLIENT_EOF:
     221          40 :             dbentry->n_sessions_abandoned++;
     222          40 :             break;
     223          10 :         case DISCONNECT_FATAL:
     224          10 :             dbentry->n_sessions_fatal++;
     225          10 :             break;
     226          22 :         case DISCONNECT_KILLED:
     227          22 :             dbentry->n_sessions_killed++;
     228          22 :             break;
     229             :     }
     230             : }
     231             : 
     232             : /*
     233             :  * Support function for the SQL-callable pgstat* functions. Returns
     234             :  * the collected statistics for one database or NULL. NULL doesn't mean
     235             :  * that the database doesn't exist, just that there are no statistics, so the
     236             :  * caller is better off to report ZERO instead.
     237             :  */
     238             : PgStat_StatDBEntry *
     239        2392 : pgstat_fetch_stat_dbentry(Oid dboid)
     240             : {
     241        2392 :     return (PgStat_StatDBEntry *)
     242        2392 :         pgstat_fetch_entry(PGSTAT_KIND_DATABASE, dboid, InvalidOid);
     243             : }
     244             : 
     245             : void
     246      905550 : AtEOXact_PgStat_Database(bool isCommit, bool parallel)
     247             : {
     248             :     /* Don't count parallel worker transaction stats */
     249      905550 :     if (!parallel)
     250             :     {
     251             :         /*
     252             :          * Count transaction commit or abort.  (We use counters, not just
     253             :          * bools, in case the reporting message isn't sent right away.)
     254             :          */
     255      902970 :         if (isCommit)
     256      865054 :             pgStatXactCommit++;
     257             :         else
     258       37916 :             pgStatXactRollback++;
     259             :     }
     260      905550 : }
     261             : 
     262             : /*
     263             :  * Subroutine for pgstat_report_stat(): Handle xact commit/rollback and I/O
     264             :  * timings.
     265             :  */
     266             : void
     267       41028 : pgstat_update_dbstats(TimestampTz ts)
     268             : {
     269             :     PgStat_StatDBEntry *dbentry;
     270             : 
     271       41028 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
     272             : 
     273             :     /*
     274             :      * Accumulate xact commit/rollback and I/O timings to stats entry of the
     275             :      * current database.
     276             :      */
     277       41028 :     dbentry->n_xact_commit += pgStatXactCommit;
     278       41028 :     dbentry->n_xact_rollback += pgStatXactRollback;
     279       41028 :     dbentry->n_block_read_time += pgStatBlockReadTime;
     280       41028 :     dbentry->n_block_write_time += pgStatBlockWriteTime;
     281             : 
     282       41028 :     if (pgstat_should_report_connstat())
     283             :     {
     284             :         long        secs;
     285             :         int         usecs;
     286             : 
     287             :         /*
     288             :          * pgLastSessionReportTime is initialized to MyStartTimestamp by
     289             :          * pgstat_report_connect().
     290             :          */
     291       29380 :         TimestampDifference(pgLastSessionReportTime, ts, &secs, &usecs);
     292       29380 :         pgLastSessionReportTime = ts;
     293       29380 :         dbentry->total_session_time += (PgStat_Counter) secs * 1000000 + usecs;
     294       29380 :         dbentry->total_active_time += pgStatActiveTime;
     295       29380 :         dbentry->total_idle_in_xact_time += pgStatTransactionIdleTime;
     296             :     }
     297             : 
     298       41028 :     pgStatXactCommit = 0;
     299       41028 :     pgStatXactRollback = 0;
     300       41028 :     pgStatBlockReadTime = 0;
     301       41028 :     pgStatBlockWriteTime = 0;
     302       41028 :     pgStatActiveTime = 0;
     303       41028 :     pgStatTransactionIdleTime = 0;
     304       41028 : }
     305             : 
     306             : /*
     307             :  * We report session statistics only for normal backend processes.  Parallel
     308             :  * workers run in parallel, so they don't contribute to session times, even
     309             :  * though they use CPU time. Walsender processes could be considered here,
     310             :  * but they have different session characteristics from normal backends (for
     311             :  * example, they are always "active"), so they would skew session statistics.
     312             :  */
     313             : static bool
     314       76042 : pgstat_should_report_connstat(void)
     315             : {
     316       76042 :     return MyBackendType == B_BACKEND;
     317             : }
     318             : 
     319             : /*
     320             :  * Find or create a local PgStat_StatDBEntry entry for dboid.
     321             :  */
     322             : PgStat_StatDBEntry *
     323     1243578 : pgstat_prep_database_pending(Oid dboid)
     324             : {
     325             :     PgStat_EntryRef *entry_ref;
     326             : 
     327     1243578 :     entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_DATABASE, dboid, InvalidOid,
     328             :                                           NULL);
     329             : 
     330     1243578 :     return entry_ref->pending;
     331             : }
     332             : 
     333             : /*
     334             :  * Reset the database's reset timestamp, without resetting the contents of the
     335             :  * database stats.
     336             :  */
     337             : void
     338           4 : pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts)
     339             : {
     340             :     PgStat_EntryRef *dbref;
     341             :     PgStatShared_Database *dbentry;
     342             : 
     343           4 :     dbref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, MyDatabaseId, InvalidOid,
     344             :                                         false);
     345             : 
     346           4 :     dbentry = (PgStatShared_Database *) dbref->shared_stats;
     347           4 :     dbentry->stats.stat_reset_timestamp = ts;
     348             : 
     349           4 :     pgstat_unlock_entry(dbref);
     350           4 : }
     351             : 
     352             : /*
     353             :  * Flush out pending stats for the entry
     354             :  *
     355             :  * If nowait is true, this function returns false if lock could not
     356             :  * immediately acquired, otherwise true is returned.
     357             :  */
     358             : bool
     359       70422 : pgstat_database_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
     360             : {
     361             :     PgStatShared_Database *sharedent;
     362             :     PgStat_StatDBEntry *pendingent;
     363             : 
     364       70422 :     pendingent = (PgStat_StatDBEntry *) entry_ref->pending;
     365       70422 :     sharedent = (PgStatShared_Database *) entry_ref->shared_stats;
     366             : 
     367       70422 :     if (!pgstat_lock_entry(entry_ref, nowait))
     368           0 :         return false;
     369             : 
     370             : #define PGSTAT_ACCUM_DBCOUNT(item)      \
     371             :     (sharedent)->stats.item += (pendingent)->item
     372             : 
     373       70422 :     PGSTAT_ACCUM_DBCOUNT(n_xact_commit);
     374       70422 :     PGSTAT_ACCUM_DBCOUNT(n_xact_rollback);
     375       70422 :     PGSTAT_ACCUM_DBCOUNT(n_blocks_fetched);
     376       70422 :     PGSTAT_ACCUM_DBCOUNT(n_blocks_hit);
     377             : 
     378       70422 :     PGSTAT_ACCUM_DBCOUNT(n_tuples_returned);
     379       70422 :     PGSTAT_ACCUM_DBCOUNT(n_tuples_fetched);
     380       70422 :     PGSTAT_ACCUM_DBCOUNT(n_tuples_inserted);
     381       70422 :     PGSTAT_ACCUM_DBCOUNT(n_tuples_updated);
     382       70422 :     PGSTAT_ACCUM_DBCOUNT(n_tuples_deleted);
     383             : 
     384             :     /* last_autovac_time is reported immediately */
     385             :     Assert(pendingent->last_autovac_time == 0);
     386             : 
     387       70422 :     PGSTAT_ACCUM_DBCOUNT(n_conflict_tablespace);
     388       70422 :     PGSTAT_ACCUM_DBCOUNT(n_conflict_lock);
     389       70422 :     PGSTAT_ACCUM_DBCOUNT(n_conflict_snapshot);
     390       70422 :     PGSTAT_ACCUM_DBCOUNT(n_conflict_bufferpin);
     391       70422 :     PGSTAT_ACCUM_DBCOUNT(n_conflict_startup_deadlock);
     392             : 
     393       70422 :     PGSTAT_ACCUM_DBCOUNT(n_temp_bytes);
     394       70422 :     PGSTAT_ACCUM_DBCOUNT(n_temp_files);
     395       70422 :     PGSTAT_ACCUM_DBCOUNT(n_deadlocks);
     396             : 
     397             :     /* checksum failures are reported immediately */
     398             :     Assert(pendingent->n_checksum_failures == 0);
     399             :     Assert(pendingent->last_checksum_failure == 0);
     400             : 
     401       70422 :     PGSTAT_ACCUM_DBCOUNT(n_block_read_time);
     402       70422 :     PGSTAT_ACCUM_DBCOUNT(n_block_write_time);
     403             : 
     404       70422 :     PGSTAT_ACCUM_DBCOUNT(n_sessions);
     405       70422 :     PGSTAT_ACCUM_DBCOUNT(total_session_time);
     406       70422 :     PGSTAT_ACCUM_DBCOUNT(total_active_time);
     407       70422 :     PGSTAT_ACCUM_DBCOUNT(total_idle_in_xact_time);
     408       70422 :     PGSTAT_ACCUM_DBCOUNT(n_sessions_abandoned);
     409       70422 :     PGSTAT_ACCUM_DBCOUNT(n_sessions_fatal);
     410       70422 :     PGSTAT_ACCUM_DBCOUNT(n_sessions_killed);
     411             : #undef PGSTAT_ACCUM_DBCOUNT
     412             : 
     413       70422 :     pgstat_unlock_entry(entry_ref);
     414             : 
     415       70422 :     memset(pendingent, 0, sizeof(*pendingent));
     416             : 
     417       70422 :     return true;
     418             : }
     419             : 
     420             : void
     421          14 : pgstat_database_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
     422             : {
     423          14 :     ((PgStatShared_Database *) header)->stats.stat_reset_timestamp = ts;
     424          14 : }

Generated by: LCOV version 1.14