LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat_database.c (source / functions) Coverage Total Hit UIC UBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 95.6 % 160 153 5 2 44 51 58 3 65 2 30
Current Date: 2023-04-08 15:15:32 Functions: 94.1 % 17 16 1 13 1 2 1 13
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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-2023, 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 CBC          20 : pgstat_drop_database(Oid databaseid)
      45                 : {
      46              20 :     pgstat_drop_transactional(PGSTAT_KIND_DATABASE, databaseid, InvalidOid);
      47              20 : }
      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              16 : 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              16 :     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              16 :     entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE,
      69                 :                                             dboid, InvalidOid, false);
      70                 : 
      71              16 :     dbentry = (PgStatShared_Database *) entry_ref->shared_stats;
      72              16 :     dbentry->stats.last_autovac_time = GetCurrentTimestamp();
      73                 : 
      74              16 :     pgstat_unlock_entry(entry_ref);
      75              16 : }
      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              12 :     Assert(IsUnderPostmaster);
      86              12 :     if (!pgstat_track_counts)
      87 UBC           0 :         return;
      88                 : 
      89 CBC          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               1 :         case PROCSIG_RECOVERY_CONFLICT_TABLESPACE:
     101 GNC           1 :             dbentry->conflict_tablespace++;
     102 CBC           1 :             break;
     103               1 :         case PROCSIG_RECOVERY_CONFLICT_LOCK:
     104 GNC           1 :             dbentry->conflict_lock++;
     105 CBC           1 :             break;
     106               1 :         case PROCSIG_RECOVERY_CONFLICT_SNAPSHOT:
     107 GNC           1 :             dbentry->conflict_snapshot++;
     108 CBC           1 :             break;
     109               1 :         case PROCSIG_RECOVERY_CONFLICT_BUFFERPIN:
     110 GNC           1 :             dbentry->conflict_bufferpin++;
     111               1 :             break;
     112               5 :         case PROCSIG_RECOVERY_CONFLICT_LOGICALSLOT:
     113               5 :             dbentry->conflict_logicalslot++;
     114 CBC           5 :             break;
     115               1 :         case PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK:
     116 GNC           1 :             dbentry->conflict_startup_deadlock++;
     117 CBC           1 :             break;
     118 ECB             :     }
     119                 : }
     120                 : 
     121                 : /*
     122                 :  * Report a detected deadlock.
     123                 :  */
     124                 : void
     125 GIC           5 : pgstat_report_deadlock(void)
     126                 : {
     127                 :     PgStat_StatDBEntry *dbent;
     128 ECB             : 
     129 GIC           5 :     if (!pgstat_track_counts)
     130 UIC           0 :         return;
     131                 : 
     132 CBC           5 :     dbent = pgstat_prep_database_pending(MyDatabaseId);
     133 GNC           5 :     dbent->deadlocks++;
     134                 : }
     135 ECB             : 
     136                 : /*
     137                 :  * Report one or more checksum failures.
     138                 :  */
     139                 : void
     140 GIC           2 : pgstat_report_checksum_failures_in_db(Oid dboid, int failurecount)
     141                 : {
     142                 :     PgStat_EntryRef *entry_ref;
     143 ECB             :     PgStatShared_Database *sharedent;
     144                 : 
     145 GIC           2 :     if (!pgstat_track_counts)
     146 UIC           0 :         return;
     147                 : 
     148 ECB             :     /*
     149 EUB             :      * Update the shared stats directly - checksum failures should never be
     150                 :      * common enough for that to be a problem.
     151                 :      */
     152                 :     entry_ref =
     153 GIC           2 :         pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, dboid, InvalidOid, false);
     154                 : 
     155               2 :     sharedent = (PgStatShared_Database *) entry_ref->shared_stats;
     156 GNC           2 :     sharedent->stats.checksum_failures += failurecount;
     157 GIC           2 :     sharedent->stats.last_checksum_failure = GetCurrentTimestamp();
     158 ECB             : 
     159 CBC           2 :     pgstat_unlock_entry(entry_ref);
     160 ECB             : }
     161                 : 
     162                 : /*
     163                 :  * Report one checksum failure in the current database.
     164                 :  */
     165                 : void
     166 UIC           0 : pgstat_report_checksum_failure(void)
     167                 : {
     168               0 :     pgstat_report_checksum_failures_in_db(MyDatabaseId, 1);
     169 UBC           0 : }
     170                 : 
     171 EUB             : /*
     172                 :  * Report creation of temporary file.
     173                 :  */
     174                 : void
     175 GIC        3222 : pgstat_report_tempfile(size_t filesize)
     176                 : {
     177                 :     PgStat_StatDBEntry *dbent;
     178 ECB             : 
     179 GIC        3222 :     if (!pgstat_track_counts)
     180 UIC           0 :         return;
     181                 : 
     182 CBC        3222 :     dbent = pgstat_prep_database_pending(MyDatabaseId);
     183 GNC        3222 :     dbent->temp_bytes += filesize;
     184            3222 :     dbent->temp_files++;
     185 ECB             : }
     186                 : 
     187                 : /*
     188                 :  * Notify stats system of a new connection.
     189                 :  */
     190                 : void
     191 GIC        8866 : pgstat_report_connect(Oid dboid)
     192                 : {
     193                 :     PgStat_StatDBEntry *dbentry;
     194 ECB             : 
     195 GIC        8866 :     if (!pgstat_should_report_connstat())
     196            1143 :         return;
     197                 : 
     198 CBC        7723 :     pgLastSessionReportTime = MyStartTimestamp;
     199 ECB             : 
     200 GIC        7723 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
     201 GNC        7723 :     dbentry->sessions++;
     202                 : }
     203 ECB             : 
     204                 : /*
     205                 :  * Notify the stats system of a disconnect.
     206                 :  */
     207                 : void
     208 GIC       10456 : pgstat_report_disconnect(Oid dboid)
     209                 : {
     210                 :     PgStat_StatDBEntry *dbentry;
     211 ECB             : 
     212 GIC       10456 :     if (!pgstat_should_report_connstat())
     213            2733 :         return;
     214                 : 
     215 CBC        7723 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
     216 ECB             : 
     217 GIC        7723 :     switch (pgStatSessionEndCause)
     218 ECB             :     {
     219 GIC        7684 :         case DISCONNECT_NOT_YET:
     220 ECB             :         case DISCONNECT_NORMAL:
     221                 :             /* we don't collect these */
     222 CBC        7684 :             break;
     223 GIC          23 :         case DISCONNECT_CLIENT_EOF:
     224 GNC          23 :             dbentry->sessions_abandoned++;
     225 CBC          23 :             break;
     226               5 :         case DISCONNECT_FATAL:
     227 GNC           5 :             dbentry->sessions_fatal++;
     228 CBC           5 :             break;
     229              11 :         case DISCONNECT_KILLED:
     230 GNC          11 :             dbentry->sessions_killed++;
     231 CBC          11 :             break;
     232 ECB             :     }
     233                 : }
     234                 : 
     235                 : /*
     236                 :  * Support function for the SQL-callable pgstat* functions. Returns
     237                 :  * the collected statistics for one database or NULL. NULL doesn't mean
     238                 :  * that the database doesn't exist, just that there are no statistics, so the
     239                 :  * caller is better off to report ZERO instead.
     240                 :  */
     241                 : PgStat_StatDBEntry *
     242 GIC        1396 : pgstat_fetch_stat_dbentry(Oid dboid)
     243                 : {
     244            1396 :     return (PgStat_StatDBEntry *)
     245 CBC        1396 :         pgstat_fetch_entry(PGSTAT_KIND_DATABASE, dboid, InvalidOid);
     246                 : }
     247 ECB             : 
     248                 : void
     249 GIC      486199 : AtEOXact_PgStat_Database(bool isCommit, bool parallel)
     250                 : {
     251                 :     /* Don't count parallel worker transaction stats */
     252 CBC      486199 :     if (!parallel)
     253                 :     {
     254                 :         /*
     255 ECB             :          * Count transaction commit or abort.  (We use counters, not just
     256                 :          * bools, in case the reporting message isn't sent right away.)
     257                 :          */
     258 GIC      484901 :         if (isCommit)
     259          464737 :             pgStatXactCommit++;
     260                 :         else
     261 CBC       20164 :             pgStatXactRollback++;
     262 ECB             :     }
     263 GIC      486199 : }
     264 ECB             : 
     265                 : /*
     266                 :  * Subroutine for pgstat_report_stat(): Handle xact commit/rollback and I/O
     267                 :  * timings.
     268                 :  */
     269                 : void
     270 GIC       24455 : pgstat_update_dbstats(TimestampTz ts)
     271                 : {
     272                 :     PgStat_StatDBEntry *dbentry;
     273 ECB             : 
     274 GIC       24455 :     dbentry = pgstat_prep_database_pending(MyDatabaseId);
     275                 : 
     276                 :     /*
     277 ECB             :      * Accumulate xact commit/rollback and I/O timings to stats entry of the
     278                 :      * current database.
     279                 :      */
     280 GNC       24455 :     dbentry->xact_commit += pgStatXactCommit;
     281           24455 :     dbentry->xact_rollback += pgStatXactRollback;
     282           24455 :     dbentry->blk_read_time += pgStatBlockReadTime;
     283           24455 :     dbentry->blk_write_time += pgStatBlockWriteTime;
     284 ECB             : 
     285 CBC       24455 :     if (pgstat_should_report_connstat())
     286 ECB             :     {
     287                 :         long        secs;
     288                 :         int         usecs;
     289                 : 
     290                 :         /*
     291                 :          * pgLastSessionReportTime is initialized to MyStartTimestamp by
     292                 :          * pgstat_report_connect().
     293                 :          */
     294 GIC       16572 :         TimestampDifference(pgLastSessionReportTime, ts, &secs, &usecs);
     295           16572 :         pgLastSessionReportTime = ts;
     296 GNC       16572 :         dbentry->session_time += (PgStat_Counter) secs * 1000000 + usecs;
     297           16572 :         dbentry->active_time += pgStatActiveTime;
     298           16572 :         dbentry->idle_in_transaction_time += pgStatTransactionIdleTime;
     299 ECB             :     }
     300                 : 
     301 CBC       24455 :     pgStatXactCommit = 0;
     302 GIC       24455 :     pgStatXactRollback = 0;
     303           24455 :     pgStatBlockReadTime = 0;
     304 CBC       24455 :     pgStatBlockWriteTime = 0;
     305           24455 :     pgStatActiveTime = 0;
     306           24455 :     pgStatTransactionIdleTime = 0;
     307           24455 : }
     308 ECB             : 
     309                 : /*
     310                 :  * We report session statistics only for normal backend processes.  Parallel
     311                 :  * workers run in parallel, so they don't contribute to session times, even
     312                 :  * though they use CPU time. Walsender processes could be considered here,
     313                 :  * but they have different session characteristics from normal backends (for
     314                 :  * example, they are always "active"), so they would skew session statistics.
     315                 :  */
     316                 : static bool
     317 GIC       43777 : pgstat_should_report_connstat(void)
     318                 : {
     319           43777 :     return MyBackendType == B_BACKEND;
     320 ECB             : }
     321                 : 
     322                 : /*
     323                 :  * Find or create a local PgStat_StatDBEntry entry for dboid.
     324                 :  */
     325                 : PgStat_StatDBEntry *
     326 GIC      751190 : pgstat_prep_database_pending(Oid dboid)
     327                 : {
     328                 :     PgStat_EntryRef *entry_ref;
     329 ECB             : 
     330 GIC      751190 :     entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_DATABASE, dboid, InvalidOid,
     331                 :                                           NULL);
     332                 : 
     333 CBC      751190 :     return entry_ref->pending;
     334                 : }
     335                 : 
     336 ECB             : /*
     337                 :  * Reset the database's reset timestamp, without resetting the contents of the
     338                 :  * database stats.
     339                 :  */
     340                 : void
     341 GIC           5 : pgstat_reset_database_timestamp(Oid dboid, TimestampTz ts)
     342                 : {
     343                 :     PgStat_EntryRef *dbref;
     344 ECB             :     PgStatShared_Database *dbentry;
     345                 : 
     346 GIC           5 :     dbref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, MyDatabaseId, InvalidOid,
     347                 :                                         false);
     348                 : 
     349 CBC           5 :     dbentry = (PgStatShared_Database *) dbref->shared_stats;
     350 GIC           5 :     dbentry->stats.stat_reset_timestamp = ts;
     351                 : 
     352 CBC           5 :     pgstat_unlock_entry(dbref);
     353               5 : }
     354                 : 
     355 ECB             : /*
     356                 :  * Flush out pending stats for the entry
     357                 :  *
     358                 :  * If nowait is true, this function returns false if lock could not
     359                 :  * immediately acquired, otherwise true is returned.
     360                 :  */
     361                 : bool
     362 GIC       41606 : pgstat_database_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
     363                 : {
     364                 :     PgStatShared_Database *sharedent;
     365 ECB             :     PgStat_StatDBEntry *pendingent;
     366                 : 
     367 GIC       41606 :     pendingent = (PgStat_StatDBEntry *) entry_ref->pending;
     368           41606 :     sharedent = (PgStatShared_Database *) entry_ref->shared_stats;
     369                 : 
     370 CBC       41606 :     if (!pgstat_lock_entry(entry_ref, nowait))
     371               2 :         return false;
     372                 : 
     373 ECB             : #define PGSTAT_ACCUM_DBCOUNT(item)      \
     374                 :     (sharedent)->stats.item += (pendingent)->item
     375                 : 
     376 GNC       41604 :     PGSTAT_ACCUM_DBCOUNT(xact_commit);
     377           41604 :     PGSTAT_ACCUM_DBCOUNT(xact_rollback);
     378           41604 :     PGSTAT_ACCUM_DBCOUNT(blocks_fetched);
     379           41604 :     PGSTAT_ACCUM_DBCOUNT(blocks_hit);
     380 ECB             : 
     381 GNC       41604 :     PGSTAT_ACCUM_DBCOUNT(tuples_returned);
     382           41604 :     PGSTAT_ACCUM_DBCOUNT(tuples_fetched);
     383           41604 :     PGSTAT_ACCUM_DBCOUNT(tuples_inserted);
     384           41604 :     PGSTAT_ACCUM_DBCOUNT(tuples_updated);
     385           41604 :     PGSTAT_ACCUM_DBCOUNT(tuples_deleted);
     386 ECB             : 
     387                 :     /* last_autovac_time is reported immediately */
     388 CBC       41604 :     Assert(pendingent->last_autovac_time == 0);
     389                 : 
     390 GNC       41604 :     PGSTAT_ACCUM_DBCOUNT(conflict_tablespace);
     391           41604 :     PGSTAT_ACCUM_DBCOUNT(conflict_lock);
     392           41604 :     PGSTAT_ACCUM_DBCOUNT(conflict_snapshot);
     393           41604 :     PGSTAT_ACCUM_DBCOUNT(conflict_logicalslot);
     394           41604 :     PGSTAT_ACCUM_DBCOUNT(conflict_bufferpin);
     395           41604 :     PGSTAT_ACCUM_DBCOUNT(conflict_startup_deadlock);
     396 ECB             : 
     397 GNC       41604 :     PGSTAT_ACCUM_DBCOUNT(temp_bytes);
     398           41604 :     PGSTAT_ACCUM_DBCOUNT(temp_files);
     399           41604 :     PGSTAT_ACCUM_DBCOUNT(deadlocks);
     400                 : 
     401 ECB             :     /* checksum failures are reported immediately */
     402 GNC       41604 :     Assert(pendingent->checksum_failures == 0);
     403 CBC       41604 :     Assert(pendingent->last_checksum_failure == 0);
     404                 : 
     405 GNC       41604 :     PGSTAT_ACCUM_DBCOUNT(blk_read_time);
     406           41604 :     PGSTAT_ACCUM_DBCOUNT(blk_write_time);
     407 ECB             : 
     408 GNC       41604 :     PGSTAT_ACCUM_DBCOUNT(sessions);
     409           41604 :     PGSTAT_ACCUM_DBCOUNT(session_time);
     410           41604 :     PGSTAT_ACCUM_DBCOUNT(active_time);
     411           41604 :     PGSTAT_ACCUM_DBCOUNT(idle_in_transaction_time);
     412           41604 :     PGSTAT_ACCUM_DBCOUNT(sessions_abandoned);
     413           41604 :     PGSTAT_ACCUM_DBCOUNT(sessions_fatal);
     414           41604 :     PGSTAT_ACCUM_DBCOUNT(sessions_killed);
     415 ECB             : #undef PGSTAT_ACCUM_DBCOUNT
     416                 : 
     417 CBC       41604 :     pgstat_unlock_entry(entry_ref);
     418 ECB             : 
     419 GIC       41604 :     memset(pendingent, 0, sizeof(*pendingent));
     420                 : 
     421 CBC       41604 :     return true;
     422                 : }
     423 ECB             : 
     424                 : void
     425 CBC          13 : pgstat_database_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
     426                 : {
     427 GIC          13 :     ((PgStatShared_Database *) header)->stats.stat_reset_timestamp = ts;
     428              13 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a