LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.7 % 436 404 1 4 25 2 8 262 9 125 21 273 1 2
Current Date: 2023-04-08 17:13:01 Functions: 100.0 % 32 32 32 32
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 83.3 % 6 5 1 5
Legend: Lines: hit not hit (120,180] days: 100.0 % 4 4 4
(180,240] days: 100.0 % 6 6 3 3 2
(240..) days: 92.6 % 420 389 4 25 2 8 259 122 21 261
Function coverage date bins:
(240..) days: 50.8 % 63 32 32 31

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /* ----------
                                  2                 :  * pgstat.c
                                  3                 :  *    Infrastructure for the cumulative statistics system.
                                  4                 :  *
                                  5                 :  * The cumulative statistics system accumulates statistics for different kinds
                                  6                 :  * of objects. Some kinds of statistics are collected for a fixed number of
                                  7                 :  * objects (most commonly 1), e.g., checkpointer statistics. Other kinds of
                                  8                 :  * statistics are collected for a varying number of objects
                                  9                 :  * (e.g. relations). See PgStat_KindInfo for a list of currently handled
                                 10                 :  * statistics.
                                 11                 :  *
                                 12                 :  * Statistics are loaded from the filesystem during startup (by the startup
                                 13                 :  * process), unless preceded by a crash, in which case all stats are
                                 14                 :  * discarded. They are written out by the checkpointer process just before
                                 15                 :  * shutting down, except when shutting down in immediate mode.
                                 16                 :  *
                                 17                 :  * Fixed-numbered stats are stored in plain (non-dynamic) shared memory.
                                 18                 :  *
                                 19                 :  * Statistics for variable-numbered objects are stored in dynamic shared
                                 20                 :  * memory and can be found via a dshash hashtable. The statistics counters are
                                 21                 :  * not part of the dshash entry (PgStatShared_HashEntry) directly, but are
                                 22                 :  * separately allocated (PgStatShared_HashEntry->body). The separate
                                 23                 :  * allocation allows different kinds of statistics to be stored in the same
                                 24                 :  * hashtable without wasting space in PgStatShared_HashEntry.
                                 25                 :  *
                                 26                 :  * Variable-numbered stats are addressed by PgStat_HashKey while running.  It
                                 27                 :  * is not possible to have statistics for an object that cannot be addressed
                                 28                 :  * that way at runtime. A wider identifier can be used when serializing to
                                 29                 :  * disk (used for replication slot stats).
                                 30                 :  *
                                 31                 :  * To avoid contention on the shared hashtable, each backend has a
                                 32                 :  * backend-local hashtable (pgStatEntryRefHash) in front of the shared
                                 33                 :  * hashtable, containing references (PgStat_EntryRef) to shared hashtable
                                 34                 :  * entries. The shared hashtable only needs to be accessed when no prior
                                 35                 :  * reference is found in the local hashtable. Besides pointing to the
                                 36                 :  * shared hashtable entry (PgStatShared_HashEntry) PgStat_EntryRef also
                                 37                 :  * contains a pointer to the shared statistics data, as a process-local
                                 38                 :  * address, to reduce access costs.
                                 39                 :  *
                                 40                 :  * The names for structs stored in shared memory are prefixed with
                                 41                 :  * PgStatShared instead of PgStat. Each stats entry in shared memory is
                                 42                 :  * protected by a dedicated lwlock.
                                 43                 :  *
                                 44                 :  * Most stats updates are first accumulated locally in each process as pending
                                 45                 :  * entries, then later flushed to shared memory (just after commit, or by
                                 46                 :  * idle-timeout). This practically eliminates contention on individual stats
                                 47                 :  * entries. For most kinds of variable-numbered pending stats data is stored
                                 48                 :  * in PgStat_EntryRef->pending. All entries with pending data are in the
                                 49                 :  * pgStatPending list. Pending statistics updates are flushed out by
                                 50                 :  * pgstat_report_stat().
                                 51                 :  *
                                 52                 :  * The behavior of different kinds of statistics is determined by the kind's
                                 53                 :  * entry in pgstat_kind_infos, see PgStat_KindInfo for details.
                                 54                 :  *
                                 55                 :  * The consistency of read accesses to statistics can be configured using the
                                 56                 :  * stats_fetch_consistency GUC (see config.sgml and monitoring.sgml for the
                                 57                 :  * settings). When using PGSTAT_FETCH_CONSISTENCY_CACHE or
                                 58                 :  * PGSTAT_FETCH_CONSISTENCY_SNAPSHOT statistics are stored in
                                 59                 :  * pgStatLocal.snapshot.
                                 60                 :  *
                                 61                 :  * To keep things manageable, stats handling is split across several
                                 62                 :  * files. Infrastructure pieces are in:
                                 63                 :  * - pgstat.c - this file, to tie it all together
                                 64                 :  * - pgstat_shmem.c - nearly everything dealing with shared memory, including
                                 65                 :  *   the maintenance of hashtable entries
                                 66                 :  * - pgstat_xact.c - transactional integration, including the transactional
                                 67                 :  *   creation and dropping of stats entries
                                 68                 :  *
                                 69                 :  * Each statistics kind is handled in a dedicated file:
                                 70                 :  * - pgstat_archiver.c
                                 71                 :  * - pgstat_bgwriter.c
                                 72                 :  * - pgstat_checkpointer.c
                                 73                 :  * - pgstat_database.c
                                 74                 :  * - pgstat_function.c
                                 75                 :  * - pgstat_io.c
                                 76                 :  * - pgstat_relation.c
                                 77                 :  * - pgstat_replslot.c
                                 78                 :  * - pgstat_slru.c
                                 79                 :  * - pgstat_subscription.c
                                 80                 :  * - pgstat_wal.c
                                 81                 :  *
                                 82                 :  * Whenever possible infrastructure files should not contain code related to
                                 83                 :  * specific kinds of stats.
                                 84                 :  *
                                 85                 :  *
                                 86                 :  * Copyright (c) 2001-2023, PostgreSQL Global Development Group
                                 87                 :  *
                                 88                 :  * IDENTIFICATION
                                 89                 :  *    src/backend/utils/activity/pgstat.c
                                 90                 :  * ----------
                                 91                 :  */
                                 92                 : #include "postgres.h"
                                 93                 : 
                                 94                 : #include <unistd.h>
                                 95                 : 
                                 96                 : #include "access/transam.h"
                                 97                 : #include "access/xact.h"
                                 98                 : #include "lib/dshash.h"
                                 99                 : #include "pgstat.h"
                                100                 : #include "port/atomics.h"
                                101                 : #include "storage/fd.h"
                                102                 : #include "storage/ipc.h"
                                103                 : #include "storage/lwlock.h"
                                104                 : #include "storage/pg_shmem.h"
                                105                 : #include "storage/shmem.h"
                                106                 : #include "utils/guc.h"
                                107                 : #include "utils/memutils.h"
                                108                 : #include "utils/pgstat_internal.h"
                                109                 : #include "utils/timestamp.h"
                                110                 : 
                                111                 : 
                                112                 : /* ----------
                                113                 :  * Timer definitions.
                                114                 :  *
                                115                 :  * In milliseconds.
                                116                 :  * ----------
                                117                 :  */
                                118                 : 
                                119                 : /* minimum interval non-forced stats flushes.*/
                                120                 : #define PGSTAT_MIN_INTERVAL         1000
                                121                 : /* how long until to block flushing pending stats updates */
                                122                 : #define PGSTAT_MAX_INTERVAL         60000
                                123                 : /* when to call pgstat_report_stat() again, even when idle */
                                124                 : #define PGSTAT_IDLE_INTERVAL        10000
                                125                 : 
                                126                 : /* ----------
                                127                 :  * Initial size hints for the hash tables used in statistics.
                                128                 :  * ----------
                                129                 :  */
                                130                 : 
                                131                 : #define PGSTAT_SNAPSHOT_HASH_SIZE   512
                                132                 : 
                                133                 : 
                                134                 : /* hash table for statistics snapshots entry */
                                135                 : typedef struct PgStat_SnapshotEntry
                                136                 : {
                                137                 :     PgStat_HashKey key;
                                138                 :     char        status;         /* for simplehash use */
                                139                 :     void       *data;           /* the stats data itself */
                                140                 : } PgStat_SnapshotEntry;
                                141                 : 
                                142                 : 
                                143                 : /* ----------
                                144                 :  * Backend-local Hash Table Definitions
                                145                 :  * ----------
                                146                 :  */
                                147                 : 
                                148                 : /* for stats snapshot entries */
                                149                 : #define SH_PREFIX pgstat_snapshot
                                150                 : #define SH_ELEMENT_TYPE PgStat_SnapshotEntry
                                151                 : #define SH_KEY_TYPE PgStat_HashKey
                                152                 : #define SH_KEY key
                                153                 : #define SH_HASH_KEY(tb, key) \
                                154                 :     pgstat_hash_hash_key(&key, sizeof(PgStat_HashKey), NULL)
                                155                 : #define SH_EQUAL(tb, a, b) \
                                156                 :     pgstat_cmp_hash_key(&a, &b, sizeof(PgStat_HashKey), NULL) == 0
                                157                 : #define SH_SCOPE static inline
                                158                 : #define SH_DEFINE
                                159                 : #define SH_DECLARE
                                160                 : #include "lib/simplehash.h"
                                161                 : 
                                162                 : 
                                163                 : /* ----------
                                164                 :  * Local function forward declarations
                                165                 :  * ----------
                                166                 :  */
                                167                 : 
                                168                 : static void pgstat_write_statsfile(void);
                                169                 : static void pgstat_read_statsfile(void);
                                170                 : 
                                171                 : static void pgstat_reset_after_failure(void);
                                172                 : 
                                173                 : static bool pgstat_flush_pending_entries(bool nowait);
                                174                 : 
                                175                 : static void pgstat_prep_snapshot(void);
                                176                 : static void pgstat_build_snapshot(void);
                                177                 : static void pgstat_build_snapshot_fixed(PgStat_Kind kind);
                                178                 : 
                                179                 : static inline bool pgstat_is_kind_valid(int ikind);
                                180                 : 
                                181                 : 
                                182                 : /* ----------
                                183                 :  * GUC parameters
                                184                 :  * ----------
                                185                 :  */
                                186                 : 
                                187                 : bool        pgstat_track_counts = false;
                                188                 : int         pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_CACHE;
                                189                 : 
                                190                 : 
                                191                 : /* ----------
                                192                 :  * state shared with pgstat_*.c
                                193                 :  * ----------
                                194                 :  */
                                195                 : 
                                196                 : PgStat_LocalState pgStatLocal;
                                197                 : 
                                198                 : 
                                199                 : /* ----------
                                200                 :  * Local data
                                201                 :  *
                                202                 :  * NB: There should be only variables related to stats infrastructure here,
                                203                 :  * not for specific kinds of stats.
                                204                 :  * ----------
                                205                 :  */
                                206                 : 
                                207                 : /*
                                208                 :  * Memory contexts containing the pgStatEntryRefHash table, the
                                209                 :  * pgStatSharedRef entries, and pending data respectively. Mostly to make it
                                210                 :  * easier to track / attribute memory usage.
                                211                 :  */
                                212                 : 
                                213                 : static MemoryContext pgStatPendingContext = NULL;
                                214                 : 
                                215                 : /*
                                216                 :  * Backend local list of PgStat_EntryRef with unflushed pending stats.
                                217                 :  *
                                218                 :  * Newly pending entries should only ever be added to the end of the list,
                                219                 :  * otherwise pgstat_flush_pending_entries() might not see them immediately.
                                220                 :  */
                                221                 : static dlist_head pgStatPending = DLIST_STATIC_INIT(pgStatPending);
                                222                 : 
                                223                 : 
                                224                 : /*
                                225                 :  * Force the next stats flush to happen regardless of
                                226                 :  * PGSTAT_MIN_INTERVAL. Useful in test scripts.
                                227                 :  */
                                228                 : static bool pgStatForceNextFlush = false;
                                229                 : 
                                230                 : /*
                                231                 :  * For assertions that check pgstat is not used before initialization / after
                                232                 :  * shutdown.
                                233                 :  */
                                234                 : #ifdef USE_ASSERT_CHECKING
                                235                 : static bool pgstat_is_initialized = false;
                                236                 : static bool pgstat_is_shutdown = false;
                                237                 : #endif
                                238                 : 
                                239                 : 
                                240                 : /*
                                241                 :  * The different kinds of statistics.
                                242                 :  *
                                243                 :  * If reasonably possible, handling specific to one kind of stats should go
                                244                 :  * through this abstraction, rather than making more of pgstat.c aware.
                                245                 :  *
                                246                 :  * See comments for struct PgStat_KindInfo for details about the individual
                                247                 :  * fields.
                                248                 :  *
                                249                 :  * XXX: It'd be nicer to define this outside of this file. But there doesn't
                                250                 :  * seem to be a great way of doing that, given the split across multiple
                                251                 :  * files.
                                252                 :  */
                                253                 : static const PgStat_KindInfo pgstat_kind_infos[PGSTAT_NUM_KINDS] = {
                                254                 : 
                                255                 :     /* stats kinds for variable-numbered objects */
                                256                 : 
                                257                 :     [PGSTAT_KIND_DATABASE] = {
                                258                 :         .name = "database",
                                259                 : 
                                260                 :         .fixed_amount = false,
                                261                 :         /* so pg_stat_database entries can be seen in all databases */
                                262                 :         .accessed_across_databases = true,
                                263                 : 
                                264                 :         .shared_size = sizeof(PgStatShared_Database),
                                265                 :         .shared_data_off = offsetof(PgStatShared_Database, stats),
                                266                 :         .shared_data_len = sizeof(((PgStatShared_Database *) 0)->stats),
                                267                 :         .pending_size = sizeof(PgStat_StatDBEntry),
                                268                 : 
                                269                 :         .flush_pending_cb = pgstat_database_flush_cb,
                                270                 :         .reset_timestamp_cb = pgstat_database_reset_timestamp_cb,
                                271                 :     },
                                272                 : 
                                273                 :     [PGSTAT_KIND_RELATION] = {
                                274                 :         .name = "relation",
                                275                 : 
                                276                 :         .fixed_amount = false,
                                277                 : 
                                278                 :         .shared_size = sizeof(PgStatShared_Relation),
                                279                 :         .shared_data_off = offsetof(PgStatShared_Relation, stats),
                                280                 :         .shared_data_len = sizeof(((PgStatShared_Relation *) 0)->stats),
                                281                 :         .pending_size = sizeof(PgStat_TableStatus),
                                282                 : 
                                283                 :         .flush_pending_cb = pgstat_relation_flush_cb,
                                284                 :         .delete_pending_cb = pgstat_relation_delete_pending_cb,
                                285                 :     },
                                286                 : 
                                287                 :     [PGSTAT_KIND_FUNCTION] = {
                                288                 :         .name = "function",
                                289                 : 
                                290                 :         .fixed_amount = false,
                                291                 : 
                                292                 :         .shared_size = sizeof(PgStatShared_Function),
                                293                 :         .shared_data_off = offsetof(PgStatShared_Function, stats),
                                294                 :         .shared_data_len = sizeof(((PgStatShared_Function *) 0)->stats),
                                295                 :         .pending_size = sizeof(PgStat_FunctionCounts),
                                296                 : 
                                297                 :         .flush_pending_cb = pgstat_function_flush_cb,
                                298                 :     },
                                299                 : 
                                300                 :     [PGSTAT_KIND_REPLSLOT] = {
                                301                 :         .name = "replslot",
                                302                 : 
                                303                 :         .fixed_amount = false,
                                304                 : 
                                305                 :         .accessed_across_databases = true,
                                306                 :         .named_on_disk = true,
                                307                 : 
                                308                 :         .shared_size = sizeof(PgStatShared_ReplSlot),
                                309                 :         .shared_data_off = offsetof(PgStatShared_ReplSlot, stats),
                                310                 :         .shared_data_len = sizeof(((PgStatShared_ReplSlot *) 0)->stats),
                                311                 : 
                                312                 :         .reset_timestamp_cb = pgstat_replslot_reset_timestamp_cb,
                                313                 :         .to_serialized_name = pgstat_replslot_to_serialized_name_cb,
                                314                 :         .from_serialized_name = pgstat_replslot_from_serialized_name_cb,
                                315                 :     },
                                316                 : 
                                317                 :     [PGSTAT_KIND_SUBSCRIPTION] = {
                                318                 :         .name = "subscription",
                                319                 : 
                                320                 :         .fixed_amount = false,
                                321                 :         /* so pg_stat_subscription_stats entries can be seen in all databases */
                                322                 :         .accessed_across_databases = true,
                                323                 : 
                                324                 :         .shared_size = sizeof(PgStatShared_Subscription),
                                325                 :         .shared_data_off = offsetof(PgStatShared_Subscription, stats),
                                326                 :         .shared_data_len = sizeof(((PgStatShared_Subscription *) 0)->stats),
                                327                 :         .pending_size = sizeof(PgStat_BackendSubEntry),
                                328                 : 
                                329                 :         .flush_pending_cb = pgstat_subscription_flush_cb,
                                330                 :         .reset_timestamp_cb = pgstat_subscription_reset_timestamp_cb,
                                331                 :     },
                                332                 : 
                                333                 : 
                                334                 :     /* stats for fixed-numbered (mostly 1) objects */
                                335                 : 
                                336                 :     [PGSTAT_KIND_ARCHIVER] = {
                                337                 :         .name = "archiver",
                                338                 : 
                                339                 :         .fixed_amount = true,
                                340                 : 
                                341                 :         .reset_all_cb = pgstat_archiver_reset_all_cb,
                                342                 :         .snapshot_cb = pgstat_archiver_snapshot_cb,
                                343                 :     },
                                344                 : 
                                345                 :     [PGSTAT_KIND_BGWRITER] = {
                                346                 :         .name = "bgwriter",
                                347                 : 
                                348                 :         .fixed_amount = true,
                                349                 : 
                                350                 :         .reset_all_cb = pgstat_bgwriter_reset_all_cb,
                                351                 :         .snapshot_cb = pgstat_bgwriter_snapshot_cb,
                                352                 :     },
                                353                 : 
                                354                 :     [PGSTAT_KIND_CHECKPOINTER] = {
                                355                 :         .name = "checkpointer",
                                356                 : 
                                357                 :         .fixed_amount = true,
                                358                 : 
                                359                 :         .reset_all_cb = pgstat_checkpointer_reset_all_cb,
                                360                 :         .snapshot_cb = pgstat_checkpointer_snapshot_cb,
                                361                 :     },
                                362                 : 
                                363                 :     [PGSTAT_KIND_IO] = {
                                364                 :         .name = "io",
                                365                 : 
                                366                 :         .fixed_amount = true,
                                367                 : 
                                368                 :         .reset_all_cb = pgstat_io_reset_all_cb,
                                369                 :         .snapshot_cb = pgstat_io_snapshot_cb,
                                370                 :     },
                                371                 : 
                                372                 :     [PGSTAT_KIND_SLRU] = {
                                373                 :         .name = "slru",
                                374                 : 
                                375                 :         .fixed_amount = true,
                                376                 : 
                                377                 :         .reset_all_cb = pgstat_slru_reset_all_cb,
                                378                 :         .snapshot_cb = pgstat_slru_snapshot_cb,
                                379                 :     },
                                380                 : 
                                381                 :     [PGSTAT_KIND_WAL] = {
                                382                 :         .name = "wal",
                                383                 : 
                                384                 :         .fixed_amount = true,
                                385                 : 
                                386                 :         .reset_all_cb = pgstat_wal_reset_all_cb,
                                387                 :         .snapshot_cb = pgstat_wal_snapshot_cb,
                                388                 :     },
                                389                 : };
                                390                 : 
                                391                 : 
                                392                 : /* ------------------------------------------------------------
                                393                 :  * Functions managing the state of the stats system for all backends.
                                394                 :  * ------------------------------------------------------------
                                395                 :  */
                                396                 : 
                                397                 : /*
                                398                 :  * Read on-disk stats into memory at server start.
                                399                 :  *
                                400                 :  * Should only be called by the startup process or in single user mode.
                                401                 :  */
                                402                 : void
  368 andres                    403 GIC        1045 : pgstat_restore_stats(void)
                                404                 : {
                                405            1045 :     pgstat_read_statsfile();
 6450 tgl                       406            1045 : }
                                407                 : 
                                408                 : /*
                                409                 :  * Remove the stats file.  This is currently used only if WAL recovery is
                                410                 :  * needed after a crash.
                                411                 :  *
                                412                 :  * Should only be called by the startup process or in single user mode.
 7045 bruce                     413 ECB             :  */
                                414                 : void
  368 andres                    415 CBC         131 : pgstat_discard_stats(void)
 7045 bruce                     416 ECB             : {
                                417                 :     int         ret;
                                418                 : 
                                419                 :     /* NB: this needs to be done even in single user mode */
                                420                 : 
  368 andres                    421 GIC         131 :     ret = unlink(PGSTAT_STAT_PERMANENT_FILENAME);
                                422             131 :     if (ret != 0)
                                423                 :     {
                                424             130 :         if (errno == ENOENT)
  368 andres                    425 CBC         130 :             elog(DEBUG2,
                                426                 :                  "didn't need to unlink permanent stats file \"%s\" - didn't exist",
                                427                 :                  PGSTAT_STAT_PERMANENT_FILENAME);
                                428                 :         else
  368 andres                    429 UIC           0 :             ereport(LOG,
                                430                 :                     (errcode_for_file_access(),
  368 andres                    431 ECB             :                      errmsg("could not unlink permanent statistics file \"%s\": %m",
                                432                 :                             PGSTAT_STAT_PERMANENT_FILENAME)));
                                433                 :     }
                                434                 :     else
                                435                 :     {
  368 andres                    436 GIC           1 :         ereport(DEBUG2,
                                437                 :                 (errcode_for_file_access(),
                                438                 :                  errmsg_internal("unlinked permanent statistics file \"%s\"",
                                439                 :                                  PGSTAT_STAT_PERMANENT_FILENAME)));
                                440                 :     }
                                441                 : 
                                442                 :     /*
                                443                 :      * Reset stats contents. This will set reset timestamps of fixed-numbered
                                444                 :      * stats to the current time (no variable stats exist).
                                445                 :      */
  360 andres                    446 CBC         131 :     pgstat_reset_after_failure();
 7045 bruce                     447 GIC         131 : }
                                448                 : 
                                449                 : /*
                                450                 :  * pgstat_before_server_shutdown() needs to be called by exactly one process
                                451                 :  * during regular server shutdowns. Otherwise all stats will be lost.
                                452                 :  *
                                453                 :  * We currently only write out stats for proc_exit(0). We might want to change
                                454                 :  * that at some point... But right now pgstat_discard_stats() would be called
                                455                 :  * during the start after a disorderly shutdown, anyway.
 7961 JanWieck                  456 ECB             :  */
  368 andres                    457                 : void
  368 andres                    458 GIC         974 : pgstat_before_server_shutdown(int code, Datum arg)
                                459                 : {
                                460             974 :     Assert(pgStatLocal.shmem != NULL);
                                461             974 :     Assert(!pgStatLocal.shmem->is_shutdown);
                                462                 : 
                                463                 :     /*
                                464                 :      * Stats should only be reported after pgstat_initialize() and before
                                465                 :      * pgstat_shutdown(). This is a convenient point to catch most violations
                                466                 :      * of this rule.
                                467                 :      */
  368 andres                    468 CBC         974 :     Assert(pgstat_is_initialized && !pgstat_is_shutdown);
                                469                 : 
  368 andres                    470 ECB             :     /* flush out our own pending changes before writing out */
  368 andres                    471 CBC         974 :     pgstat_report_stat(true);
                                472                 : 
                                473                 :     /*
                                474                 :      * Only write out file during normal shutdown. Don't even signal that
                                475                 :      * we've shutdown during irregular shutdowns, because the shutdown
                                476                 :      * sequence isn't coordinated to ensure this backend shuts down last.
                                477                 :      */
                                478             974 :     if (code == 0)
                                479                 :     {
  368 andres                    480 GIC         969 :         pgStatLocal.shmem->is_shutdown = true;
  368 andres                    481 CBC         969 :         pgstat_write_statsfile();
                                482                 :     }
 5862 bruce                     483 GIC         974 : }
                                484                 : 
                                485                 : 
                                486                 : /* ------------------------------------------------------------
                                487                 :  * Backend initialization / shutdown functions
  384 andres                    488 ECB             :  * ------------------------------------------------------------
                                489                 :  */
                                490                 : 
                                491                 : /*
                                492                 :  * Shut down a single backend's statistics reporting at process exit.
                                493                 :  *
                                494                 :  * Flush out any remaining statistics counts.  Without this, operations
                                495                 :  * triggered during backend exit (such as temp table deletions) won't be
                                496                 :  * counted.
                                497                 :  */
                                498                 : static void
  384 andres                    499 GIC       13300 : pgstat_shutdown_hook(int code, Datum arg)
                                500                 : {
                                501           13300 :     Assert(!pgstat_is_shutdown);
  368                           502           13300 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
                                503                 : 
                                504                 :     /*
                                505                 :      * If we got as far as discovering our own database ID, we can flush out
                                506                 :      * what we did so far.  Otherwise, we'd be reporting an invalid database
                                507                 :      * ID, so forget it.  (This means that accesses to pg_database during
                                508                 :      * failed backend starts might never get counted.)
  384 andres                    509 ECB             :      */
  384 andres                    510 GIC       13300 :     if (OidIsValid(MyDatabaseId))
  368 andres                    511 CBC       10456 :         pgstat_report_disconnect(MyDatabaseId);
  368 andres                    512 ECB             : 
  368 andres                    513 GIC       13300 :     pgstat_report_stat(true);
                                514                 : 
                                515                 :     /* there shouldn't be any pending changes left */
                                516           13300 :     Assert(dlist_is_empty(&pgStatPending));
                                517           13300 :     dlist_init(&pgStatPending);
                                518                 : 
                                519           13300 :     pgstat_detach_shmem();
  384 andres                    520 ECB             : 
                                521                 : #ifdef USE_ASSERT_CHECKING
  384 andres                    522 GIC       13300 :     pgstat_is_shutdown = true;
  384 andres                    523 ECB             : #endif
  384 andres                    524 GIC       13300 : }
                                525                 : 
  370 andres                    526 ECB             : /*
                                527                 :  * Initialize pgstats state, and set up our on-proc-exit hook. Called from
                                528                 :  * BaseInit().
  384                           529                 :  *
                                530                 :  * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
                                531                 :  */
                                532                 : void
  384 andres                    533 GIC       13300 : pgstat_initialize(void)
  384 andres                    534 ECB             : {
  384 andres                    535 GIC       13300 :     Assert(!pgstat_is_initialized);
                                536                 : 
  368                           537           13300 :     pgstat_attach_shmem();
                                538                 : 
                                539           13300 :     pgstat_init_wal();
                                540                 : 
                                541                 :     /* Set up a process-exit hook to clean up */
  384                           542           13300 :     before_shmem_exit(pgstat_shutdown_hook, 0);
  384 andres                    543 ECB             : 
                                544                 : #ifdef USE_ASSERT_CHECKING
  384 andres                    545 CBC       13300 :     pgstat_is_initialized = true;
                                546                 : #endif
                                547           13300 : }
                                548                 : 
  384 andres                    549 ECB             : 
                                550                 : /* ------------------------------------------------------------
                                551                 :  * Public functions used by backends follow
                                552                 :  * ------------------------------------------------------------
                                553                 :  */
                                554                 : 
  370                           555                 : /*
                                556                 :  * Must be called by processes that performs DML: tcop/postgres.c, logical
  368                           557                 :  * receiver processes, SPI worker, etc. to flush pending statistics updates to
                                558                 :  * shared memory.
                                559                 :  *
                                560                 :  * Unless called with 'force', pending stats updates are flushed happen once
                                561                 :  * per PGSTAT_MIN_INTERVAL (1000ms). When not forced, stats flushes do not
                                562                 :  * block on lock acquisition, except if stats updates have been pending for
                                563                 :  * longer than PGSTAT_MAX_INTERVAL (60000ms).
                                564                 :  *
                                565                 :  * Whenever pending stats updates remain at the end of pgstat_report_stat() a
                                566                 :  * suggested idle timeout is returned. Currently this is always
                                567                 :  * PGSTAT_IDLE_INTERVAL (10000ms). Callers can use the returned time to set up
                                568                 :  * a timeout after which to call pgstat_report_stat(true), but are not
                                569                 :  * required to do so.
                                570                 :  *
                                571                 :  * Note that this is called only when not within a transaction, so it is fair
                                572                 :  * to use transaction stop time as an approximation of current time.
                                573                 :  */
                                574                 : long
  368 andres                    575 GIC      422106 : pgstat_report_stat(bool force)
                                576                 : {
                                577                 :     static TimestampTz pending_since = 0;
                                578                 :     static TimestampTz last_flush = 0;
                                579                 :     bool        partial_flush;
                                580                 :     TimestampTz now;
                                581                 :     bool        nowait;
                                582                 : 
  611                           583          422106 :     pgstat_assert_is_up();
  296                           584          422106 :     Assert(!IsTransactionOrTransactionBlock());
  611 andres                    585 ECB             : 
                                586                 :     /* "absorb" the forced flush even if there's nothing to flush */
  368 andres                    587 GIC      422106 :     if (pgStatForceNextFlush)
                                588                 :     {
                                589             201 :         force = true;
                                590             201 :         pgStatForceNextFlush = false;
                                591                 :     }
                                592                 : 
  368 andres                    593 ECB             :     /* Don't expend a clock check if nothing to do */
  368 andres                    594 CBC      422106 :     if (dlist_is_empty(&pgStatPending) &&
   60 andres                    595 GNC        7269 :         !have_iostats &&
  368 andres                    596 GIC        7154 :         !have_slrustats &&
                                597            6346 :         !pgstat_have_pending_wal())
  368 andres                    598 ECB             :     {
  368 andres                    599 GIC        6288 :         Assert(pending_since == 0);
  368 andres                    600 CBC        6288 :         return 0;
  368 andres                    601 ECB             :     }
                                602                 : 
                                603                 :     /*
                                604                 :      * There should never be stats to report once stats are shut down. Can't
                                605                 :      * assert that before the checks above, as there is an unconditional
                                606                 :      * pgstat_report_stat() call in pgstat_shutdown_hook() - which at least
                                607                 :      * the process that ran pgstat_before_server_shutdown() will still call.
 5823 tgl                       608                 :      */
  368 andres                    609 GIC      415818 :     Assert(!pgStatLocal.shmem->is_shutdown);
  368 andres                    610 ECB             : 
 5823 tgl                       611 CBC      415818 :     now = GetCurrentTransactionStopTimestamp();
                                612                 : 
  368 andres                    613 GIC      415818 :     if (!force)
                                614                 :     {
                                615          785208 :         if (pending_since > 0 &&
                                616          382645 :             TimestampDifferenceExceeds(pending_since, now, PGSTAT_MAX_INTERVAL))
                                617                 :         {
                                618                 :             /* don't keep pending updates longer than PGSTAT_MAX_INTERVAL */
  368 andres                    619 UIC           0 :             force = true;
  368 andres                    620 ECB             :         }
  368 andres                    621 GIC      402563 :         else if (last_flush > 0 &&
  368 andres                    622 CBC      393687 :                  !TimestampDifferenceExceeds(last_flush, now, PGSTAT_MIN_INTERVAL))
                                623                 :         {
  368 andres                    624 ECB             :             /* don't flush too frequently */
  368 andres                    625 GIC      391364 :             if (pending_since == 0)
  368 andres                    626 CBC       10960 :                 pending_since = now;
 5823 tgl                       627 ECB             : 
  368 andres                    628 GIC      391364 :             return PGSTAT_IDLE_INTERVAL;
                                629                 :         }
  368 andres                    630 EUB             :     }
                                631                 : 
  368 andres                    632 CBC       24454 :     pgstat_update_dbstats(now);
  386 andres                    633 ECB             : 
                                634                 :     /* don't wait for lock acquisition when !force */
  368 andres                    635 GIC       24454 :     nowait = !force;
  386 andres                    636 ECB             : 
  368 andres                    637 CBC       24454 :     partial_flush = false;
                                638                 : 
  368 andres                    639 ECB             :     /* flush database / relation / function / ... stats */
  368 andres                    640 GIC       24454 :     partial_flush |= pgstat_flush_pending_entries(nowait);
                                641                 : 
                                642                 :     /* flush IO stats */
   60 andres                    643 GNC       24454 :     partial_flush |= pgstat_flush_io(nowait);
                                644                 : 
                                645                 :     /* flush wal stats */
  368 andres                    646 CBC       24454 :     partial_flush |= pgstat_flush_wal(nowait);
                                647                 : 
                                648                 :     /* flush SLRU stats */
                                649           24454 :     partial_flush |= pgstat_slru_flush(nowait);
                                650                 : 
                                651           24454 :     last_flush = now;
                                652                 : 
                                653                 :     /*
  368 andres                    654 ECB             :      * If some of the pending stats could not be flushed due to lock
                                655                 :      * contention, let the caller know when to retry.
                                656                 :      */
  368 andres                    657 CBC       24454 :     if (partial_flush)
                                658                 :     {
                                659                 :         /* force should have prevented us from getting here */
                                660               8 :         Assert(!force);
                                661                 : 
                                662                 :         /* remember since when stats have been pending */
                                663               8 :         if (pending_since == 0)
  368 andres                    664 GIC           8 :             pending_since = now;
  712 akapila                   665 ECB             : 
  368 andres                    666 GIC           8 :         return PGSTAT_IDLE_INTERVAL;
                                667                 :     }
                                668                 : 
                                669           24446 :     pending_since = 0;
                                670                 : 
  368 andres                    671 CBC       24446 :     return 0;
                                672                 : }
                                673                 : 
  368 andres                    674 ECB             : /*
                                675                 :  * Force locally pending stats to be flushed during the next
                                676                 :  * pgstat_report_stat() call. This is useful for writing tests.
                                677                 :  */
                                678                 : void
  368 andres                    679 GIC         201 : pgstat_force_next_flush(void)
  368 andres                    680 ECB             : {
  368 andres                    681 GIC         201 :     pgStatForceNextFlush = true;
                                682             201 : }
  368 andres                    683 ECB             : 
                                684                 : /*
                                685                 :  * Only for use by pgstat_reset_counters()
                                686                 :  */
                                687                 : static bool
  368 andres                    688 GIC       10238 : match_db_entries(PgStatShared_HashEntry *entry, Datum match_data)
                                689                 : {
                                690           10238 :     return entry->key.dboid == DatumGetObjectId(MyDatabaseId);
                                691                 : }
                                692                 : 
  368 andres                    693 ECB             : /*
                                694                 :  * Reset counters for our database.
                                695                 :  *
                                696                 :  * Permission checking for this function is managed through the normal
                                697                 :  * GRANT system.
                                698                 :  */
                                699                 : void
  368 andres                    700 GIC          13 : pgstat_reset_counters(void)
                                701                 : {
  368 andres                    702 CBC          13 :     TimestampTz ts = GetCurrentTimestamp();
                                703                 : 
                                704              13 :     pgstat_reset_matching_entries(match_db_entries,
                                705                 :                                   ObjectIdGetDatum(MyDatabaseId),
                                706                 :                                   ts);
  368 andres                    707 GIC          13 : }
                                708                 : 
                                709                 : /*
                                710                 :  * Reset a single variable-numbered entry.
                                711                 :  *
                                712                 :  * If the stats kind is within a database, also reset the database's
                                713                 :  * stat_reset_timestamp.
  368 andres                    714 ECB             :  *
                                715                 :  * Permission checking for this function is managed through the normal
                                716                 :  * GRANT system.
                                717                 :  */
                                718                 : void
  368 andres                    719 GIC          16 : pgstat_reset(PgStat_Kind kind, Oid dboid, Oid objoid)
                                720                 : {
  368 andres                    721 CBC          16 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
  368 andres                    722 GIC          16 :     TimestampTz ts = GetCurrentTimestamp();
                                723                 : 
                                724                 :     /* not needed atm, and doesn't make sense with the current signature */
                                725              16 :     Assert(!pgstat_get_kind_info(kind)->fixed_amount);
                                726                 : 
                                727                 :     /* reset the "single counter" */
                                728              16 :     pgstat_reset_entry(kind, dboid, objoid, ts);
                                729                 : 
                                730              16 :     if (!kind_info->accessed_across_databases)
                                731               5 :         pgstat_reset_database_timestamp(dboid, ts);
                                732              16 : }
 5932 tgl                       733 ECB             : 
                                734                 : /*
  368 andres                    735                 :  * Reset stats for all entries of a kind.
                                736                 :  *
                                737                 :  * Permission checking for this function is managed through the normal
                                738                 :  * GRANT system.
                                739                 :  */
                                740                 : void
  368 andres                    741 GIC          25 : pgstat_reset_of_kind(PgStat_Kind kind)
  368 andres                    742 ECB             : {
  368 andres                    743 GIC          25 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
  368 andres                    744 CBC          25 :     TimestampTz ts = GetCurrentTimestamp();
 5932 tgl                       745 ECB             : 
  368 andres                    746 CBC          25 :     if (kind_info->fixed_amount)
  368 andres                    747 GIC          21 :         kind_info->reset_all_cb(ts);
                                748                 :     else
                                749               4 :         pgstat_reset_entries_of_kind(kind, ts);
                                750              25 : }
                                751                 : 
                                752                 : 
                                753                 : /* ------------------------------------------------------------
                                754                 :  * Fetching of stats
  368 andres                    755 ECB             :  * ------------------------------------------------------------
                                756                 :  */
 7961 JanWieck                  757                 : 
  368 andres                    758                 : /*
                                759                 :  * Discard any data collected in the current transaction.  Any subsequent
                                760                 :  * request will cause new snapshots to be read.
                                761                 :  *
                                762                 :  * This is also invoked during transaction commit or abort to discard
                                763                 :  * the no-longer-wanted snapshot.
                                764                 :  */
                                765                 : void
  368 andres                    766 GIC      486568 : pgstat_clear_snapshot(void)
                                767                 : {
                                768          486568 :     pgstat_assert_is_up();
                                769                 : 
                                770          486568 :     memset(&pgStatLocal.snapshot.fixed_valid, 0,
                                771                 :            sizeof(pgStatLocal.snapshot.fixed_valid));
                                772          486568 :     pgStatLocal.snapshot.stats = NULL;
                                773          486568 :     pgStatLocal.snapshot.mode = PGSTAT_FETCH_CONSISTENCY_NONE;
                                774                 : 
                                775                 :     /* Release memory, if any was allocated */
                                776          486568 :     if (pgStatLocal.snapshot.context)
                                777                 :     {
                                778             386 :         MemoryContextDelete(pgStatLocal.snapshot.context);
                                779                 : 
  368 andres                    780 ECB             :         /* Reset variables */
  368 andres                    781 GIC         386 :         pgStatLocal.snapshot.context = NULL;
 7961 JanWieck                  782 ECB             :     }
                                783                 : 
 5442 tgl                       784                 :     /*
                                785                 :      * Historically the backend_status.c facilities lived in this file, and
  368 andres                    786                 :      * were reset with the same function. For now keep it that way, and
                                787                 :      * forward the reset request.
                                788                 :      */
  368 andres                    789 GIC      486568 :     pgstat_clear_backend_activity_snapshot();
  368 andres                    790 CBC      486568 : }
                                791                 : 
  368 andres                    792 ECB             : void *
  368 andres                    793 GIC        8782 : pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
                                794                 : {
  368 andres                    795 ECB             :     PgStat_HashKey key;
                                796                 :     PgStat_EntryRef *entry_ref;
                                797                 :     void       *stats_data;
  368 andres                    798 GIC        8782 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                799                 : 
                                800                 :     /* should be called from backends */
                                801            8782 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
  163 peter                     802 GNC        8782 :     Assert(!kind_info->fixed_amount);
 5442 tgl                       803 ECB             : 
  368 andres                    804 CBC        8782 :     pgstat_prep_snapshot();
                                805                 : 
  368 andres                    806 GIC        8782 :     key.kind = kind;
  368 andres                    807 CBC        8782 :     key.dboid = dboid;
  368 andres                    808 GIC        8782 :     key.objoid = objoid;
                                809                 : 
                                810                 :     /* if we need to build a full snapshot, do so */
                                811            8782 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
  368 andres                    812 CBC         227 :         pgstat_build_snapshot();
                                813                 : 
                                814                 :     /* if caching is desired, look up in cache */
                                815            8782 :     if (pgstat_fetch_consistency > PGSTAT_FETCH_CONSISTENCY_NONE)
  368 andres                    816 ECB             :     {
  368 andres                    817 GIC        4481 :         PgStat_SnapshotEntry *entry = NULL;
 5235 tgl                       818 ECB             : 
  368 andres                    819 GIC        4481 :         entry = pgstat_snapshot_lookup(pgStatLocal.snapshot.stats, key);
 5235 tgl                       820 ECB             : 
  368 andres                    821 CBC        4481 :         if (entry)
                                822             262 :             return entry->data;
                                823                 : 
                                824                 :         /*
  368 andres                    825 ECB             :          * If we built a full snapshot and the key is not in
                                826                 :          * pgStatLocal.snapshot.stats, there are no matching stats.
                                827                 :          */
  368 andres                    828 GIC        4219 :         if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
  368 andres                    829 CBC          11 :             return NULL;
                                830                 :     }
 5442 tgl                       831 ECB             : 
  368 andres                    832 GIC        8509 :     pgStatLocal.snapshot.mode = pgstat_fetch_consistency;
 5442 tgl                       833 ECB             : 
  368 andres                    834 GIC        8509 :     entry_ref = pgstat_get_entry_ref(kind, dboid, objoid, false, NULL);
 5932 tgl                       835 ECB             : 
  368 andres                    836 CBC        8509 :     if (entry_ref == NULL || entry_ref->shared_entry->dropped)
                                837                 :     {
                                838                 :         /* create empty entry when using PGSTAT_FETCH_CONSISTENCY_CACHE */
  368 andres                    839 GIC        2501 :         if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_CACHE)
                                840                 :         {
                                841             811 :             PgStat_SnapshotEntry *entry = NULL;
  368 andres                    842 ECB             :             bool        found;
 1601                           843                 : 
  368 andres                    844 GIC         811 :             entry = pgstat_snapshot_insert(pgStatLocal.snapshot.stats, key, &found);
                                845             811 :             Assert(!found);
  368 andres                    846 CBC         811 :             entry->data = NULL;
                                847                 :         }
                                848            2501 :         return NULL;
                                849                 :     }
 5932 tgl                       850 ECB             : 
                                851                 :     /*
                                852                 :      * Allocate in caller's context for PGSTAT_FETCH_CONSISTENCY_NONE,
  368 andres                    853                 :      * otherwise we could quickly end up with a fair bit of memory used due to
                                854                 :      * repeated accesses.
                                855                 :      */
  368 andres                    856 GIC        6008 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE)
                                857            2611 :         stats_data = palloc(kind_info->shared_data_len);
  368 andres                    858 ECB             :     else
  368 andres                    859 CBC        3397 :         stats_data = MemoryContextAlloc(pgStatLocal.snapshot.context,
                                860            3397 :                                         kind_info->shared_data_len);
                                861                 : 
  230                           862            6008 :     pgstat_lock_entry_shared(entry_ref, false);
  368 andres                    863 GIC       12016 :     memcpy(stats_data,
                                864            6008 :            pgstat_get_entry_data(kind, entry_ref->shared_stats),
                                865            6008 :            kind_info->shared_data_len);
  230                           866            6008 :     pgstat_unlock_entry(entry_ref);
                                867                 : 
  368                           868            6008 :     if (pgstat_fetch_consistency > PGSTAT_FETCH_CONSISTENCY_NONE)
                                869                 :     {
  368 andres                    870 CBC        3397 :         PgStat_SnapshotEntry *entry = NULL;
  368 andres                    871 ECB             :         bool        found;
                                872                 : 
  368 andres                    873 CBC        3397 :         entry = pgstat_snapshot_insert(pgStatLocal.snapshot.stats, key, &found);
                                874            3397 :         entry->data = stats_data;
                                875                 :     }
 5932 tgl                       876 ECB             : 
  368 andres                    877 CBC        6008 :     return stats_data;
 7961 JanWieck                  878 ECB             : }
                                879                 : 
  370 andres                    880                 : /*
                                881                 :  * If a stats snapshot has been taken, return the timestamp at which that was
  368                           882                 :  * done, and set *have_snapshot to true. Otherwise *have_snapshot is set to
                                883                 :  * false.
 6290 tgl                       884                 :  */
                                885                 : TimestampTz
  368 andres                    886 GIC          15 : pgstat_get_stat_snapshot_timestamp(bool *have_snapshot)
 6290 tgl                       887 ECB             : {
  368 andres                    888 CBC          15 :     if (pgStatLocal.snapshot.mode == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                                889                 :     {
  368 andres                    890 GIC           9 :         *have_snapshot = true;
  368 andres                    891 CBC           9 :         return pgStatLocal.snapshot.snapshot_timestamp;
                                892                 :     }
                                893                 : 
  368 andres                    894 GIC           6 :     *have_snapshot = false;
                                895                 : 
                                896               6 :     return 0;
                                897                 : }
                                898                 : 
                                899                 : bool
  367 andres                    900 CBC          79 : pgstat_have_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
                                901                 : {
  367 andres                    902 ECB             :     /* fixed-numbered stats always exist */
  367 andres                    903 GIC          79 :     if (pgstat_get_kind_info(kind)->fixed_amount)
  367 andres                    904 CBC           6 :         return true;
  367 andres                    905 ECB             : 
  367 andres                    906 GIC          73 :     return pgstat_get_entry_ref(kind, dboid, objoid, false, NULL) != NULL;
                                907                 : }
  367 andres                    908 ECB             : 
                                909                 : /*
  368                           910                 :  * Ensure snapshot for fixed-numbered 'kind' exists.
                                911                 :  *
                                912                 :  * Typically used by the pgstat_fetch_* functions for a kind of stats, before
                                913                 :  * massaging the data into the desired format.
 7961 JanWieck                  914                 :  */
                                915                 : void
  368 andres                    916 GIC         205 : pgstat_snapshot_fixed(PgStat_Kind kind)
 7961 JanWieck                  917 ECB             : {
  163 peter                     918 GNC         205 :     Assert(pgstat_is_kind_valid(kind));
                                919             205 :     Assert(pgstat_get_kind_info(kind)->fixed_amount);
 7961 JanWieck                  920 ECB             : 
  368 andres                    921 GIC         205 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                                922              12 :         pgstat_build_snapshot();
                                923                 :     else
                                924             193 :         pgstat_build_snapshot_fixed(kind);
                                925                 : 
                                926             205 :     Assert(pgStatLocal.snapshot.fixed_valid[kind]);
 7961 JanWieck                  927             205 : }
                                928                 : 
                                929                 : static void
  368 andres                    930 CBC        8805 : pgstat_prep_snapshot(void)
                                931                 : {
                                932            8805 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE ||
                                933            4504 :         pgStatLocal.snapshot.stats != NULL)
 4828 magnus                    934 GIC        8419 :         return;
 4828 magnus                    935 ECB             : 
  368 andres                    936 CBC         386 :     if (!pgStatLocal.snapshot.context)
  368 andres                    937 GIC         386 :         pgStatLocal.snapshot.context = AllocSetContextCreate(TopMemoryContext,
  368 andres                    938 ECB             :                                                              "PgStat Snapshot",
                                939                 :                                                              ALLOCSET_SMALL_SIZES);
 4819 magnus                    940                 : 
  368 andres                    941 CBC         386 :     pgStatLocal.snapshot.stats =
  368 andres                    942 GIC         386 :         pgstat_snapshot_create(pgStatLocal.snapshot.context,
                                943                 :                                PGSTAT_SNAPSHOT_HASH_SIZE,
  368 andres                    944 ECB             :                                NULL);
                                945                 : }
 4819 magnus                    946                 : 
  384 andres                    947                 : static void
  368 andres                    948 CBC         239 : pgstat_build_snapshot(void)
                                949                 : {
  368 andres                    950 ECB             :     dshash_seq_status hstat;
                                951                 :     PgStatShared_HashEntry *p;
                                952                 : 
                                953                 :     /* should only be called when we need a snapshot */
  368 andres                    954 GIC         239 :     Assert(pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT);
 1102 tomas.vondra              955 ECB             : 
  368 andres                    956                 :     /* snapshot already built */
  368 andres                    957 GIC         239 :     if (pgStatLocal.snapshot.mode == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                                958             216 :         return;
                                959                 : 
                                960              23 :     pgstat_prep_snapshot();
                                961                 : 
  368 andres                    962 CBC          23 :     Assert(pgStatLocal.snapshot.stats->members == 0);
                                963                 : 
  368 andres                    964 GIC          23 :     pgStatLocal.snapshot.snapshot_timestamp = GetCurrentTimestamp();
                                965                 : 
                                966                 :     /*
                                967                 :      * Snapshot all variable stats.
 7961 JanWieck                  968 ECB             :      */
  368 andres                    969 GIC          23 :     dshash_seq_init(&hstat, pgStatLocal.shared_hash, false);
                                970           18669 :     while ((p = dshash_seq_next(&hstat)) != NULL)
  368 andres                    971 ECB             :     {
  368 andres                    972 CBC       18646 :         PgStat_Kind kind = p->key.kind;
  368 andres                    973 GIC       18646 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
  368 andres                    974 ECB             :         bool        found;
                                975                 :         PgStat_SnapshotEntry *entry;
                                976                 :         PgStatShared_Common *stats_data;
                                977                 : 
                                978                 :         /*
                                979                 :          * Check if the stats object should be included in the snapshot.
                                980                 :          * Unless the stats kind can be accessed from all databases (e.g.,
                                981                 :          * database stats themselves), we only include stats for the current
                                982                 :          * database or objects not associated with a database (e.g. shared
                                983                 :          * relations).
                                984                 :          */
  368 andres                    985 GIC       18646 :         if (p->key.dboid != MyDatabaseId &&
  368 andres                    986 CBC        6832 :             p->key.dboid != InvalidOid &&
                                987            5560 :             !kind_info->accessed_across_databases)
  368 andres                    988 GIC        5616 :             continue;
                                989                 : 
                                990           13132 :         if (p->dropped)
                                991             102 :             continue;
                                992                 : 
                                993           13030 :         Assert(pg_atomic_read_u32(&p->refcount) > 0);
                                994                 : 
                                995           13030 :         stats_data = dsa_get_address(pgStatLocal.dsa, p->body);
                                996           13030 :         Assert(stats_data);
                                997                 : 
                                998           13030 :         entry = pgstat_snapshot_insert(pgStatLocal.snapshot.stats, p->key, &found);
  368 andres                    999 CBC       13030 :         Assert(!found);
  368 andres                   1000 ECB             : 
  368 andres                   1001 CBC       26060 :         entry->data = MemoryContextAlloc(pgStatLocal.snapshot.context,
                               1002           13030 :                                          kind_info->shared_size);
                               1003                 : 
                               1004                 :         /*
  230 andres                   1005 ECB             :          * Acquire the LWLock directly instead of using
                               1006                 :          * pg_stat_lock_entry_shared() which requires a reference.
                               1007                 :          */
  230 andres                   1008 CBC       13030 :         LWLockAcquire(&stats_data->lock, LW_SHARED);
  368 andres                   1009 GIC       26060 :         memcpy(entry->data,
  368 andres                   1010 CBC       13030 :                pgstat_get_entry_data(kind, stats_data),
                               1011           13030 :                kind_info->shared_size);
  230 andres                   1012 GIC       13030 :         LWLockRelease(&stats_data->lock);
  368 andres                   1013 ECB             :     }
  368 andres                   1014 CBC          23 :     dshash_seq_term(&hstat);
                               1015                 : 
  384 andres                   1016 ECB             :     /*
  368                          1017                 :      * Build snapshot of all fixed-numbered stats.
                               1018                 :      */
  368 andres                   1019 GIC         276 :     for (int kind = PGSTAT_KIND_FIRST_VALID; kind <= PGSTAT_KIND_LAST; kind++)
                               1020                 :     {
                               1021             253 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1022                 : 
  368 andres                   1023 CBC         253 :         if (!kind_info->fixed_amount)
  368 andres                   1024 ECB             :         {
  368 andres                   1025 CBC         115 :             Assert(kind_info->snapshot_cb == NULL);
                               1026             115 :             continue;
  368 andres                   1027 ECB             :         }
                               1028                 : 
  368 andres                   1029 CBC         138 :         pgstat_build_snapshot_fixed(kind);
                               1030                 :     }
                               1031                 : 
  368 andres                   1032 GIC          23 :     pgStatLocal.snapshot.mode = PGSTAT_FETCH_CONSISTENCY_SNAPSHOT;
                               1033                 : }
 7961 JanWieck                 1034 ECB             : 
                               1035                 : static void
  368 andres                   1036 CBC        6145 : pgstat_build_snapshot_fixed(PgStat_Kind kind)
                               1037                 : {
                               1038            6145 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1039                 : 
                               1040            6145 :     Assert(kind_info->fixed_amount);
                               1041            6145 :     Assert(kind_info->snapshot_cb != NULL);
                               1042                 : 
  368 andres                   1043 GIC        6145 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE)
 6463 tgl                      1044 ECB             :     {
                               1045                 :         /* rebuild every time */
  368 andres                   1046 GIC        5829 :         pgStatLocal.snapshot.fixed_valid[kind] = false;
 6463 tgl                      1047 ECB             :     }
  368 andres                   1048 GIC         316 :     else if (pgStatLocal.snapshot.fixed_valid[kind])
                               1049                 :     {
                               1050                 :         /* in snapshot mode we shouldn't get called again */
  368 andres                   1051 CBC           6 :         Assert(pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_CACHE);
  368 andres                   1052 GIC           6 :         return;
 6463 tgl                      1053 ECB             :     }
                               1054                 : 
  368 andres                   1055 CBC        6139 :     Assert(!pgStatLocal.snapshot.fixed_valid[kind]);
  368 andres                   1056 ECB             : 
  368 andres                   1057 GIC        6139 :     kind_info->snapshot_cb();
  368 andres                   1058 ECB             : 
  368 andres                   1059 GIC        6139 :     Assert(!pgStatLocal.snapshot.fixed_valid[kind]);
                               1060            6139 :     pgStatLocal.snapshot.fixed_valid[kind] = true;
 7961 JanWieck                 1061 ECB             : }
                               1062                 : 
                               1063                 : 
                               1064                 : /* ------------------------------------------------------------
                               1065                 :  * Backend-local pending stats infrastructure
  368 andres                   1066                 :  * ------------------------------------------------------------
                               1067                 :  */
                               1068                 : 
                               1069                 : /*
                               1070                 :  * Returns the appropriate PgStat_EntryRef, preparing it to receive pending
                               1071                 :  * stats if not already done.
                               1072                 :  *
                               1073                 :  * If created_entry is non-NULL, it'll be set to true if the entry is newly
                               1074                 :  * created, false otherwise.
 5442 tgl                      1075                 :  */
                               1076                 : PgStat_EntryRef *
  368 andres                   1077 GIC     1541192 : pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, Oid objoid, bool *created_entry)
                               1078                 : {
                               1079                 :     PgStat_EntryRef *entry_ref;
                               1080                 : 
                               1081                 :     /* need to be able to flush out */
                               1082         1541192 :     Assert(pgstat_get_kind_info(kind)->flush_pending_cb != NULL);
                               1083                 : 
                               1084         1541192 :     if (unlikely(!pgStatPendingContext))
                               1085                 :     {
                               1086           12442 :         pgStatPendingContext =
  205                          1087           12442 :             AllocSetContextCreate(TopMemoryContext,
                               1088                 :                                   "PgStat Pending",
                               1089                 :                                   ALLOCSET_SMALL_SIZES);
                               1090                 :     }
                               1091                 : 
  368 andres                   1092 CBC     1541192 :     entry_ref = pgstat_get_entry_ref(kind, dboid, objoid,
                               1093                 :                                      true, created_entry);
                               1094                 : 
  368 andres                   1095 GIC     1541192 :     if (entry_ref->pending == NULL)
                               1096                 :     {
  368 andres                   1097 CBC      787083 :         size_t      entrysize = pgstat_get_kind_info(kind)->pending_size;
                               1098                 : 
                               1099          787083 :         Assert(entrysize != (size_t) -1);
                               1100                 : 
                               1101          787083 :         entry_ref->pending = MemoryContextAllocZero(pgStatPendingContext, entrysize);
                               1102          787083 :         dlist_push_tail(&pgStatPending, &entry_ref->pending_node);
                               1103                 :     }
                               1104                 : 
  368 andres                   1105 GIC     1541192 :     return entry_ref;
                               1106                 : }
  613 andres                   1107 ECB             : 
                               1108                 : /*
                               1109                 :  * Return an existing stats entry, or NULL.
  368                          1110                 :  *
                               1111                 :  * This should only be used for helper function for pgstatfuncs.c - outside of
                               1112                 :  * that it shouldn't be needed.
                               1113                 :  */
                               1114                 : PgStat_EntryRef *
  368 andres                   1115 GIC          42 : pgstat_fetch_pending_entry(PgStat_Kind kind, Oid dboid, Oid objoid)
  613 andres                   1116 ECB             : {
  368                          1117                 :     PgStat_EntryRef *entry_ref;
                               1118                 : 
  368 andres                   1119 GIC          42 :     entry_ref = pgstat_get_entry_ref(kind, dboid, objoid, false, NULL);
 3357 fujii                    1120 ECB             : 
  368 andres                   1121 GIC          42 :     if (entry_ref == NULL || entry_ref->pending == NULL)
                               1122              15 :         return NULL;
                               1123                 : 
                               1124              27 :     return entry_ref;
                               1125                 : }
                               1126                 : 
                               1127                 : void
                               1128          787083 : pgstat_delete_pending_entry(PgStat_EntryRef *entry_ref)
                               1129                 : {
  368 andres                   1130 CBC      787083 :     PgStat_Kind kind = entry_ref->shared_entry->key.kind;
  368 andres                   1131 GIC      787083 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1132          787083 :     void       *pending_data = entry_ref->pending;
                               1133                 : 
  368 andres                   1134 CBC      787083 :     Assert(pending_data != NULL);
                               1135                 :     /* !fixed_amount stats should be handled explicitly */
                               1136          787083 :     Assert(!pgstat_get_kind_info(kind)->fixed_amount);
 1102 tomas.vondra             1137 ECB             : 
  368 andres                   1138 GIC      787083 :     if (kind_info->delete_pending_cb)
  368 andres                   1139 CBC      745356 :         kind_info->delete_pending_cb(entry_ref);
                               1140                 : 
  368 andres                   1141 GIC      787083 :     pfree(pending_data);
                               1142          787083 :     entry_ref->pending = NULL;
  913 akapila                  1143 ECB             : 
  368 andres                   1144 GIC      787083 :     dlist_delete(&entry_ref->pending_node);
  913 akapila                  1145 CBC      787083 : }
 1102 tomas.vondra             1146 ECB             : 
  404 akapila                  1147                 : /*
                               1148                 :  * Flush out pending stats for database objects (databases, relations,
  368 andres                   1149                 :  * functions).
                               1150                 :  */
                               1151                 : static bool
  368 andres                   1152 GIC       24454 : pgstat_flush_pending_entries(bool nowait)
  404 akapila                  1153 ECB             : {
  368 andres                   1154 CBC       24454 :     bool        have_pending = false;
  368 andres                   1155 GIC       24454 :     dlist_node *cur = NULL;
  368 andres                   1156 ECB             : 
                               1157                 :     /*
                               1158                 :      * Need to be a bit careful iterating over the list of pending entries.
                               1159                 :      * Processing a pending entry may queue further pending entries to the end
                               1160                 :      * of the list that we want to process, so a simple iteration won't do.
                               1161                 :      * Further complicating matters is that we want to delete the current
                               1162                 :      * entry in each iteration from the list if we flushed successfully.
                               1163                 :      *
                               1164                 :      * So we just keep track of the next pointer in each loop iteration.
                               1165                 :      */
  368 andres                   1166 GIC       24454 :     if (!dlist_is_empty(&pgStatPending))
  368 andres                   1167 CBC       24454 :         cur = dlist_head_node(&pgStatPending);
                               1168                 : 
                               1169          783818 :     while (cur)
  368 andres                   1170 ECB             :     {
  368 andres                   1171 GIC      759364 :         PgStat_EntryRef *entry_ref =
                               1172          759364 :         dlist_container(PgStat_EntryRef, pending_node, cur);
                               1173          759364 :         PgStat_HashKey key = entry_ref->shared_entry->key;
                               1174          759364 :         PgStat_Kind kind = key.kind;
                               1175          759364 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1176                 :         bool        did_flush;
                               1177                 :         dlist_node *next;
                               1178                 : 
                               1179          759364 :         Assert(!kind_info->fixed_amount);
                               1180          759364 :         Assert(kind_info->flush_pending_cb != NULL);
  368 andres                   1181 ECB             : 
                               1182                 :         /* flush the stats, if possible */
  368 andres                   1183 GIC      759364 :         did_flush = kind_info->flush_pending_cb(entry_ref, nowait);
  368 andres                   1184 ECB             : 
  368 andres                   1185 GIC      759364 :         Assert(did_flush || nowait);
  404 akapila                  1186 ECB             : 
  368 andres                   1187                 :         /* determine next entry, before deleting the pending entry */
  368 andres                   1188 CBC      759364 :         if (dlist_has_next(&pgStatPending, cur))
                               1189          734910 :             next = dlist_next_node(&pgStatPending, cur);
  368 andres                   1190 ECB             :         else
  368 andres                   1191 GIC       24454 :             next = NULL;
                               1192                 : 
                               1193                 :         /* if successfully flushed, remove entry */
  368 andres                   1194 CBC      759364 :         if (did_flush)
                               1195          759359 :             pgstat_delete_pending_entry(entry_ref);
                               1196                 :         else
  368 andres                   1197 GIC           5 :             have_pending = true;
  368 andres                   1198 ECB             : 
  368 andres                   1199 GIC      759364 :         cur = next;
  368 andres                   1200 ECB             :     }
                               1201                 : 
  368 andres                   1202 GIC       24454 :     Assert(dlist_is_empty(&pgStatPending) == !have_pending);
  368 andres                   1203 ECB             : 
  368 andres                   1204 CBC       24454 :     return have_pending;
                               1205                 : }
  404 akapila                  1206 ECB             : 
                               1207                 : 
                               1208                 : /* ------------------------------------------------------------
  384 andres                   1209                 :  * Helper / infrastructure functions
                               1210                 :  * ------------------------------------------------------------
                               1211                 :  */
 6138 tgl                      1212                 : 
                               1213                 : PgStat_Kind
  368 andres                   1214 CBC          82 : pgstat_get_kind_from_str(char *kind_str)
                               1215                 : {
  368 andres                   1216 GIC         233 :     for (int kind = PGSTAT_KIND_FIRST_VALID; kind <= PGSTAT_KIND_LAST; kind++)
  368 andres                   1217 ECB             :     {
  368 andres                   1218 GIC         230 :         if (pg_strcasecmp(kind_str, pgstat_kind_infos[kind].name) == 0)
  368 andres                   1219 CBC          79 :             return kind;
                               1220                 :     }
                               1221                 : 
  368 andres                   1222 GIC           3 :     ereport(ERROR,
                               1223                 :             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               1224                 :              errmsg("invalid statistics kind: \"%s\"", kind_str)));
                               1225                 :     return PGSTAT_KIND_DATABASE;    /* avoid compiler warnings */
                               1226                 : }
                               1227                 : 
                               1228                 : static inline bool
  368 andres                   1229 CBC     6176704 : pgstat_is_kind_valid(int ikind)
                               1230                 : {
                               1231         6176704 :     return ikind >= PGSTAT_KIND_FIRST_VALID && ikind <= PGSTAT_KIND_LAST;
                               1232                 : }
  368 andres                   1233 ECB             : 
                               1234                 : const PgStat_KindInfo *
  368 andres                   1235 GIC     6022445 : pgstat_get_kind_info(PgStat_Kind kind)
                               1236                 : {
  163 peter                    1237 GNC     6022445 :     Assert(pgstat_is_kind_valid(kind));
                               1238                 : 
  368 andres                   1239 GIC     6022445 :     return &pgstat_kind_infos[kind];
                               1240                 : }
                               1241                 : 
                               1242                 : /*
                               1243                 :  * Stats should only be reported after pgstat_initialize() and before
  384 andres                   1244 ECB             :  * pgstat_shutdown(). This check is put in a few central places to catch
                               1245                 :  * violations of this rule more easily.
 6138 tgl                      1246                 :  */
                               1247                 : #ifdef USE_ASSERT_CHECKING
                               1248                 : void
  384 andres                   1249 GIC     4873592 : pgstat_assert_is_up(void)
  384 andres                   1250 ECB             : {
  384 andres                   1251 GIC     4873592 :     Assert(pgstat_is_initialized && !pgstat_is_shutdown);
  384 andres                   1252 CBC     4873592 : }
                               1253                 : #endif
 6138 tgl                      1254 ECB             : 
                               1255                 : 
                               1256                 : /* ------------------------------------------------------------
                               1257                 :  * reading and writing of on-disk stats file
                               1258                 :  * ------------------------------------------------------------
                               1259                 :  */
                               1260                 : 
                               1261                 : /* helpers for pgstat_write_statsfile() */
                               1262                 : static void
  368 andres                   1263 GIC      453092 : write_chunk(FILE *fpout, void *ptr, size_t len)
  384 andres                   1264 ECB             : {
                               1265                 :     int         rc;
                               1266                 : 
  368 andres                   1267 CBC      453092 :     rc = fwrite(ptr, len, 1, fpout);
                               1268                 : 
                               1269                 :     /* we'll check for errors with ferror once at the end */
                               1270                 :     (void) rc;
  384 andres                   1271 GIC      453092 : }
                               1272                 : 
                               1273                 : #define write_chunk_s(fpout, ptr) write_chunk(fpout, ptr, sizeof(*ptr))
                               1274                 : 
                               1275                 : /*
                               1276                 :  * This function is called in the last process that is accessing the shared
                               1277                 :  * stats so locking is not required.
 7961 JanWieck                 1278 ECB             :  */
                               1279                 : static void
  368 andres                   1280 GIC         969 : pgstat_write_statsfile(void)
                               1281                 : {
 7836 bruce                    1282 ECB             :     FILE       *fpout;
                               1283                 :     int32       format_id;
  368 andres                   1284 GIC         969 :     const char *tmpfile = PGSTAT_STAT_PERMANENT_TMPFILE;
                               1285             969 :     const char *statfile = PGSTAT_STAT_PERMANENT_FILENAME;
  368 andres                   1286 ECB             :     dshash_seq_status hstat;
                               1287                 :     PgStatShared_HashEntry *ps;
                               1288                 : 
  368 andres                   1289 GIC         969 :     pgstat_assert_is_up();
                               1290                 : 
                               1291                 :     /* we're shutting down, so it's ok to just override this */
                               1292             969 :     pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_NONE;
                               1293                 : 
 3041 tgl                      1294             969 :     elog(DEBUG2, "writing stats file \"%s\"", statfile);
 3702 alvherre                 1295 ECB             : 
                               1296                 :     /*
                               1297                 :      * Open the statistics temp file to write out the current values.
                               1298                 :      */
 5270 tgl                      1299 CBC         969 :     fpout = AllocateFile(tmpfile, PG_BINARY_W);
 7961 JanWieck                 1300             969 :     if (fpout == NULL)
                               1301                 :     {
 7201 tgl                      1302 UIC           0 :         ereport(LOG,
                               1303                 :                 (errcode_for_file_access(),
 6385 bruce                    1304 ECB             :                  errmsg("could not open temporary statistics file \"%s\": %m",
                               1305                 :                         tmpfile)));
 7961 JanWieck                 1306 UIC           0 :         return;
 7961 JanWieck                 1307 ECB             :     }
                               1308                 : 
 6478 tgl                      1309                 :     /*
                               1310                 :      * Write the file header --- currently just a format ID.
                               1311                 :      */
 6478 tgl                      1312 GIC         969 :     format_id = PGSTAT_FILE_FORMAT_ID;
  368 andres                   1313             969 :     write_chunk_s(fpout, &format_id);
 6478 tgl                      1314 ECB             : 
 5854 magnus                   1315                 :     /*
                               1316                 :      * XXX: The following could now be generalized to just iterate over
  368 andres                   1317 EUB             :      * pgstat_kind_infos instead of knowing about the different kinds of
                               1318                 :      * stats.
                               1319                 :      */
                               1320                 : 
 3357 fujii                    1321                 :     /*
                               1322                 :      * Write archiver stats struct
                               1323                 :      */
  368 andres                   1324 GIC         969 :     pgstat_build_snapshot_fixed(PGSTAT_KIND_ARCHIVER);
                               1325             969 :     write_chunk_s(fpout, &pgStatLocal.snapshot.archiver);
                               1326                 : 
  919 fujii                    1327 ECB             :     /*
  368 andres                   1328                 :      * Write bgwriter stats struct
                               1329                 :      */
  368 andres                   1330 GIC         969 :     pgstat_build_snapshot_fixed(PGSTAT_KIND_BGWRITER);
                               1331             969 :     write_chunk_s(fpout, &pgStatLocal.snapshot.bgwriter);
                               1332                 : 
                               1333                 :     /*
                               1334                 :      * Write checkpointer stats struct
                               1335                 :      */
                               1336             969 :     pgstat_build_snapshot_fixed(PGSTAT_KIND_CHECKPOINTER);
                               1337             969 :     write_chunk_s(fpout, &pgStatLocal.snapshot.checkpointer);
                               1338                 : 
                               1339                 :     /*
                               1340                 :      * Write IO stats struct
                               1341                 :      */
   60 andres                   1342 GNC         969 :     pgstat_build_snapshot_fixed(PGSTAT_KIND_IO);
                               1343             969 :     write_chunk_s(fpout, &pgStatLocal.snapshot.io);
                               1344                 : 
 7961 JanWieck                 1345 ECB             :     /*
  368 andres                   1346                 :      * Write SLRU stats struct
                               1347                 :      */
  368 andres                   1348 GIC         969 :     pgstat_build_snapshot_fixed(PGSTAT_KIND_SLRU);
                               1349             969 :     write_chunk_s(fpout, &pgStatLocal.snapshot.slru);
                               1350                 : 
  913 akapila                  1351 ECB             :     /*
  368 andres                   1352                 :      * Write WAL stats struct
                               1353                 :      */
  368 andres                   1354 GIC         969 :     pgstat_build_snapshot_fixed(PGSTAT_KIND_WAL);
                               1355             969 :     write_chunk_s(fpout, &pgStatLocal.snapshot.wal);
                               1356                 : 
  404 akapila                  1357 ECB             :     /*
  368 andres                   1358                 :      * Walk through the stats entries
                               1359                 :      */
  368 andres                   1360 GIC         969 :     dshash_seq_init(&hstat, pgStatLocal.shared_hash, false);
                               1361          224102 :     while ((ps = dshash_seq_next(&hstat)) != NULL)
                               1362                 :     {
  368 andres                   1363 ECB             :         PgStatShared_Common *shstats;
  368 andres                   1364 CBC      223133 :         const PgStat_KindInfo *kind_info = NULL;
                               1365                 : 
  368 andres                   1366 GIC      223133 :         CHECK_FOR_INTERRUPTS();
                               1367                 : 
                               1368                 :         /* we may have some "dropped" entries not yet removed, skip them */
  368 andres                   1369 CBC      223133 :         Assert(!ps->dropped);
                               1370          223133 :         if (ps->dropped)
  368 andres                   1371 UIC           0 :             continue;
                               1372                 : 
  368 andres                   1373 GIC      223133 :         shstats = (PgStatShared_Common *) dsa_get_address(pgStatLocal.dsa, ps->body);
                               1374                 : 
  368 andres                   1375 CBC      223133 :         kind_info = pgstat_get_kind_info(ps->key.kind);
  368 andres                   1376 ECB             : 
                               1377                 :         /* if not dropped the valid-entry refcount should exist */
  368 andres                   1378 GIC      223133 :         Assert(pg_atomic_read_u32(&ps->refcount) > 0);
                               1379                 : 
                               1380          223133 :         if (!kind_info->to_serialized_name)
  404 akapila                  1381 ECB             :         {
  368 andres                   1382                 :             /* normal stats entry, identified by PgStat_HashKey */
  404 akapila                  1383 GIC      223090 :             fputc('S', fpout);
  368 andres                   1384          223090 :             write_chunk_s(fpout, &ps->key);
  404 akapila                  1385 ECB             :         }
                               1386                 :         else
  368 andres                   1387                 :         {
                               1388                 :             /* stats entry identified by name on disk (e.g. slots) */
                               1389                 :             NameData    name;
                               1390                 : 
  183 andres                   1391 CBC          43 :             kind_info->to_serialized_name(&ps->key, shstats, &name);
  368 andres                   1392 EUB             : 
  368 andres                   1393 GIC          43 :             fputc('N', fpout);
  368 andres                   1394 CBC          43 :             write_chunk_s(fpout, &ps->key.kind);
  368 andres                   1395 GIC          43 :             write_chunk_s(fpout, &name);
  368 andres                   1396 ECB             :         }
                               1397                 : 
                               1398                 :         /* Write except the header part of the entry */
  368 andres                   1399 CBC      223133 :         write_chunk(fpout,
                               1400                 :                     pgstat_get_entry_data(ps->key.kind, shstats),
  368 andres                   1401 ECB             :                     pgstat_get_entry_len(ps->key.kind));
                               1402                 :     }
  368 andres                   1403 GIC         969 :     dshash_seq_term(&hstat);
  404 akapila                  1404 ECB             : 
 7961 JanWieck                 1405                 :     /*
                               1406                 :      * No more output to be done. Close the temp file and replace the old
                               1407                 :      * pgstat.stat with it.  The ferror() check replaces testing for error
                               1408                 :      * after each individual fputc or fwrite (in write_chunk()) above.
                               1409                 :      */
 7961 JanWieck                 1410 GIC         969 :     fputc('E', fpout);
                               1411                 : 
 6290 tgl                      1412 CBC         969 :     if (ferror(fpout))
                               1413                 :     {
 6290 tgl                      1414 LBC           0 :         ereport(LOG,
 6290 tgl                      1415 ECB             :                 (errcode_for_file_access(),
 2118                          1416                 :                  errmsg("could not write temporary statistics file \"%s\": %m",
                               1417                 :                         tmpfile)));
 5270 tgl                      1418 UIC           0 :         FreeFile(fpout);
 5360 magnus                   1419               0 :         unlink(tmpfile);
 6290 tgl                      1420 ECB             :     }
 5270 tgl                      1421 GIC         969 :     else if (FreeFile(fpout) < 0)
                               1422                 :     {
 7201 tgl                      1423 UIC           0 :         ereport(LOG,
 7201 tgl                      1424 ECB             :                 (errcode_for_file_access(),
                               1425                 :                  errmsg("could not close temporary statistics file \"%s\": %m",
                               1426                 :                         tmpfile)));
 5360 magnus                   1427 UIC           0 :         unlink(tmpfile);
                               1428                 :     }
 5360 magnus                   1429 GIC         969 :     else if (rename(tmpfile, statfile) < 0)
                               1430                 :     {
 6290 tgl                      1431 LBC           0 :         ereport(LOG,
                               1432                 :                 (errcode_for_file_access(),
 6290 tgl                      1433 ECB             :                  errmsg("could not rename temporary statistics file \"%s\" to \"%s\": %m",
                               1434                 :                         tmpfile, statfile)));
 5360 magnus                   1435 UBC           0 :         unlink(tmpfile);
                               1436                 :     }
                               1437                 : }
                               1438                 : 
  368 andres                   1439 EUB             : /* helpers for pgstat_read_statsfile() */
                               1440                 : static bool
  368 andres                   1441 GIC      313298 : read_chunk(FILE *fpin, void *ptr, size_t len)
 3702 alvherre                 1442 ECB             : {
  368 andres                   1443 GIC      313298 :     return fread(ptr, 1, len, fpin) == len;
 7961 JanWieck                 1444 EUB             : }
                               1445                 : 
                               1446                 : #define read_chunk_s(fpin, ptr) read_chunk(fpin, ptr, sizeof(*ptr))
                               1447                 : 
  370 andres                   1448                 : /*
                               1449                 :  * Reads in existing statistics file into the shared stats hash.
 2504 tgl                      1450 ECB             :  *
                               1451                 :  * This function is called in the only process that is accessing the shared
  368 andres                   1452 EUB             :  * stats so locking is not required.
                               1453                 :  */
                               1454                 : static void
  368 andres                   1455 GIC        1045 : pgstat_read_statsfile(void)
 7961 JanWieck                 1456 EUB             : {
                               1457                 :     FILE       *fpin;
                               1458                 :     int32       format_id;
                               1459                 :     bool        found;
  368 andres                   1460 GIC        1045 :     const char *statfile = PGSTAT_STAT_PERMANENT_FILENAME;
                               1461            1045 :     PgStat_ShmemControl *shmem = pgStatLocal.shmem;
 5854 magnus                   1462 ECB             : 
                               1463                 :     /* shouldn't be called from postmaster */
  368 andres                   1464 CBC        1045 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
                               1465                 : 
  368 andres                   1466 GIC        1045 :     elog(DEBUG2, "reading stats file \"%s\"", statfile);
                               1467                 : 
                               1468                 :     /*
                               1469                 :      * Try to open the stats file. If it doesn't exist, the backends simply
                               1470                 :      * returns zero for anything and statistics simply starts from scratch
                               1471                 :      * with empty counters.
                               1472                 :      *
                               1473                 :      * ENOENT is a possibility if stats collection was previously disabled or
                               1474                 :      * has not yet written the stats file for the first time.  Any other
                               1475                 :      * failure condition is suspicious.
 7961 JanWieck                 1476 ECB             :      */
 5360 magnus                   1477 GIC        1045 :     if ((fpin = AllocateFile(statfile, PG_BINARY_R)) == NULL)
                               1478                 :     {
 4776 tgl                      1479             305 :         if (errno != ENOENT)
  368 andres                   1480 UIC           0 :             ereport(LOG,
 4776 tgl                      1481 ECB             :                     (errcode_for_file_access(),
                               1482                 :                      errmsg("could not open statistics file \"%s\": %m",
                               1483                 :                             statfile)));
  360 andres                   1484 GIC         305 :         pgstat_reset_after_failure();
  368 andres                   1485 CBC         305 :         return;
                               1486                 :     }
 7961 JanWieck                 1487 ECB             : 
                               1488                 :     /*
                               1489                 :      * Verify it's of the expected format.
                               1490                 :      */
  368 andres                   1491 GIC         740 :     if (!read_chunk_s(fpin, &format_id) ||
 3702 alvherre                 1492             740 :         format_id != PGSTAT_FILE_FORMAT_ID)
  368 andres                   1493               1 :         goto error;
                               1494                 : 
                               1495                 :     /*
                               1496                 :      * XXX: The following could now be generalized to just iterate over
                               1497                 :      * pgstat_kind_infos instead of knowing about the different kinds of
  368 andres                   1498 ECB             :      * stats.
                               1499                 :      */
 5854 magnus                   1500                 : 
 2113 tgl                      1501 EUB             :     /*
                               1502                 :      * Read archiver stats struct
                               1503                 :      */
  368 andres                   1504 GIC         739 :     if (!read_chunk_s(fpin, &shmem->archiver.stats))
  368 andres                   1505 LBC           0 :         goto error;
 2113 tgl                      1506 ECB             : 
                               1507                 :     /*
                               1508                 :      * Read bgwriter stats struct
                               1509                 :      */
  368 andres                   1510 GIC         739 :     if (!read_chunk_s(fpin, &shmem->bgwriter.stats))
  368 andres                   1511 UIC           0 :         goto error;
 3357 fujii                    1512 ECB             : 
  919                          1513                 :     /*
  368 andres                   1514                 :      * Read checkpointer stats struct
                               1515                 :      */
  368 andres                   1516 GIC         739 :     if (!read_chunk_s(fpin, &shmem->checkpointer.stats))
  368 andres                   1517 UIC           0 :         goto error;
                               1518                 : 
                               1519                 :     /*
                               1520                 :      * Read IO stats struct
                               1521                 :      */
   60 andres                   1522 GNC         739 :     if (!read_chunk_s(fpin, &shmem->io.stats))
   60 andres                   1523 UNC           0 :         goto error;
                               1524                 : 
                               1525                 :     /*
                               1526                 :      * Read SLRU stats struct
                               1527                 :      */
  368 andres                   1528 GIC         739 :     if (!read_chunk_s(fpin, &shmem->slru.stats))
  368 andres                   1529 UIC           0 :         goto error;
                               1530                 : 
  368 andres                   1531 ECB             :     /*
  368 andres                   1532 EUB             :      * Read WAL stats struct
                               1533                 :      */
  368 andres                   1534 GIC         739 :     if (!read_chunk_s(fpin, &shmem->wal.stats))
  368 andres                   1535 UIC           0 :         goto error;
                               1536                 : 
 7961 JanWieck                 1537 ECB             :     /*
  368 andres                   1538 EUB             :      * We found an existing statistics file. Read it and put all the hash
                               1539                 :      * table entries into place.
                               1540                 :      */
                               1541                 :     for (;;)
 7961 JanWieck                 1542 GIC      154054 :     {
  363 tgl                      1543 CBC      154793 :         int         t = fgetc(fpin);
 7961 JanWieck                 1544 EUB             : 
  368 andres                   1545 GIC      154793 :         switch (t)
                               1546                 :         {
                               1547          154054 :             case 'S':
                               1548                 :             case 'N':
 6463 tgl                      1549 ECB             :                 {
  368 andres                   1550 EUB             :                     PgStat_HashKey key;
                               1551                 :                     PgStatShared_HashEntry *p;
                               1552                 :                     PgStatShared_Common *header;
                               1553                 : 
  368 andres                   1554 GIC      154054 :                     CHECK_FOR_INTERRUPTS();
  712 akapila                  1555 ECB             : 
  368 andres                   1556 GBC      154054 :                     if (t == 'S')
                               1557                 :                     {
                               1558                 :                         /* normal stats entry, identified by PgStat_HashKey */
  368 andres                   1559 GIC      154037 :                         if (!read_chunk_s(fpin, &key))
  368 andres                   1560 UIC           0 :                             goto error;
  712 akapila                  1561 ECB             : 
  368 andres                   1562 GBC      154037 :                         if (!pgstat_is_kind_valid(key.kind))
  368 andres                   1563 UIC           0 :                             goto error;
                               1564                 :                     }
                               1565                 :                     else
                               1566                 :                     {
                               1567                 :                         /* stats entry identified by name on disk (e.g. slots) */
  368 andres                   1568 GIC          17 :                         const PgStat_KindInfo *kind_info = NULL;
  368 andres                   1569 ECB             :                         PgStat_Kind kind;
                               1570                 :                         NameData    name;
                               1571                 : 
  368 andres                   1572 CBC          17 :                         if (!read_chunk_s(fpin, &kind))
  368 andres                   1573 UIC           0 :                             goto error;
  368 andres                   1574 CBC          17 :                         if (!read_chunk_s(fpin, &name))
  368 andres                   1575 UIC           0 :                             goto error;
  368 andres                   1576 GIC          17 :                         if (!pgstat_is_kind_valid(kind))
  368 andres                   1577 UIC           0 :                             goto error;
                               1578                 : 
  368 andres                   1579 GIC          17 :                         kind_info = pgstat_get_kind_info(kind);
                               1580                 : 
  368 andres                   1581 CBC          17 :                         if (!kind_info->from_serialized_name)
  368 andres                   1582 UIC           0 :                             goto error;
  368 andres                   1583 ECB             : 
  368 andres                   1584 GIC          17 :                         if (!kind_info->from_serialized_name(&name, &key))
                               1585                 :                         {
  368 andres                   1586 ECB             :                             /* skip over data for entry we don't care about */
  368 andres                   1587 GBC           1 :                             if (fseek(fpin, pgstat_get_entry_len(kind), SEEK_CUR) != 0)
  368 andres                   1588 UIC           0 :                                 goto error;
  368 andres                   1589 ECB             : 
  368 andres                   1590 GBC           1 :                             continue;
                               1591                 :                         }
                               1592                 : 
  368 andres                   1593 GIC          16 :                         Assert(key.kind == kind);
                               1594                 :                     }
  404 akapila                  1595 ECB             : 
                               1596                 :                     /*
                               1597                 :                      * This intentionally doesn't use pgstat_get_entry_ref() -
                               1598                 :                      * putting all stats into checkpointer's
  368 andres                   1599                 :                      * pgStatEntryRefHash would be wasted effort and memory.
  368 andres                   1600 EUB             :                      */
  368 andres                   1601 CBC      154053 :                     p = dshash_find_or_insert(pgStatLocal.shared_hash, &key, &found);
  368 andres                   1602 EUB             : 
  368 andres                   1603 ECB             :                     /* don't allow duplicate entries */
  368 andres                   1604 GBC      154053 :                     if (found)
                               1605                 :                     {
  368 andres                   1606 LBC           0 :                         dshash_release_lock(pgStatLocal.shared_hash, p);
  368 andres                   1607 UIC           0 :                         elog(WARNING, "found duplicate stats entry %d/%u/%u",
  368 andres                   1608 ECB             :                              key.kind, key.dboid, key.objoid);
  368 andres                   1609 UBC           0 :                         goto error;
                               1610                 :                     }
  404 akapila                  1611 ECB             : 
  368 andres                   1612 GIC      154053 :                     header = pgstat_init_entry(key.kind, p);
                               1613          154053 :                     dshash_release_lock(pgStatLocal.shared_hash, p);
  368 andres                   1614 ECB             : 
  368 andres                   1615 GBC      154053 :                     if (!read_chunk(fpin,
                               1616                 :                                     pgstat_get_entry_data(key.kind, header),
  368 andres                   1617 ECB             :                                     pgstat_get_entry_len(key.kind)))
  368 andres                   1618 UIC           0 :                         goto error;
                               1619                 : 
  404 akapila                  1620 CBC      154053 :                     break;
                               1621                 :                 }
 3702 alvherre                 1622 GIC         739 :             case 'E':
                               1623                 :                 /* check that 'E' actually signals end of file */
  358 andres                   1624             739 :                 if (fgetc(fpin) != EOF)
                               1625               1 :                     goto error;
                               1626                 : 
 3702 alvherre                 1627             738 :                 goto done;
 3702 alvherre                 1628 ECB             : 
 3702 alvherre                 1629 UIC           0 :             default:
  368 andres                   1630               0 :                 goto error;
 3702 alvherre                 1631 ECB             :         }
                               1632                 :     }
 3702 alvherre                 1633 EUB             : 
 3702 alvherre                 1634 GBC         740 : done:
 3702 alvherre                 1635 GIC         740 :     FreeFile(fpin);
 3702 alvherre                 1636 EUB             : 
  368 andres                   1637 GIC         740 :     elog(DEBUG2, "removing permanent stats file \"%s\"", statfile);
                               1638             740 :     unlink(statfile);
 5442 tgl                      1639 ECB             : 
  368 andres                   1640 CBC         740 :     return;
                               1641                 : 
                               1642               2 : error:
  368 andres                   1643 GIC           2 :     ereport(LOG,
                               1644                 :             (errmsg("corrupted statistics file \"%s\"", statfile)));
 7836 bruce                    1645 EUB             : 
  360 andres                   1646 GIC           2 :     pgstat_reset_after_failure();
 5905 tgl                      1647 ECB             : 
  368 andres                   1648 GIC           2 :     goto done;
 6138 tgl                      1649 ECB             : }
                               1650                 : 
  370 andres                   1651                 : /*
  360                          1652                 :  * Helper to reset / drop stats after a crash or after restoring stats from
                               1653                 :  * disk failed, potentially after already loading parts.
 5270 tgl                      1654                 :  */
                               1655                 : static void
  360 andres                   1656 GBC         438 : pgstat_reset_after_failure(void)
 5270 tgl                      1657 EUB             : {
  360 andres                   1658 GIC         438 :     TimestampTz ts = GetCurrentTimestamp();
                               1659                 : 
                               1660                 :     /* reset fixed-numbered stats */
  368 andres                   1661 CBC        5256 :     for (int kind = PGSTAT_KIND_FIRST_VALID; kind <= PGSTAT_KIND_LAST; kind++)
 5270 tgl                      1662 ECB             :     {
  368 andres                   1663 GIC        4818 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
 5270 tgl                      1664 ECB             : 
  368 andres                   1665 CBC        4818 :         if (!kind_info->fixed_amount)
  368 andres                   1666 GIC        2190 :             continue;
 5270 tgl                      1667 ECB             : 
  368 andres                   1668 GIC        2628 :         kind_info->reset_all_cb(ts);
 3357 fujii                    1669 ECB             :     }
                               1670                 : 
                               1671                 :     /* and drop variable-numbered ones */
  368 andres                   1672 GIC         438 :     pgstat_drop_all_entries();
  495 akapila                  1673 CBC         438 : }
        

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