LCOV - differential code coverage report
Current view: top level - src/backend/utils/activity - pgstat.c (source / functions) Coverage Total Hit UNC LBC UBC GNC CBC DUB DCB
Current: c38de3ae6098ccf1904109f2e550eb4777f66024 vs e352ac8c5c90ed6ce792f044c22145578542a330 Lines: 85.5 % 622 532 21 69 75 457 10 58
Current Date: 2026-11-05 14:14:01 +0100 Functions: 100.0 % 36 36 6 30
Baseline: lcov-20261105-baseline Branches: 62.5 % 550 344 48 1 157 50 294
Baseline Date: 2026-11-05 14:14:01 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(7,30] days: 81.2 % 64 52 12 52
(30,360] days: 79.5 % 83 66 9 8 23 43
(360..) days: 87.2 % 475 414 61 414
Function coverage date bins:
(30,360] days: 100.0 % 4 4 1 3
(360..) days: 100.0 % 32 32 5 27
Branch coverage date bins:
(7,30] days: 62.5 % 56 35 21 35
(30,360] days: 54.3 % 94 51 27 16 15 36
(360..) days: 64.5 % 400 258 1 141 258

 Age         Owner                    Branch data    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 (if the stats kind allows it), except when shutting down in
                                 16                 :                :  * immediate mode.
                                 17                 :                :  *
                                 18                 :                :  * Fixed-numbered stats are stored in plain (non-dynamic) shared memory.
                                 19                 :                :  *
                                 20                 :                :  * Statistics for variable-numbered objects are stored in dynamic shared
                                 21                 :                :  * memory and can be found via shared stats dshash hashtables. The statistics
                                 22                 :                :  * counters are not part of the dshash entry (PgStatShared_HashEntry)
                                 23                 :                :  * directly, but are separately allocated (PgStatShared_HashEntry->body). The
                                 24                 :                :  * separate allocation allows different kinds of statistics to share a
                                 25                 :                :  * hashtable without wasting space in PgStatShared_HashEntry.
                                 26                 :                :  *
                                 27                 :                :  * Variable-numbered stats are addressed by PgStat_HashKey while running.  It
                                 28                 :                :  * is not possible to have statistics for an object that cannot be addressed
                                 29                 :                :  * that way at runtime. A wider identifier can be used when serializing to
                                 30                 :                :  * disk (used for replication slot stats).
                                 31                 :                :  *
                                 32                 :                :  * To avoid contention on the shared stats hashtables, each backend has a
                                 33                 :                :  * backend-local hashtable (pgStatEntryRefHash) containing references
                                 34                 :                :  * (PgStat_EntryRef) to shared stats hashtable entries. The shared stats
                                 35                 :                :  * hashtables only need to be accessed when no prior reference is found in the
                                 36                 :                :  * local hashtable. Besides pointing to the shared stats hashtable entry
                                 37                 :                :  * (PgStatShared_HashEntry), PgStat_EntryRef also contains a process-local
                                 38                 :                :  * pointer to the shared statistics data, 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                 :                :  * It is possible for external modules to define custom statistics kinds,
                                 53                 :                :  * that can use the same properties as any built-in stats kinds.  Each custom
                                 54                 :                :  * stats kind needs to assign a unique ID to ensure that it does not overlap
                                 55                 :                :  * with other extensions.  In order to reserve a unique stats kind ID, refer
                                 56                 :                :  * to https://wiki.postgresql.org/wiki/CustomCumulativeStats.
                                 57                 :                :  *
                                 58                 :                :  * The behavior of different kinds of statistics is determined by the kind's
                                 59                 :                :  * entry in pgstat_kind_builtin_infos for all the built-in statistics kinds
                                 60                 :                :  * defined, and pgstat_kind_custom_infos for custom kinds registered at
                                 61                 :                :  * startup by pgstat_register_kind().  See PgStat_KindInfo for details.
                                 62                 :                :  *
                                 63                 :                :  * The consistency of read accesses to statistics can be configured using the
                                 64                 :                :  * stats_fetch_consistency GUC (see config.sgml and monitoring.sgml for the
                                 65                 :                :  * settings). When using PGSTAT_FETCH_CONSISTENCY_CACHE or
                                 66                 :                :  * PGSTAT_FETCH_CONSISTENCY_SNAPSHOT statistics are stored in
                                 67                 :                :  * pgStatLocal.snapshot.
                                 68                 :                :  *
                                 69                 :                :  * To keep things manageable, stats handling is split across several
                                 70                 :                :  * files. Infrastructure pieces are in:
                                 71                 :                :  * - pgstat.c - this file, to tie it all together
                                 72                 :                :  * - pgstat_shmem.c - nearly everything dealing with shared memory, including
                                 73                 :                :  *   the maintenance of hashtable entries
                                 74                 :                :  * - pgstat_xact.c - transactional integration, including the transactional
                                 75                 :                :  *   creation and dropping of stats entries
                                 76                 :                :  *
                                 77                 :                :  * Each statistics kind is handled in a dedicated file:
                                 78                 :                :  * - pgstat_archiver.c
                                 79                 :                :  * - pgstat_backend.c
                                 80                 :                :  * - pgstat_bgwriter.c
                                 81                 :                :  * - pgstat_checkpointer.c
                                 82                 :                :  * - pgstat_database.c
                                 83                 :                :  * - pgstat_function.c
                                 84                 :                :  * - pgstat_io.c
                                 85                 :                :  * - pgstat_lock.c
                                 86                 :                :  * - pgstat_relation.c
                                 87                 :                :  * - pgstat_replslot.c
                                 88                 :                :  * - pgstat_slru.c
                                 89                 :                :  * - pgstat_subscription.c
                                 90                 :                :  * - pgstat_wal.c
                                 91                 :                :  *
                                 92                 :                :  * Whenever possible infrastructure files should not contain code related to
                                 93                 :                :  * specific kinds of stats.
                                 94                 :                :  *
                                 95                 :                :  *
                                 96                 :                :  * Copyright (c) 2001-2026, PostgreSQL Global Development Group
                                 97                 :                :  *
                                 98                 :                :  * IDENTIFICATION
                                 99                 :                :  *    src/backend/utils/activity/pgstat.c
                                100                 :                :  * ----------
                                101                 :                :  */
                                102                 :                : #include "postgres.h"
                                103                 :                : 
                                104                 :                : #include <unistd.h>
                                105                 :                : 
                                106                 :                : #include "access/xact.h"
                                107                 :                : #include "lib/dshash.h"
                                108                 :                : #include "pgstat.h"
                                109                 :                : #include "storage/fd.h"
                                110                 :                : #include "storage/ipc.h"
                                111                 :                : #include "storage/lwlock.h"
                                112                 :                : #include "utils/guc_hooks.h"
                                113                 :                : #include "utils/memutils.h"
                                114                 :                : #include "utils/pgstat_internal.h"
                                115                 :                : #include "utils/timestamp.h"
                                116                 :                : 
                                117                 :                : 
                                118                 :                : /* ----------
                                119                 :                :  * Timer definitions.
                                120                 :                :  *
                                121                 :                :  * In milliseconds.
                                122                 :                :  * ----------
                                123                 :                :  */
                                124                 :                : 
                                125                 :                : /* minimum interval non-forced stats flushes.*/
                                126                 :                : #define PGSTAT_MIN_INTERVAL         1000
                                127                 :                : /* how long until to block flushing pending stats updates */
                                128                 :                : #define PGSTAT_MAX_INTERVAL         60000
                                129                 :                : /* when to call pgstat_report_stat() again, even when idle */
                                130                 :                : #define PGSTAT_IDLE_INTERVAL        10000
                                131                 :                : 
                                132                 :                : /* ----------
                                133                 :                :  * Initial size hints for the hash tables used in statistics.
                                134                 :                :  * ----------
                                135                 :                :  */
                                136                 :                : 
                                137                 :                : #define PGSTAT_SNAPSHOT_HASH_SIZE   512
                                138                 :                : 
                                139                 :                : /* ---------
                                140                 :                :  * Identifiers in stats file.
                                141                 :                :  * ---------
                                142                 :                :  */
                                143                 :                : #define PGSTAT_FILE_ENTRY_END   'E' /* end of file */
                                144                 :                : #define PGSTAT_FILE_ENTRY_FIXED 'F' /* fixed-numbered stats entry */
                                145                 :                : #define PGSTAT_FILE_ENTRY_NAME  'N' /* stats entry identified by name */
                                146                 :                : #define PGSTAT_FILE_ENTRY_HASH  'S' /* stats entry identified by
                                147                 :                :                                      * PgStat_HashKey */
                                148                 :                : 
                                149                 :                : /* hash table for statistics snapshots entry */
                                150                 :                : typedef struct PgStat_SnapshotEntry
                                151                 :                : {
                                152                 :                :     PgStat_HashKey key;
                                153                 :                :     char        status;         /* for simplehash use */
                                154                 :                :     void       *data;           /* the stats data itself */
                                155                 :                : } PgStat_SnapshotEntry;
                                156                 :                : 
                                157                 :                : 
                                158                 :                : /* ----------
                                159                 :                :  * Backend-local Hash Table Definitions
                                160                 :                :  * ----------
                                161                 :                :  */
                                162                 :                : 
                                163                 :                : /* for stats snapshot entries */
                                164                 :                : #define SH_PREFIX pgstat_snapshot
                                165                 :                : #define SH_ELEMENT_TYPE PgStat_SnapshotEntry
                                166                 :                : #define SH_KEY_TYPE PgStat_HashKey
                                167                 :                : #define SH_KEY key
                                168                 :                : #define SH_HASH_KEY(tb, key) \
                                169                 :                :     pgstat_hash_hash_key(&key, sizeof(PgStat_HashKey), NULL)
                                170                 :                : #define SH_EQUAL(tb, a, b) \
                                171                 :                :     pgstat_cmp_hash_key(&a, &b, sizeof(PgStat_HashKey), NULL) == 0
                                172                 :                : #define SH_SCOPE static inline
                                173                 :                : #define SH_DEFINE
                                174                 :                : #define SH_DECLARE
                                175                 :                : #include "lib/simplehash.h"
                                176                 :                : 
                                177                 :                : 
                                178                 :                : /* ----------
                                179                 :                :  * Local function forward declarations
                                180                 :                :  * ----------
                                181                 :                :  */
                                182                 :                : 
                                183                 :                : static void pgstat_write_statsfile(void);
                                184                 :                : static void pgstat_read_statsfile(void);
                                185                 :                : 
                                186                 :                : static void pgstat_init_snapshot_fixed(void);
                                187                 :                : 
                                188                 :                : static void pgstat_reset_after_failure(void);
                                189                 :                : 
                                190                 :                : static bool pgstat_flush_pending_entries(bool nowait);
                                191                 :                : 
                                192                 :                : static void pgstat_prep_snapshot(void);
                                193                 :                : static void pgstat_build_snapshot(void);
                                194                 :                : static void pgstat_build_snapshot_fixed(PgStat_Kind kind);
                                195                 :                : 
                                196                 :                : static inline bool pgstat_is_kind_valid(PgStat_Kind kind);
                                197                 :                : 
                                198                 :                : 
                                199                 :                : /* ----------
                                200                 :                :  * GUC parameters
                                201                 :                :  * ----------
                                202                 :                :  */
                                203                 :                : 
                                204                 :                : bool        pgstat_track_counts = false;
                                205                 :                : int         pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_CACHE;
                                206                 :                : 
                                207                 :                : 
                                208                 :                : /* ----------
                                209                 :                :  * state shared with pgstat_*.c
                                210                 :                :  * ----------
                                211                 :                :  */
                                212                 :                : 
                                213                 :                : PgStat_LocalState pgStatLocal;
                                214                 :                : 
                                215                 :                : /*
                                216                 :                :  * Track pending reports for fixed-numbered stats, used by
                                217                 :                :  * pgstat_report_stat().
                                218                 :                :  */
                                219                 :                : bool        pgstat_report_fixed = false;
                                220                 :                : 
                                221                 :                : /* ----------
                                222                 :                :  * Local data
                                223                 :                :  *
                                224                 :                :  * NB: There should be only variables related to stats infrastructure here,
                                225                 :                :  * not for specific kinds of stats.
                                226                 :                :  * ----------
                                227                 :                :  */
                                228                 :                : 
                                229                 :                : /*
                                230                 :                :  * Memory contexts containing the pgStatEntryRefHash table, the
                                231                 :                :  * pgStatSharedRef entries, and pending data respectively. Mostly to make it
                                232                 :                :  * easier to track / attribute memory usage.
                                233                 :                :  */
                                234                 :                : 
                                235                 :                : static MemoryContext pgStatPendingContext = NULL;
                                236                 :                : 
                                237                 :                : /*
                                238                 :                :  * Backend local list of PgStat_EntryRef with unflushed pending stats.
                                239                 :                :  *
                                240                 :                :  * Newly pending entries should only ever be added to the end of the list,
                                241                 :                :  * otherwise pgstat_flush_pending_entries() might not see them immediately.
                                242                 :                :  */
                                243                 :                : static dlist_head pgStatPending = DLIST_STATIC_INIT(pgStatPending);
                                244                 :                : 
                                245                 :                : 
                                246                 :                : /*
                                247                 :                :  * Force the next stats flush to happen regardless of
                                248                 :                :  * PGSTAT_MIN_INTERVAL. Useful in test scripts.
                                249                 :                :  */
                                250                 :                : static bool pgStatForceNextFlush = false;
                                251                 :                : 
                                252                 :                : /*
                                253                 :                :  * Force-clear existing snapshot before next use when stats_fetch_consistency
                                254                 :                :  * is changed.
                                255                 :                :  */
                                256                 :                : static bool force_stats_snapshot_clear = false;
                                257                 :                : 
                                258                 :                : 
                                259                 :                : /*
                                260                 :                :  * For assertions that check pgstat is not used before initialization / after
                                261                 :                :  * shutdown.
                                262                 :                :  */
                                263                 :                : #ifdef USE_ASSERT_CHECKING
                                264                 :                : static bool pgstat_is_initialized = false;
                                265                 :                : static bool pgstat_is_shutdown = false;
                                266                 :                : #endif
                                267                 :                : 
                                268                 :                : 
                                269                 :                : /*
                                270                 :                :  * The different kinds of built-in statistics.
                                271                 :                :  *
                                272                 :                :  * If reasonably possible, handling specific to one kind of stats should go
                                273                 :                :  * through this abstraction, rather than making more of pgstat.c aware.
                                274                 :                :  *
                                275                 :                :  * See comments for struct PgStat_KindInfo for details about the individual
                                276                 :                :  * fields.
                                277                 :                :  *
                                278                 :                :  * XXX: It'd be nicer to define this outside of this file. But there doesn't
                                279                 :                :  * seem to be a great way of doing that, given the split across multiple
                                280                 :                :  * files.
                                281                 :                :  */
                                282                 :                : static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE] = {
                                283                 :                : 
                                284                 :                :     /* stats kinds for variable-numbered objects */
                                285                 :                : 
                                286                 :                :     [PGSTAT_KIND_DATABASE] = {
                                287                 :                :         .name = "database",
                                288                 :                : 
                                289                 :                :         .fixed_amount = false,
                                290                 :                :         .write_to_file = true,
                                291                 :                :         /* so pg_stat_database entries can be seen in all databases */
                                292                 :                :         .accessed_across_databases = true,
                                293                 :                : 
                                294                 :                :         .shared_size = sizeof(PgStatShared_Database),
                                295                 :                :         .shared_data_off = offsetof(PgStatShared_Database, stats),
                                296                 :                :         .shared_data_len = sizeof(((PgStatShared_Database *) 0)->stats),
                                297                 :                :         .pending_size = sizeof(PgStat_StatDBEntry),
                                298                 :                : 
                                299                 :                :         .flush_pending_cb = pgstat_database_flush_cb,
                                300                 :                :         .reset_timestamp_cb = pgstat_database_reset_timestamp_cb,
                                301                 :                :     },
                                302                 :                : 
                                303                 :                :     [PGSTAT_KIND_RELATION] = {
                                304                 :                :         .name = "relation",
                                305                 :                : 
                                306                 :                :         .fixed_amount = false,
                                307                 :                :         .write_to_file = true,
                                308                 :                : 
                                309                 :                :         .shared_size = sizeof(PgStatShared_Relation),
                                310                 :                :         .shared_data_off = offsetof(PgStatShared_Relation, stats),
                                311                 :                :         .shared_data_len = sizeof(((PgStatShared_Relation *) 0)->stats),
                                312                 :                :         .pending_size = sizeof(PgStat_RelationStatus),
                                313                 :                : 
                                314                 :                :         .flush_pending_cb = pgstat_relation_flush_cb,
                                315                 :                :         .delete_pending_cb = pgstat_relation_delete_pending_cb,
                                316                 :                :         .reset_timestamp_cb = pgstat_relation_reset_timestamp_cb,
                                317                 :                :     },
                                318                 :                : 
                                319                 :                :     [PGSTAT_KIND_INDEX] = {
                                320                 :                :         .name = "index",
                                321                 :                : 
                                322                 :                :         .fixed_amount = false,
                                323                 :                :         .write_to_file = true,
                                324                 :                : 
                                325                 :                :         .shared_size = sizeof(PgStatShared_Index),
                                326                 :                :         .shared_data_off = offsetof(PgStatShared_Index, stats),
                                327                 :                :         .shared_data_len = sizeof(((PgStatShared_Index *) 0)->stats),
                                328                 :                :         .pending_size = sizeof(PgStat_RelationStatus),
                                329                 :                : 
                                330                 :                :         .flush_pending_cb = pgstat_index_flush_cb,
                                331                 :                :         .delete_pending_cb = pgstat_index_delete_pending_cb,
                                332                 :                :         .reset_timestamp_cb = pgstat_index_reset_timestamp_cb,
                                333                 :                :     },
                                334                 :                : 
                                335                 :                :     [PGSTAT_KIND_FUNCTION] = {
                                336                 :                :         .name = "function",
                                337                 :                : 
                                338                 :                :         .fixed_amount = false,
                                339                 :                :         .write_to_file = true,
                                340                 :                : 
                                341                 :                :         .shared_size = sizeof(PgStatShared_Function),
                                342                 :                :         .shared_data_off = offsetof(PgStatShared_Function, stats),
                                343                 :                :         .shared_data_len = sizeof(((PgStatShared_Function *) 0)->stats),
                                344                 :                :         .pending_size = sizeof(PgStat_FunctionCounts),
                                345                 :                : 
                                346                 :                :         .flush_pending_cb = pgstat_function_flush_cb,
                                347                 :                :         .reset_timestamp_cb = pgstat_function_reset_timestamp_cb,
                                348                 :                :     },
                                349                 :                : 
                                350                 :                :     [PGSTAT_KIND_REPLSLOT] = {
                                351                 :                :         .name = "replslot",
                                352                 :                : 
                                353                 :                :         .fixed_amount = false,
                                354                 :                :         .write_to_file = true,
                                355                 :                : 
                                356                 :                :         .accessed_across_databases = true,
                                357                 :                : 
                                358                 :                :         .shared_size = sizeof(PgStatShared_ReplSlot),
                                359                 :                :         .shared_data_off = offsetof(PgStatShared_ReplSlot, stats),
                                360                 :                :         .shared_data_len = sizeof(((PgStatShared_ReplSlot *) 0)->stats),
                                361                 :                : 
                                362                 :                :         .reset_timestamp_cb = pgstat_replslot_reset_timestamp_cb,
                                363                 :                :         .to_serialized_name = pgstat_replslot_to_serialized_name_cb,
                                364                 :                :         .from_serialized_name = pgstat_replslot_from_serialized_name_cb,
                                365                 :                :     },
                                366                 :                : 
                                367                 :                :     [PGSTAT_KIND_SUBSCRIPTION] = {
                                368                 :                :         .name = "subscription",
                                369                 :                : 
                                370                 :                :         .fixed_amount = false,
                                371                 :                :         .write_to_file = true,
                                372                 :                :         /* so pg_stat_subscription_stats entries can be seen in all databases */
                                373                 :                :         .accessed_across_databases = true,
                                374                 :                : 
                                375                 :                :         .shared_size = sizeof(PgStatShared_Subscription),
                                376                 :                :         .shared_data_off = offsetof(PgStatShared_Subscription, stats),
                                377                 :                :         .shared_data_len = sizeof(((PgStatShared_Subscription *) 0)->stats),
                                378                 :                :         .pending_size = sizeof(PgStat_BackendSubEntry),
                                379                 :                : 
                                380                 :                :         .flush_pending_cb = pgstat_subscription_flush_cb,
                                381                 :                :         .reset_timestamp_cb = pgstat_subscription_reset_timestamp_cb,
                                382                 :                :     },
                                383                 :                : 
                                384                 :                :     [PGSTAT_KIND_BACKEND] = {
                                385                 :                :         .name = "backend",
                                386                 :                : 
                                387                 :                :         .fixed_amount = false,
                                388                 :                :         .write_to_file = false,
                                389                 :                : 
                                390                 :                :         .accessed_across_databases = true,
                                391                 :                : 
                                392                 :                :         .shared_size = sizeof(PgStatShared_Backend),
                                393                 :                :         .shared_data_off = offsetof(PgStatShared_Backend, stats),
                                394                 :                :         .shared_data_len = sizeof(((PgStatShared_Backend *) 0)->stats),
                                395                 :                : 
                                396                 :                :         .flush_static_cb = pgstat_backend_flush_cb,
                                397                 :                :         .reset_timestamp_cb = pgstat_backend_reset_timestamp_cb,
                                398                 :                :     },
                                399                 :                : 
                                400                 :                :     /* stats for fixed-numbered (mostly 1) objects */
                                401                 :                : 
                                402                 :                :     [PGSTAT_KIND_ARCHIVER] = {
                                403                 :                :         .name = "archiver",
                                404                 :                : 
                                405                 :                :         .fixed_amount = true,
                                406                 :                :         .write_to_file = true,
                                407                 :                : 
                                408                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, archiver),
                                409                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, archiver),
                                410                 :                :         .shared_data_off = offsetof(PgStatShared_Archiver, stats),
                                411                 :                :         .shared_data_len = sizeof(((PgStatShared_Archiver *) 0)->stats),
                                412                 :                : 
                                413                 :                :         .init_shmem_cb = pgstat_archiver_init_shmem_cb,
                                414                 :                :         .reset_all_cb = pgstat_archiver_reset_all_cb,
                                415                 :                :         .snapshot_cb = pgstat_archiver_snapshot_cb,
                                416                 :                :     },
                                417                 :                : 
                                418                 :                :     [PGSTAT_KIND_BGWRITER] = {
                                419                 :                :         .name = "bgwriter",
                                420                 :                : 
                                421                 :                :         .fixed_amount = true,
                                422                 :                :         .write_to_file = true,
                                423                 :                : 
                                424                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, bgwriter),
                                425                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, bgwriter),
                                426                 :                :         .shared_data_off = offsetof(PgStatShared_BgWriter, stats),
                                427                 :                :         .shared_data_len = sizeof(((PgStatShared_BgWriter *) 0)->stats),
                                428                 :                : 
                                429                 :                :         .init_shmem_cb = pgstat_bgwriter_init_shmem_cb,
                                430                 :                :         .reset_all_cb = pgstat_bgwriter_reset_all_cb,
                                431                 :                :         .snapshot_cb = pgstat_bgwriter_snapshot_cb,
                                432                 :                :     },
                                433                 :                : 
                                434                 :                :     [PGSTAT_KIND_CHECKPOINTER] = {
                                435                 :                :         .name = "checkpointer",
                                436                 :                : 
                                437                 :                :         .fixed_amount = true,
                                438                 :                :         .write_to_file = true,
                                439                 :                : 
                                440                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, checkpointer),
                                441                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, checkpointer),
                                442                 :                :         .shared_data_off = offsetof(PgStatShared_Checkpointer, stats),
                                443                 :                :         .shared_data_len = sizeof(((PgStatShared_Checkpointer *) 0)->stats),
                                444                 :                : 
                                445                 :                :         .init_shmem_cb = pgstat_checkpointer_init_shmem_cb,
                                446                 :                :         .reset_all_cb = pgstat_checkpointer_reset_all_cb,
                                447                 :                :         .snapshot_cb = pgstat_checkpointer_snapshot_cb,
                                448                 :                :     },
                                449                 :                : 
                                450                 :                :     [PGSTAT_KIND_IO] = {
                                451                 :                :         .name = "io",
                                452                 :                : 
                                453                 :                :         .fixed_amount = true,
                                454                 :                :         .write_to_file = true,
                                455                 :                : 
                                456                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, io),
                                457                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, io),
                                458                 :                :         .shared_data_off = offsetof(PgStatShared_IO, stats),
                                459                 :                :         .shared_data_len = sizeof(((PgStatShared_IO *) 0)->stats),
                                460                 :                : 
                                461                 :                :         .flush_static_cb = pgstat_io_flush_cb,
                                462                 :                :         .init_shmem_cb = pgstat_io_init_shmem_cb,
                                463                 :                :         .reset_all_cb = pgstat_io_reset_all_cb,
                                464                 :                :         .snapshot_cb = pgstat_io_snapshot_cb,
                                465                 :                :     },
                                466                 :                : 
                                467                 :                :     [PGSTAT_KIND_LOCK] = {
                                468                 :                :         .name = "lock",
                                469                 :                : 
                                470                 :                :         .fixed_amount = true,
                                471                 :                :         .write_to_file = true,
                                472                 :                : 
                                473                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, lock),
                                474                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, lock),
                                475                 :                :         .shared_data_off = offsetof(PgStatShared_Lock, stats),
                                476                 :                :         .shared_data_len = sizeof(((PgStatShared_Lock *) 0)->stats),
                                477                 :                : 
                                478                 :                :         .flush_static_cb = pgstat_lock_flush_cb,
                                479                 :                :         .init_shmem_cb = pgstat_lock_init_shmem_cb,
                                480                 :                :         .reset_all_cb = pgstat_lock_reset_all_cb,
                                481                 :                :         .snapshot_cb = pgstat_lock_snapshot_cb,
                                482                 :                :     },
                                483                 :                : 
                                484                 :                :     [PGSTAT_KIND_SLRU] = {
                                485                 :                :         .name = "slru",
                                486                 :                : 
                                487                 :                :         .fixed_amount = true,
                                488                 :                :         .write_to_file = true,
                                489                 :                : 
                                490                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, slru),
                                491                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, slru),
                                492                 :                :         .shared_data_off = offsetof(PgStatShared_SLRU, stats),
                                493                 :                :         .shared_data_len = sizeof(((PgStatShared_SLRU *) 0)->stats),
                                494                 :                : 
                                495                 :                :         .flush_static_cb = pgstat_slru_flush_cb,
                                496                 :                :         .init_shmem_cb = pgstat_slru_init_shmem_cb,
                                497                 :                :         .reset_all_cb = pgstat_slru_reset_all_cb,
                                498                 :                :         .snapshot_cb = pgstat_slru_snapshot_cb,
                                499                 :                :     },
                                500                 :                : 
                                501                 :                :     [PGSTAT_KIND_WAL] = {
                                502                 :                :         .name = "wal",
                                503                 :                : 
                                504                 :                :         .fixed_amount = true,
                                505                 :                :         .write_to_file = true,
                                506                 :                : 
                                507                 :                :         .snapshot_ctl_off = offsetof(PgStat_Snapshot, wal),
                                508                 :                :         .shared_ctl_off = offsetof(PgStat_ShmemControl, wal),
                                509                 :                :         .shared_data_off = offsetof(PgStatShared_Wal, stats),
                                510                 :                :         .shared_data_len = sizeof(((PgStatShared_Wal *) 0)->stats),
                                511                 :                : 
                                512                 :                :         .init_backend_cb = pgstat_wal_init_backend_cb,
                                513                 :                :         .flush_static_cb = pgstat_wal_flush_cb,
                                514                 :                :         .init_shmem_cb = pgstat_wal_init_shmem_cb,
                                515                 :                :         .reset_all_cb = pgstat_wal_reset_all_cb,
                                516                 :                :         .snapshot_cb = pgstat_wal_snapshot_cb,
                                517                 :                :     },
                                518                 :                : };
                                519                 :                : 
                                520                 :                : /*
                                521                 :                :  * Information about custom statistics kinds.
                                522                 :                :  *
                                523                 :                :  * These are saved in a different array than the built-in kinds to save
                                524                 :                :  * in clarity with the initializations.
                                525                 :                :  *
                                526                 :                :  * Indexed by PGSTAT_KIND_CUSTOM_MIN, of size PGSTAT_KIND_CUSTOM_SIZE.
                                527                 :                :  */
                                528                 :                : static const PgStat_KindInfo **pgstat_kind_custom_infos = NULL;
                                529                 :                : 
                                530                 :                : /* ------------------------------------------------------------
                                531                 :                :  * Functions managing the state of the stats system for all backends.
                                532                 :                :  * ------------------------------------------------------------
                                533                 :                :  */
                                534                 :                : 
                                535                 :                : /*
                                536                 :                :  * Read on-disk stats into memory at server start.
                                537                 :                :  *
                                538                 :                :  * Should only be called by the startup process or in single user mode.
                                539                 :                :  */
                                540                 :                : void
  598 michael@paquier.xyz       541                 :CBC         914 : pgstat_restore_stats(void)
                                542                 :                : {
                                543                 :            914 :     pgstat_read_statsfile();
 7756 tgl@sss.pgh.pa.us         544                 :            914 : }
                                545                 :                : 
                                546                 :                : /*
                                547                 :                :  * Remove the stats file.  This is currently used only if WAL recovery is
                                548                 :                :  * needed after a crash.
                                549                 :                :  *
                                550                 :                :  * Should only be called by the startup process or in single user mode.
                                551                 :                :  */
                                552                 :                : void
 1674 andres@anarazel.de        553                 :            211 : pgstat_discard_stats(void)
                                554                 :                : {
                                555                 :                :     int         ret;
                                556                 :                : 
                                557                 :                :     /* NB: this needs to be done even in single user mode */
                                558                 :                : 
                                559                 :                :     /* First, cleanup the main pgstats file */
                                560                 :            211 :     ret = unlink(PGSTAT_STAT_PERMANENT_FILENAME);
                                561         [ +  + ]:            211 :     if (ret != 0)
                                562                 :                :     {
                                563         [ +  - ]:            210 :         if (errno == ENOENT)
                                564         [ +  + ]:            210 :             elog(DEBUG2,
                                565                 :                :                  "didn't need to unlink permanent stats file \"%s\" - didn't exist",
                                566                 :                :                  PGSTAT_STAT_PERMANENT_FILENAME);
                                567                 :                :         else
 1674 andres@anarazel.de        568         [ #  # ]:UBC           0 :             ereport(LOG,
                                569                 :                :                     (errcode_for_file_access(),
                                570                 :                :                      errmsg("could not unlink permanent statistics file \"%s\": %m",
                                571                 :                :                             PGSTAT_STAT_PERMANENT_FILENAME)));
                                572                 :                :     }
                                573                 :                :     else
                                574                 :                :     {
 1674 andres@anarazel.de        575         [ -  + ]:CBC           1 :         ereport(DEBUG2,
                                576                 :                :                 (errcode_for_file_access(),
                                577                 :                :                  errmsg_internal("unlinked permanent statistics file \"%s\"",
                                578                 :                :                                  PGSTAT_STAT_PERMANENT_FILENAME)));
                                579                 :                :     }
                                580                 :                : 
                                581                 :                :     /* Finish callbacks, if required */
  325 michael@paquier.xyz       582         [ +  + ]:           6963 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                                583                 :                :     {
                                584                 :           6752 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                585                 :                : 
                                586   [ +  +  +  + ]:           6752 :         if (kind_info && kind_info->finish)
                                587                 :              3 :             kind_info->finish(STATS_DISCARD);
                                588                 :                :     }
                                589                 :                : 
                                590                 :                :     /*
                                591                 :                :      * Reset stats contents. This will set reset timestamps of fixed-numbered
                                592                 :                :      * stats to the current time (no variable stats exist).
                                593                 :                :      */
 1666 andres@anarazel.de        594                 :            211 :     pgstat_reset_after_failure();
 8351 bruce@momjian.us          595                 :            211 : }
                                596                 :                : 
                                597                 :                : /*
                                598                 :                :  * pgstat_before_server_shutdown() needs to be called by exactly one process
                                599                 :                :  * during regular server shutdowns. Otherwise all stats will be lost.
                                600                 :                :  *
                                601                 :                :  * We currently only write out stats for proc_exit(0). We might want to change
                                602                 :                :  * that at some point... But right now pgstat_discard_stats() would be called
                                603                 :                :  * during the start after a disorderly shutdown, anyway.
                                604                 :                :  */
                                605                 :                : void
 1674 andres@anarazel.de        606                 :            803 : pgstat_before_server_shutdown(int code, Datum arg)
                                607                 :                : {
                                608         [ -  + ]:            803 :     Assert(pgStatLocal.shmem != NULL);
                                609         [ -  + ]:            803 :     Assert(!pgStatLocal.shmem->is_shutdown);
                                610                 :                : 
                                611                 :                :     /*
                                612                 :                :      * Stats should only be reported after pgstat_initialize() and before
                                613                 :                :      * pgstat_shutdown(). This is a convenient point to catch most violations
                                614                 :                :      * of this rule.
                                615                 :                :      */
                                616   [ +  -  -  + ]:            803 :     Assert(pgstat_is_initialized && !pgstat_is_shutdown);
                                617                 :                : 
                                618                 :                :     /* flush out our own pending changes before writing out */
                                619                 :            803 :     pgstat_report_stat(true);
                                620                 :                : 
                                621                 :                :     /*
                                622                 :                :      * Only write out file during normal shutdown. Don't even signal that
                                623                 :                :      * we've shutdown during irregular shutdowns, because the shutdown
                                624                 :                :      * sequence isn't coordinated to ensure this backend shuts down last.
                                625                 :                :      */
                                626         [ +  + ]:            803 :     if (code == 0)
                                627                 :                :     {
                                628                 :            798 :         pgStatLocal.shmem->is_shutdown = true;
  598 michael@paquier.xyz       629                 :            798 :         pgstat_write_statsfile();
                                630                 :                :     }
 7168 bruce@momjian.us          631                 :            803 : }
                                632                 :                : 
                                633                 :                : 
                                634                 :                : /* ------------------------------------------------------------
                                635                 :                :  * Backend initialization / shutdown functions
                                636                 :                :  * ------------------------------------------------------------
                                637                 :                :  */
                                638                 :                : 
                                639                 :                : /*
                                640                 :                :  * Shut down a single backend's statistics reporting at process exit.
                                641                 :                :  *
                                642                 :                :  * Flush out any remaining statistics counts.  Without this, operations
                                643                 :                :  * triggered during backend exit (such as temp table deletions) won't be
                                644                 :                :  * counted.
                                645                 :                :  */
                                646                 :                : static void
 1690 andres@anarazel.de        647                 :          24261 : pgstat_shutdown_hook(int code, Datum arg)
                                648                 :                : {
                                649         [ -  + ]:          24261 :     Assert(!pgstat_is_shutdown);
 1674                           650   [ +  +  -  + ]:          24261 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
                                651                 :                : 
                                652                 :                :     /*
                                653                 :                :      * If we got as far as discovering our own database ID, we can flush out
                                654                 :                :      * what we did so far.  Otherwise, we'd be reporting an invalid database
                                655                 :                :      * ID, so forget it.  (This means that accesses to pg_database during
                                656                 :                :      * failed backend starts might never get counted.)
                                657                 :                :      */
 1690                           658         [ +  + ]:          24261 :     if (OidIsValid(MyDatabaseId))
 1674                           659                 :          17968 :         pgstat_report_disconnect(MyDatabaseId);
                                660                 :                : 
                                661                 :          24261 :     pgstat_report_stat(true);
                                662                 :                : 
                                663                 :                :     /* there shouldn't be any pending changes left */
                                664         [ -  + ]:          24261 :     Assert(dlist_is_empty(&pgStatPending));
                                665                 :          24261 :     dlist_init(&pgStatPending);
                                666                 :                : 
                                667                 :                :     /* drop the backend stats entry */
  140 michael@paquier.xyz       668         [ -  + ]:          24261 :     if (!pgstat_drop_entry(PGSTAT_KIND_BACKEND, InvalidOid, MyProcNumber, false))
  686 michael@paquier.xyz       669                 :UBC           0 :         pgstat_request_entry_refs_gc();
                                670                 :                : 
 1674 andres@anarazel.de        671                 :CBC       24261 :     pgstat_detach_shmem();
                                672                 :                : 
                                673                 :                : #ifdef USE_ASSERT_CHECKING
 1690                           674                 :          24261 :     pgstat_is_shutdown = true;
                                675                 :                : #endif
                                676                 :          24261 : }
                                677                 :                : 
                                678                 :                : /*
                                679                 :                :  * Initialize pgstats state, and set up our on-proc-exit hook. Called from
                                680                 :                :  * BaseInit().
                                681                 :                :  *
                                682                 :                :  * NOTE: MyDatabaseId isn't set yet; so the shutdown hook has to be careful.
                                683                 :                :  */
                                684                 :                : void
                                685                 :          24261 : pgstat_initialize(void)
                                686                 :                : {
                                687         [ -  + ]:          24261 :     Assert(!pgstat_is_initialized);
                                688                 :                : 
 1674                           689                 :          24261 :     pgstat_attach_shmem();
                                690                 :                : 
  823 michael@paquier.xyz       691                 :          24261 :     pgstat_init_snapshot_fixed();
                                692                 :                : 
                                693                 :                :     /* Backend initialization callbacks */
  791                           694         [ +  + ]:         800613 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                                695                 :                :     {
                                696                 :         776352 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                697                 :                : 
                                698   [ +  +  +  + ]:         776352 :         if (kind_info == NULL || kind_info->init_backend_cb == NULL)
                                699                 :         752091 :             continue;
                                700                 :                : 
                                701                 :          24261 :         kind_info->init_backend_cb();
                                702                 :                :     }
                                703                 :                : 
                                704                 :                :     /* Set up a process-exit hook to clean up */
 1690 andres@anarazel.de        705                 :          24261 :     before_shmem_exit(pgstat_shutdown_hook, 0);
                                706                 :                : 
                                707                 :                : #ifdef USE_ASSERT_CHECKING
                                708                 :          24261 :     pgstat_is_initialized = true;
                                709                 :                : #endif
                                710                 :          24261 : }
                                711                 :                : 
                                712                 :                : 
                                713                 :                : /* ------------------------------------------------------------
                                714                 :                :  * Public functions used by backends follow
                                715                 :                :  * ------------------------------------------------------------
                                716                 :                :  */
                                717                 :                : 
                                718                 :                : /*
                                719                 :                :  * Must be called by processes that performs DML: tcop/postgres.c, logical
                                720                 :                :  * receiver processes, SPI worker, etc. to flush pending statistics updates to
                                721                 :                :  * shared memory.
                                722                 :                :  *
                                723                 :                :  * Unless called with 'force', pending stats updates are flushed happen once
                                724                 :                :  * per PGSTAT_MIN_INTERVAL (1000ms). When not forced, stats flushes do not
                                725                 :                :  * block on lock acquisition, except if stats updates have been pending for
                                726                 :                :  * longer than PGSTAT_MAX_INTERVAL (60000ms).
                                727                 :                :  *
                                728                 :                :  * Whenever pending stats updates remain at the end of pgstat_report_stat() a
                                729                 :                :  * suggested idle timeout is returned. Currently this is always
                                730                 :                :  * PGSTAT_IDLE_INTERVAL (10000ms). Callers can use the returned time to set up
                                731                 :                :  * a timeout after which to call pgstat_report_stat(true), but are not
                                732                 :                :  * required to do so.
                                733                 :                :  *
                                734                 :                :  * Note that this is called only when not within a transaction, so it is fair
                                735                 :                :  * to use transaction stop time as an approximation of current time.
                                736                 :                :  */
                                737                 :                : long
 1674                           738                 :         391724 : pgstat_report_stat(bool force)
                                739                 :                : {
                                740                 :                :     static TimestampTz pending_since = 0;
                                741                 :                :     static TimestampTz last_flush = 0;
                                742                 :                :     bool        partial_flush;
                                743                 :                :     TimestampTz now;
                                744                 :                :     bool        nowait;
                                745                 :                : 
 1917                           746                 :         391724 :     pgstat_assert_is_up();
 1602                           747         [ -  + ]:         391724 :     Assert(!IsTransactionOrTransactionBlock());
                                748                 :                : 
                                749                 :                :     /* "absorb" the forced flush even if there's nothing to flush */
 1674                           750         [ +  + ]:         391724 :     if (pgStatForceNextFlush)
                                751                 :                :     {
                                752                 :            353 :         force = true;
                                753                 :            353 :         pgStatForceNextFlush = false;
                                754                 :                :     }
                                755                 :                : 
                                756                 :                :     /* Don't expend a clock check if nothing to do */
  465 michael@paquier.xyz       757         [ +  + ]:         391724 :     if (dlist_is_empty(&pgStatPending) &&
                                758         [ +  + ]:          12158 :         !pgstat_report_fixed)
                                759                 :                :     {
                                760                 :           8844 :         return 0;
                                761                 :                :     }
                                762                 :                : 
                                763                 :                :     /*
                                764                 :                :      * There should never be stats to report once stats are shut down. Can't
                                765                 :                :      * assert that before the checks above, as there is an unconditional
                                766                 :                :      * pgstat_report_stat() call in pgstat_shutdown_hook() - which at least
                                767                 :                :      * the process that ran pgstat_before_server_shutdown() will still call.
                                768                 :                :      */
 1674 andres@anarazel.de        769         [ -  + ]:         382880 :     Assert(!pgStatLocal.shmem->is_shutdown);
                                770                 :                : 
 1242                           771         [ +  + ]:         382880 :     if (force)
                                772                 :                :     {
                                773                 :                :         /*
                                774                 :                :          * Stats reports are forced either when it's been too long since stats
                                775                 :                :          * have been reported or in processes that force stats reporting to
                                776                 :                :          * happen at specific points (including shutdown). In the former case
                                777                 :                :          * the transaction stop time might be quite old, in the latter it
                                778                 :                :          * would never get cleared.
                                779                 :                :          */
                                780                 :          24217 :         now = GetCurrentTimestamp();
                                781                 :                :     }
                                782                 :                :     else
                                783                 :                :     {
                                784                 :         358663 :         now = GetCurrentTransactionStopTimestamp();
                                785                 :                : 
 1674                           786   [ +  +  -  + ]:         681210 :         if (pending_since > 0 &&
                                787                 :         322547 :             TimestampDifferenceExceeds(pending_since, now, PGSTAT_MAX_INTERVAL))
                                788                 :                :         {
                                789                 :                :             /* don't keep pending updates longer than PGSTAT_MAX_INTERVAL */
 1674 andres@anarazel.de        790                 :UBC           0 :             force = true;
                                791                 :                :         }
 1674 andres@anarazel.de        792         [ +  + ]:CBC      358663 :         else if (last_flush > 0 &&
                                793         [ +  + ]:         343089 :                  !TimestampDifferenceExceeds(last_flush, now, PGSTAT_MIN_INTERVAL))
                                794                 :                :         {
                                795                 :                :             /* don't flush too frequently */
                                796         [ +  + ]:         338130 :             if (pending_since == 0)
                                797                 :          20252 :                 pending_since = now;
                                798                 :                : 
                                799                 :         338130 :             return PGSTAT_IDLE_INTERVAL;
                                800                 :                :         }
                                801                 :                :     }
                                802                 :                : 
                                803                 :          44750 :     pgstat_update_dbstats(now);
                                804                 :                : 
                                805                 :                :     /* don't wait for lock acquisition when !force */
                                806                 :          44750 :     nowait = !force;
                                807                 :                : 
                                808                 :          44750 :     partial_flush = false;
                                809                 :                : 
                                810                 :                :     /* flush of variable-numbered stats tracked in pending entries list */
                                811                 :          44750 :     partial_flush |= pgstat_flush_pending_entries(nowait);
                                812                 :                : 
                                813                 :                :     /* flush of other stats kinds */
  465 michael@paquier.xyz       814         [ +  + ]:          44750 :     if (pgstat_report_fixed)
                                815                 :                :     {
                                816         [ +  + ]:        1436160 :         for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                                817                 :                :         {
                                818                 :        1392640 :             const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                819                 :                : 
                                820         [ +  + ]:        1392640 :             if (!kind_info)
                                821                 :         783064 :                 continue;
                                822         [ +  + ]:         609576 :             if (!kind_info->flush_static_cb)
                                823                 :         391976 :                 continue;
                                824                 :                : 
                                825                 :         217600 :             partial_flush |= kind_info->flush_static_cb(nowait);
                                826                 :                :         }
                                827                 :                :     }
                                828                 :                : 
 1674 andres@anarazel.de        829                 :          44750 :     last_flush = now;
                                830                 :                : 
                                831                 :                :     /*
                                832                 :                :      * If some of the pending stats could not be flushed due to lock
                                833                 :                :      * contention, let the caller know when to retry.
                                834                 :                :      */
                                835         [ +  + ]:          44750 :     if (partial_flush)
                                836                 :                :     {
                                837                 :                :         /* force should have prevented us from getting here */
                                838         [ -  + ]:             11 :         Assert(!force);
                                839                 :                : 
                                840                 :                :         /* remember since when stats have been pending */
                                841         [ +  - ]:             11 :         if (pending_since == 0)
                                842                 :             11 :             pending_since = now;
                                843                 :                : 
                                844                 :             11 :         return PGSTAT_IDLE_INTERVAL;
                                845                 :                :     }
                                846                 :                : 
                                847                 :          44739 :     pending_since = 0;
  465 michael@paquier.xyz       848                 :          44739 :     pgstat_report_fixed = false;
                                849                 :                : 
 1674 andres@anarazel.de        850                 :          44739 :     return 0;
                                851                 :                : }
                                852                 :                : 
                                853                 :                : /*
                                854                 :                :  * Force locally pending stats to be flushed during the next
                                855                 :                :  * pgstat_report_stat() call. This is useful for writing tests.
                                856                 :                :  */
                                857                 :                : void
                                858                 :            353 : pgstat_force_next_flush(void)
                                859                 :                : {
                                860                 :            353 :     pgStatForceNextFlush = true;
                                861                 :            353 : }
                                862                 :                : 
                                863                 :                : /*
                                864                 :                :  * Only for use by pgstat_reset_counters()
                                865                 :                :  */
                                866                 :                : static bool
                                867                 :          14707 : match_db_entries(PgStatShared_HashEntry *entry, Datum match_data)
                                868                 :                : {
  454 peter@eisentraut.org      869                 :          14707 :     return entry->key.dboid == MyDatabaseId;
                                870                 :                : }
                                871                 :                : 
                                872                 :                : /*
                                873                 :                :  * Reset counters for our database.
                                874                 :                :  *
                                875                 :                :  * Permission checking for this function is managed through the normal
                                876                 :                :  * GRANT system.
                                877                 :                :  */
                                878                 :                : void
 1674 andres@anarazel.de        879                 :             15 : pgstat_reset_counters(void)
                                880                 :                : {
                                881                 :             15 :     TimestampTz ts = GetCurrentTimestamp();
                                882                 :                : 
                                883                 :             15 :     pgstat_reset_matching_entries(match_db_entries,
                                884                 :                :                                   ObjectIdGetDatum(MyDatabaseId),
                                885                 :                :                                   ts);
                                886                 :             15 : }
                                887                 :                : 
                                888                 :                : /*
                                889                 :                :  * Reset a single variable-numbered entry.
                                890                 :                :  *
                                891                 :                :  * If the stats kind is within a database, also reset the database's
                                892                 :                :  * stat_reset_timestamp.
                                893                 :                :  *
                                894                 :                :  * Permission checking for this function is managed through the normal
                                895                 :                :  * GRANT system.
                                896                 :                :  */
                                897                 :                : void
  778 michael@paquier.xyz       898                 :             45 : pgstat_reset(PgStat_Kind kind, Oid dboid, uint64 objid)
                                899                 :                : {
 1674 andres@anarazel.de        900                 :             45 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                901                 :             45 :     TimestampTz ts = GetCurrentTimestamp();
                                902                 :                : 
                                903                 :                :     /* not needed atm, and doesn't make sense with the current signature */
                                904         [ -  + ]:             45 :     Assert(!pgstat_get_kind_info(kind)->fixed_amount);
                                905                 :                : 
                                906                 :                :     /* reset the "single counter" */
  778 michael@paquier.xyz       907                 :             45 :     pgstat_reset_entry(kind, dboid, objid, ts);
                                908                 :                : 
 1674 andres@anarazel.de        909         [ +  + ]:             45 :     if (!kind_info->accessed_across_databases)
                                910                 :             28 :         pgstat_reset_database_timestamp(dboid, ts);
                                911                 :             45 : }
                                912                 :                : 
                                913                 :                : /*
                                914                 :                :  * Reset stats for all entries of a kind.
                                915                 :                :  *
                                916                 :                :  * Permission checking for this function is managed through the normal
                                917                 :                :  * GRANT system.
                                918                 :                :  */
                                919                 :                : void
                                920                 :             47 : pgstat_reset_of_kind(PgStat_Kind kind)
                                921                 :                : {
                                922                 :             47 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                923                 :             47 :     TimestampTz ts = GetCurrentTimestamp();
                                924                 :                : 
                                925         [ +  + ]:             47 :     if (kind_info->fixed_amount)
                                926                 :             41 :         kind_info->reset_all_cb(ts);
                                927                 :                :     else
                                928                 :              6 :         pgstat_reset_entries_of_kind(kind, ts);
                                929                 :             47 : }
                                930                 :                : 
                                931                 :                : 
                                932                 :                : /* ------------------------------------------------------------
                                933                 :                :  * Fetching of stats
                                934                 :                :  * ------------------------------------------------------------
                                935                 :                :  */
                                936                 :                : 
                                937                 :                : /*
                                938                 :                :  * Discard any data collected in the current transaction.  Any subsequent
                                939                 :                :  * request will cause new snapshots to be read.
                                940                 :                :  *
                                941                 :                :  * This is also invoked during transaction commit or abort to discard
                                942                 :                :  * the no-longer-wanted snapshot.  Updates of stats_fetch_consistency can
                                943                 :                :  * cause this routine to be called.
                                944                 :                :  */
                                945                 :                : void
                                946                 :         430508 : pgstat_clear_snapshot(void)
                                947                 :                : {
                                948                 :         430508 :     pgstat_assert_is_up();
                                949                 :                : 
                                950                 :         430508 :     memset(&pgStatLocal.snapshot.fixed_valid, 0,
                                951                 :                :            sizeof(pgStatLocal.snapshot.fixed_valid));
  823 michael@paquier.xyz       952                 :         430508 :     memset(&pgStatLocal.snapshot.custom_valid, 0,
                                953                 :                :            sizeof(pgStatLocal.snapshot.custom_valid));
 1674 andres@anarazel.de        954                 :         430508 :     pgStatLocal.snapshot.stats = NULL;
                                955                 :         430508 :     pgStatLocal.snapshot.mode = PGSTAT_FETCH_CONSISTENCY_NONE;
                                956                 :                : 
                                957                 :                :     /* Release memory, if any was allocated */
                                958         [ +  + ]:         430508 :     if (pgStatLocal.snapshot.context)
                                959                 :                :     {
                                960                 :            859 :         MemoryContextDelete(pgStatLocal.snapshot.context);
                                961                 :                : 
                                962                 :                :         /* Reset variables */
                                963                 :            859 :         pgStatLocal.snapshot.context = NULL;
                                964                 :                :     }
                                965                 :                : 
                                966                 :                :     /*
                                967                 :                :      * Historically the backend_status.c facilities lived in this file, and
                                968                 :                :      * were reset with the same function. For now keep it that way, and
                                969                 :                :      * forward the reset request.
                                970                 :                :      */
                                971                 :         430508 :     pgstat_clear_backend_activity_snapshot();
                                972                 :                : 
                                973                 :                :     /* Reset this flag, as it may be possible that a cleanup was forced. */
 1275 michael@paquier.xyz       974                 :         430508 :     force_stats_snapshot_clear = false;
 1674 andres@anarazel.de        975                 :         430508 : }
                                976                 :                : 
                                977                 :                : void *
  210 nathan@postgresql.or      978                 :          39141 : pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *may_free)
                                979                 :                : {
  412 michael@paquier.xyz       980                 :          39141 :     PgStat_HashKey key = {0};
                                981                 :                :     PgStat_EntryRef *entry_ref;
                                982                 :                :     void       *stats_data;
 1674 andres@anarazel.de        983                 :          39141 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                                984                 :                : 
                                985                 :                :     /* should be called from backends */
                                986   [ -  +  -  - ]:          39141 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
 1469 peter@eisentraut.org      987         [ -  + ]:          39141 :     Assert(!kind_info->fixed_amount);
                                988                 :                : 
                                989                 :                :     /*
                                990                 :                :      * Initialize *may_free to false.  We'll change it to true later if we end
                                991                 :                :      * up allocating the result in the caller's context and not caching it.
                                992                 :                :      */
  210 nathan@postgresql.or      993         [ +  + ]:          39141 :     if (may_free)
                                994                 :          29165 :         *may_free = false;
                                995                 :                : 
 1674 andres@anarazel.de        996                 :          39141 :     pgstat_prep_snapshot();
                                997                 :                : 
                                998                 :          39141 :     key.kind = kind;
                                999                 :          39141 :     key.dboid = dboid;
  778 michael@paquier.xyz      1000                 :          39141 :     key.objid = objid;
                               1001                 :                : 
                               1002                 :                :     /* if we need to build a full snapshot, do so */
 1674 andres@anarazel.de       1003         [ +  + ]:          39141 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                               1004                 :            323 :         pgstat_build_snapshot();
                               1005                 :                : 
                               1006                 :                :     /* if caching is desired, look up in cache */
                               1007         [ +  + ]:          39141 :     if (pgstat_fetch_consistency > PGSTAT_FETCH_CONSISTENCY_NONE)
                               1008                 :                :     {
                               1009                 :           6903 :         PgStat_SnapshotEntry *entry = NULL;
                               1010                 :                : 
                               1011                 :           6903 :         entry = pgstat_snapshot_lookup(pgStatLocal.snapshot.stats, key);
                               1012                 :                : 
                               1013         [ +  + ]:           6903 :         if (entry)
                               1014                 :            648 :             return entry->data;
                               1015                 :                : 
                               1016                 :                :         /*
                               1017                 :                :          * If we built a full snapshot and the key is not in
                               1018                 :                :          * pgStatLocal.snapshot.stats, there are no matching stats.
                               1019                 :                :          */
                               1020         [ +  + ]:           6255 :         if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                               1021                 :             16 :             return NULL;
                               1022                 :                :     }
                               1023                 :                : 
                               1024                 :          38477 :     pgStatLocal.snapshot.mode = pgstat_fetch_consistency;
                               1025                 :                : 
  778 michael@paquier.xyz      1026                 :          38477 :     entry_ref = pgstat_get_entry_ref(kind, dboid, objid, false, NULL);
                               1027                 :                : 
 1674 andres@anarazel.de       1028   [ +  +  +  + ]:          38477 :     if (entry_ref == NULL || entry_ref->shared_entry->dropped)
                               1029                 :                :     {
                               1030                 :                :         /* create empty entry when using PGSTAT_FETCH_CONSISTENCY_CACHE */
                               1031         [ +  + ]:          10350 :         if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_CACHE)
                               1032                 :                :         {
                               1033                 :           1253 :             PgStat_SnapshotEntry *entry = NULL;
                               1034                 :                :             bool        found;
                               1035                 :                : 
                               1036                 :           1253 :             entry = pgstat_snapshot_insert(pgStatLocal.snapshot.stats, key, &found);
                               1037         [ -  + ]:           1253 :             Assert(!found);
                               1038                 :           1253 :             entry->data = NULL;
                               1039                 :                :         }
                               1040                 :          10350 :         return NULL;
                               1041                 :                :     }
                               1042                 :                : 
                               1043                 :                :     /*
                               1044                 :                :      * Allocate in caller's context for PGSTAT_FETCH_CONSISTENCY_NONE,
                               1045                 :                :      * otherwise we could quickly end up with a fair bit of memory used due to
                               1046                 :                :      * repeated accesses.
                               1047                 :                :      */
                               1048         [ +  + ]:          28127 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE)
                               1049                 :                :     {
                               1050                 :          23141 :         stats_data = palloc(kind_info->shared_data_len);
                               1051                 :                : 
                               1052                 :                :         /*
                               1053                 :                :          * Since we allocated the result in the caller's context and aren't
                               1054                 :                :          * caching it, the caller can safely pfree() it.
                               1055                 :                :          */
  210 nathan@postgresql.or     1056         [ +  + ]:          23141 :         if (may_free)
                               1057                 :          21366 :             *may_free = true;
                               1058                 :                :     }
                               1059                 :                :     else
 1674 andres@anarazel.de       1060                 :           4986 :         stats_data = MemoryContextAlloc(pgStatLocal.snapshot.context,
                               1061                 :           4986 :                                         kind_info->shared_data_len);
                               1062                 :                : 
  578 tgl@sss.pgh.pa.us        1063                 :          28127 :     (void) pgstat_lock_entry_shared(entry_ref, false);
 1674 andres@anarazel.de       1064                 :          56254 :     memcpy(stats_data,
                               1065                 :          28127 :            pgstat_get_entry_data(kind, entry_ref->shared_stats),
                               1066                 :          28127 :            kind_info->shared_data_len);
 1536                          1067                 :          28127 :     pgstat_unlock_entry(entry_ref);
                               1068                 :                : 
 1674                          1069         [ +  + ]:          28127 :     if (pgstat_fetch_consistency > PGSTAT_FETCH_CONSISTENCY_NONE)
                               1070                 :                :     {
                               1071                 :           4986 :         PgStat_SnapshotEntry *entry = NULL;
                               1072                 :                :         bool        found;
                               1073                 :                : 
                               1074                 :           4986 :         entry = pgstat_snapshot_insert(pgStatLocal.snapshot.stats, key, &found);
                               1075                 :           4986 :         entry->data = stats_data;
                               1076                 :                :     }
                               1077                 :                : 
                               1078                 :          28127 :     return stats_data;
                               1079                 :                : }
                               1080                 :                : 
                               1081                 :                : /*
                               1082                 :                :  * If a stats snapshot has been taken, return the timestamp at which that was
                               1083                 :                :  * done, and set *have_snapshot to true. Otherwise *have_snapshot is set to
                               1084                 :                :  * false.
                               1085                 :                :  */
                               1086                 :                : TimestampTz
                               1087                 :             40 : pgstat_get_stat_snapshot_timestamp(bool *have_snapshot)
                               1088                 :                : {
 1275 michael@paquier.xyz      1089         [ +  + ]:             40 :     if (force_stats_snapshot_clear)
                               1090                 :             12 :         pgstat_clear_snapshot();
                               1091                 :                : 
 1674 andres@anarazel.de       1092         [ +  + ]:             40 :     if (pgStatLocal.snapshot.mode == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                               1093                 :                :     {
                               1094                 :             16 :         *have_snapshot = true;
                               1095                 :             16 :         return pgStatLocal.snapshot.snapshot_timestamp;
                               1096                 :                :     }
                               1097                 :                : 
                               1098                 :             24 :     *have_snapshot = false;
                               1099                 :                : 
                               1100                 :             24 :     return 0;
                               1101                 :                : }
                               1102                 :                : 
                               1103                 :                : bool
  778 michael@paquier.xyz      1104                 :             94 : pgstat_have_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
                               1105                 :                : {
                               1106                 :                :     /* fixed-numbered stats always exist */
 1673 andres@anarazel.de       1107         [ +  + ]:             94 :     if (pgstat_get_kind_info(kind)->fixed_amount)
                               1108                 :              8 :         return true;
                               1109                 :                : 
  778 michael@paquier.xyz      1110                 :             86 :     return pgstat_get_entry_ref(kind, dboid, objid, false, NULL) != NULL;
                               1111                 :                : }
                               1112                 :                : 
                               1113                 :                : /*
                               1114                 :                :  * Ensure snapshot for fixed-numbered 'kind' exists.
                               1115                 :                :  *
                               1116                 :                :  * Typically used by the pgstat_fetch_* functions for a kind of stats, before
                               1117                 :                :  * massaging the data into the desired format.
                               1118                 :                :  */
                               1119                 :                : void
 1674 andres@anarazel.de       1120                 :            281 : pgstat_snapshot_fixed(PgStat_Kind kind)
                               1121                 :                : {
 1469 peter@eisentraut.org     1122         [ -  + ]:            281 :     Assert(pgstat_is_kind_valid(kind));
                               1123         [ -  + ]:            281 :     Assert(pgstat_get_kind_info(kind)->fixed_amount);
                               1124                 :                : 
 1008 michael@paquier.xyz      1125         [ -  + ]:            281 :     if (force_stats_snapshot_clear)
 1008 michael@paquier.xyz      1126                 :UBC           0 :         pgstat_clear_snapshot();
                               1127                 :                : 
 1674 andres@anarazel.de       1128         [ +  + ]:CBC         281 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                               1129                 :             12 :         pgstat_build_snapshot();
                               1130                 :                :     else
                               1131                 :            269 :         pgstat_build_snapshot_fixed(kind);
                               1132                 :                : 
  823 michael@paquier.xyz      1133         [ +  + ]:            281 :     if (pgstat_is_kind_builtin(kind))
                               1134         [ -  + ]:            278 :         Assert(pgStatLocal.snapshot.fixed_valid[kind]);
                               1135         [ +  - ]:              3 :     else if (pgstat_is_kind_custom(kind))
                               1136         [ -  + ]:              3 :         Assert(pgStatLocal.snapshot.custom_valid[kind - PGSTAT_KIND_CUSTOM_MIN]);
                               1137                 :            281 : }
                               1138                 :                : 
                               1139                 :                : static void
                               1140                 :          24261 : pgstat_init_snapshot_fixed(void)
                               1141                 :                : {
                               1142                 :                :     /*
                               1143                 :                :      * Initialize fixed-numbered statistics data in snapshots, only for custom
                               1144                 :                :      * stats kinds.
                               1145                 :                :      */
                               1146         [ +  + ]:         242610 :     for (PgStat_Kind kind = PGSTAT_KIND_CUSTOM_MIN; kind <= PGSTAT_KIND_CUSTOM_MAX; kind++)
                               1147                 :                :     {
                               1148                 :         218349 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1149                 :                : 
                               1150   [ +  +  +  + ]:         218349 :         if (!kind_info || !kind_info->fixed_amount)
                               1151                 :         218242 :             continue;
                               1152                 :                : 
                               1153                 :            107 :         pgStatLocal.snapshot.custom_data[kind - PGSTAT_KIND_CUSTOM_MIN] =
                               1154                 :            107 :             MemoryContextAlloc(TopMemoryContext, kind_info->shared_data_len);
                               1155                 :                :     }
 9267 JanWieck@Yahoo.com       1156                 :          24261 : }
                               1157                 :                : 
                               1158                 :                : static void
 1674 andres@anarazel.de       1159                 :          39171 : pgstat_prep_snapshot(void)
                               1160                 :                : {
 1275 michael@paquier.xyz      1161         [ +  + ]:          39171 :     if (force_stats_snapshot_clear)
                               1162                 :             12 :         pgstat_clear_snapshot();
                               1163                 :                : 
 1674 andres@anarazel.de       1164         [ +  + ]:          39171 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE ||
                               1165         [ +  + ]:           6933 :         pgStatLocal.snapshot.stats != NULL)
 6134 magnus@hagander.net      1166                 :          38312 :         return;
                               1167                 :                : 
 1674 andres@anarazel.de       1168         [ +  - ]:            859 :     if (!pgStatLocal.snapshot.context)
                               1169                 :            859 :         pgStatLocal.snapshot.context = AllocSetContextCreate(TopMemoryContext,
                               1170                 :                :                                                              "PgStat Snapshot",
                               1171                 :                :                                                              ALLOCSET_SMALL_SIZES);
                               1172                 :                : 
                               1173                 :            859 :     pgStatLocal.snapshot.stats =
                               1174                 :            859 :         pgstat_snapshot_create(pgStatLocal.snapshot.context,
                               1175                 :                :                                PGSTAT_SNAPSHOT_HASH_SIZE,
                               1176                 :                :                                NULL);
                               1177                 :                : }
                               1178                 :                : 
                               1179                 :                : static void
                               1180                 :            335 : pgstat_build_snapshot(void)
                               1181                 :                : {
                               1182                 :                :     dshash_seq_status hstat;
                               1183                 :                :     PgStatShared_HashEntry *p;
                               1184                 :                : 
                               1185                 :                :     /* should only be called when we need a snapshot */
                               1186         [ -  + ]:            335 :     Assert(pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT);
                               1187                 :                : 
                               1188                 :                :     /* snapshot already built */
                               1189         [ +  + ]:            335 :     if (pgStatLocal.snapshot.mode == PGSTAT_FETCH_CONSISTENCY_SNAPSHOT)
                               1190                 :            305 :         return;
                               1191                 :                : 
                               1192                 :             30 :     pgstat_prep_snapshot();
                               1193                 :                : 
                               1194         [ -  + ]:             30 :     Assert(pgStatLocal.snapshot.stats->members == 0);
                               1195                 :                : 
                               1196                 :             30 :     pgStatLocal.snapshot.snapshot_timestamp = GetCurrentTimestamp();
                               1197                 :                : 
                               1198                 :                :     /*
                               1199                 :                :      * Snapshot all variable stats.
                               1200                 :                :      */
   23 michael@paquier.xyz      1201         [ +  + ]:GNC          60 :     for (int h = 0; h < pgStatLocal.num_var_hashes; h++)
                               1202                 :                :     {
                               1203                 :             30 :         dshash_table *hash = pgStatLocal.var_hashes[h];
                               1204                 :                : 
                               1205                 :             30 :         dshash_seq_init(&hstat, hash, false);
                               1206         [ +  + ]:          33745 :         while ((p = dshash_seq_next(&hstat)) != NULL)
                               1207                 :                :         {
                               1208                 :          33715 :             PgStat_Kind kind = p->key.kind;
                               1209                 :          33715 :             const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1210                 :                :             bool        found;
                               1211                 :                :             PgStat_SnapshotEntry *entry;
                               1212                 :                :             PgStatShared_Common *stats_data;
                               1213                 :                : 
                               1214                 :                :             /*
                               1215                 :                :              * Check if the stats object should be included in the snapshot.
                               1216                 :                :              * Unless the stats kind can be accessed from all databases (e.g.,
                               1217                 :                :              * database stats themselves), we only include stats for the
                               1218                 :                :              * current database or objects not associated with a database
                               1219                 :                :              * (e.g. shared relations).
                               1220                 :                :              */
                               1221         [ +  + ]:          33715 :             if (p->key.dboid != MyDatabaseId &&
                               1222         [ +  + ]:           9712 :                 p->key.dboid != InvalidOid &&
                               1223         [ +  + ]:           8028 :                 !kind_info->accessed_across_databases)
                               1224                 :           7991 :                 continue;
                               1225                 :                : 
                               1226         [ +  + ]:          25777 :             if (p->dropped)
                               1227                 :             53 :                 continue;
                               1228                 :                : 
                               1229         [ -  + ]:          25724 :             Assert(pg_atomic_read_u32(&p->refcount) > 0);
                               1230                 :                : 
                               1231                 :          25724 :             stats_data = dsa_get_address(pgStatLocal.kind_dsa[kind], p->body);
                               1232         [ -  + ]:          25724 :             Assert(stats_data);
                               1233                 :                : 
                               1234                 :          25724 :             entry = pgstat_snapshot_insert(pgStatLocal.snapshot.stats, p->key, &found);
                               1235         [ -  + ]:          25724 :             Assert(!found);
                               1236                 :                : 
                               1237                 :          25724 :             entry->data = MemoryContextAlloc(pgStatLocal.snapshot.context,
                               1238                 :                :                                              pgstat_get_entry_len(kind));
                               1239                 :                : 
                               1240                 :                :             /*
                               1241                 :                :              * Acquire the LWLock directly instead of using
                               1242                 :                :              * pg_stat_lock_entry_shared() which requires a reference.
                               1243                 :                :              */
                               1244                 :          25724 :             LWLockAcquire(&stats_data->lock, LW_SHARED);
                               1245                 :          25724 :             memcpy(entry->data,
                               1246                 :          25724 :                    pgstat_get_entry_data(kind, stats_data),
                               1247                 :                :                    pgstat_get_entry_len(kind));
                               1248                 :          25724 :             LWLockRelease(&stats_data->lock);
                               1249                 :                :         }
                               1250                 :             30 :         dshash_seq_term(&hstat);
                               1251                 :                :     }
                               1252                 :                : 
                               1253                 :                :     /*
                               1254                 :                :      * Build snapshot of all fixed-numbered stats.
                               1255                 :                :      */
  823 michael@paquier.xyz      1256         [ +  + ]:CBC         990 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                               1257                 :                :     {
 1674 andres@anarazel.de       1258                 :            960 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1259                 :                : 
  823 michael@paquier.xyz      1260         [ +  + ]:            960 :         if (!kind_info)
                               1261                 :            540 :             continue;
 1674 andres@anarazel.de       1262         [ +  + ]:            420 :         if (!kind_info->fixed_amount)
                               1263                 :                :         {
                               1264         [ -  + ]:            210 :             Assert(kind_info->snapshot_cb == NULL);
                               1265                 :            210 :             continue;
                               1266                 :                :         }
                               1267                 :                : 
                               1268                 :            210 :         pgstat_build_snapshot_fixed(kind);
                               1269                 :                :     }
                               1270                 :                : 
                               1271                 :             30 :     pgStatLocal.snapshot.mode = PGSTAT_FETCH_CONSISTENCY_SNAPSHOT;
                               1272                 :                : }
                               1273                 :                : 
                               1274                 :                : static void
                               1275                 :           6070 : pgstat_build_snapshot_fixed(PgStat_Kind kind)
                               1276                 :                : {
                               1277                 :           6070 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1278                 :                :     int         idx;
                               1279                 :                :     bool       *valid;
                               1280                 :                : 
                               1281                 :                :     /* Position in fixed_valid or custom_valid */
  823 michael@paquier.xyz      1282         [ +  + ]:           6070 :     if (pgstat_is_kind_builtin(kind))
                               1283                 :                :     {
                               1284                 :           6062 :         idx = kind;
                               1285                 :           6062 :         valid = pgStatLocal.snapshot.fixed_valid;
                               1286                 :                :     }
                               1287                 :                :     else
                               1288                 :                :     {
                               1289                 :              8 :         idx = kind - PGSTAT_KIND_CUSTOM_MIN;
                               1290                 :              8 :         valid = pgStatLocal.snapshot.custom_valid;
                               1291                 :                :     }
                               1292                 :                : 
 1674 andres@anarazel.de       1293         [ -  + ]:           6070 :     Assert(kind_info->fixed_amount);
                               1294         [ -  + ]:           6070 :     Assert(kind_info->snapshot_cb != NULL);
                               1295                 :                : 
                               1296         [ +  + ]:           6070 :     if (pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_NONE)
                               1297                 :                :     {
                               1298                 :                :         /* rebuild every time */
  823 michael@paquier.xyz      1299                 :           5606 :         valid[idx] = false;
                               1300                 :                :     }
                               1301         [ +  + ]:            464 :     else if (valid[idx])
                               1302                 :                :     {
                               1303                 :                :         /* in snapshot mode we shouldn't get called again */
 1674 andres@anarazel.de       1304         [ -  + ]:              6 :         Assert(pgstat_fetch_consistency == PGSTAT_FETCH_CONSISTENCY_CACHE);
                               1305                 :              6 :         return;
                               1306                 :                :     }
                               1307                 :                : 
  823 michael@paquier.xyz      1308         [ -  + ]:           6064 :     Assert(!valid[idx]);
                               1309                 :                : 
 1674 andres@anarazel.de       1310                 :           6064 :     kind_info->snapshot_cb();
                               1311                 :                : 
  823 michael@paquier.xyz      1312         [ -  + ]:           6064 :     Assert(!valid[idx]);
                               1313                 :           6064 :     valid[idx] = true;
                               1314                 :                : }
                               1315                 :                : 
                               1316                 :                : 
                               1317                 :                : /* ------------------------------------------------------------
                               1318                 :                :  * Backend-local pending stats infrastructure
                               1319                 :                :  * ------------------------------------------------------------
                               1320                 :                :  */
                               1321                 :                : 
                               1322                 :                : /*
                               1323                 :                :  * Returns the appropriate PgStat_EntryRef, preparing it to receive pending
                               1324                 :                :  * stats if not already done.
                               1325                 :                :  *
                               1326                 :                :  * If created_entry is non-NULL, it'll be set to true if the entry is newly
                               1327                 :                :  * created, false otherwise.
                               1328                 :                :  */
                               1329                 :                : PgStat_EntryRef *
  778                          1330                 :        2331466 : pgstat_prep_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid, bool *created_entry)
                               1331                 :                : {
                               1332                 :                :     PgStat_EntryRef *entry_ref;
                               1333                 :                : 
                               1334                 :        2331466 :     entry_ref = pgstat_get_entry_ref(kind, dboid, objid,
                               1335                 :                :                                      true, created_entry);
                               1336                 :                : 
  106 michael@paquier.xyz      1337                 :GNC     2331466 :     pgstat_prep_pending_from_entry_ref(entry_ref);
                               1338                 :                : 
 1674 andres@anarazel.de       1339                 :CBC     2331466 :     return entry_ref;
                               1340                 :                : }
                               1341                 :                : 
                               1342                 :                : /*
                               1343                 :                :  * Return an existing stats entry, or NULL.
                               1344                 :                :  *
                               1345                 :                :  * This should only be used for helper function for pgstatfuncs.c - outside of
                               1346                 :                :  * that it shouldn't be needed.
                               1347                 :                :  */
                               1348                 :                : PgStat_EntryRef *
  778 michael@paquier.xyz      1349                 :             57 : pgstat_fetch_pending_entry(PgStat_Kind kind, Oid dboid, uint64 objid)
                               1350                 :                : {
                               1351                 :                :     PgStat_EntryRef *entry_ref;
                               1352                 :                : 
                               1353                 :             57 :     entry_ref = pgstat_get_entry_ref(kind, dboid, objid, false, NULL);
                               1354                 :                : 
 1674 andres@anarazel.de       1355   [ +  +  +  + ]:             57 :     if (entry_ref == NULL || entry_ref->pending == NULL)
                               1356                 :             20 :         return NULL;
                               1357                 :                : 
                               1358                 :             37 :     return entry_ref;
                               1359                 :                : }
                               1360                 :                : 
                               1361                 :                : void
                               1362                 :        1197302 : pgstat_delete_pending_entry(PgStat_EntryRef *entry_ref)
                               1363                 :                : {
                               1364                 :        1197302 :     PgStat_Kind kind = entry_ref->shared_entry->key.kind;
                               1365                 :        1197302 :     const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1366                 :        1197302 :     void       *pending_data = entry_ref->pending;
                               1367                 :                : 
                               1368         [ -  + ]:        1197302 :     Assert(pending_data != NULL);
                               1369                 :                :     /* !fixed_amount stats should be handled explicitly */
                               1370         [ -  + ]:        1197302 :     Assert(!pgstat_get_kind_info(kind)->fixed_amount);
                               1371                 :                : 
                               1372         [ +  + ]:        1197302 :     if (kind_info->delete_pending_cb)
                               1373                 :        1125455 :         kind_info->delete_pending_cb(entry_ref);
                               1374                 :                : 
                               1375                 :        1197302 :     pfree(pending_data);
                               1376                 :        1197302 :     entry_ref->pending = NULL;
                               1377                 :                : 
                               1378                 :        1197302 :     dlist_delete(&entry_ref->pending_node);
 2219 akapila@postgresql.o     1379                 :        1197302 : }
                               1380                 :                : 
                               1381                 :                : /*
                               1382                 :                :  * Prepare the given entry to receive pending stats, if not already done.
                               1383                 :                :  */
                               1384                 :                : void
  106 michael@paquier.xyz      1385                 :GNC     2331466 : pgstat_prep_pending_from_entry_ref(PgStat_EntryRef *entry_ref)
                               1386                 :                : {
                               1387                 :                :     PgStat_Kind kind;
                               1388                 :                : 
                               1389         [ -  + ]:        2331466 :     Assert(entry_ref != NULL);
                               1390                 :                : 
                               1391                 :        2331466 :     kind = entry_ref->shared_entry->key.kind;
                               1392                 :                : 
                               1393                 :                :     /* need to be able to flush out */
                               1394         [ -  + ]:        2331466 :     Assert(pgstat_get_kind_info(kind)->flush_pending_cb != NULL);
                               1395                 :                : 
                               1396         [ +  + ]:        2331466 :     if (entry_ref->pending == NULL)
                               1397                 :                :     {
                               1398                 :        1197302 :         size_t      entrysize = pgstat_get_kind_info(kind)->pending_size;
                               1399                 :                : 
                               1400         [ -  + ]:        1197302 :         Assert(entrysize != (size_t) -1);
                               1401                 :                : 
                               1402         [ +  + ]:        1197302 :         if (unlikely(!pgStatPendingContext))
                               1403                 :                :         {
                               1404                 :          19638 :             pgStatPendingContext =
                               1405                 :          19638 :                 AllocSetContextCreate(TopMemoryContext,
                               1406                 :                :                                       "PgStat Pending",
                               1407                 :                :                                       ALLOCSET_SMALL_SIZES);
                               1408                 :                :         }
                               1409                 :                : 
                               1410                 :        1197302 :         entry_ref->pending = MemoryContextAllocZero(pgStatPendingContext, entrysize);
                               1411                 :        1197302 :         dlist_push_tail(&pgStatPending, &entry_ref->pending_node);
                               1412                 :                :     }
                               1413                 :        2331466 : }
                               1414                 :                : 
                               1415                 :                : /*
                               1416                 :                :  * Flush out pending variable-numbered stats.
                               1417                 :                :  */
                               1418                 :                : static bool
 1674 andres@anarazel.de       1419                 :CBC       44750 : pgstat_flush_pending_entries(bool nowait)
                               1420                 :                : {
                               1421                 :          44750 :     bool        have_pending = false;
                               1422                 :          44750 :     dlist_node *cur = NULL;
                               1423                 :                : 
                               1424                 :                :     /*
                               1425                 :                :      * Need to be a bit careful iterating over the list of pending entries.
                               1426                 :                :      * Processing a pending entry may queue further pending entries to the end
                               1427                 :                :      * of the list that we want to process, so a simple iteration won't do.
                               1428                 :                :      * Further complicating matters is that we want to delete the current
                               1429                 :                :      * entry in each iteration from the list if we flushed successfully.
                               1430                 :                :      *
                               1431                 :                :      * So we just keep track of the next pointer in each loop iteration.
                               1432                 :                :      */
                               1433         [ +  + ]:          44750 :     if (!dlist_is_empty(&pgStatPending))
                               1434                 :          41673 :         cur = dlist_head_node(&pgStatPending);
                               1435                 :                : 
                               1436         [ +  + ]:        1197730 :     while (cur)
                               1437                 :                :     {
                               1438                 :        1152980 :         PgStat_EntryRef *entry_ref =
                               1439                 :                :             dlist_container(PgStat_EntryRef, pending_node, cur);
                               1440                 :        1152980 :         PgStat_HashKey key = entry_ref->shared_entry->key;
                               1441                 :        1152980 :         PgStat_Kind kind = key.kind;
                               1442                 :        1152980 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1443                 :                :         bool        did_flush;
                               1444                 :                :         dlist_node *next;
                               1445                 :                : 
                               1446         [ -  + ]:        1152980 :         Assert(!kind_info->fixed_amount);
                               1447         [ -  + ]:        1152980 :         Assert(kind_info->flush_pending_cb != NULL);
                               1448                 :                : 
                               1449                 :                :         /* flush the stats, if possible */
                               1450                 :        1152980 :         did_flush = kind_info->flush_pending_cb(entry_ref, nowait);
                               1451                 :                : 
                               1452   [ +  +  -  + ]:        1152980 :         Assert(did_flush || nowait);
                               1453                 :                : 
                               1454                 :                :         /* determine next entry, before deleting the pending entry */
                               1455         [ +  + ]:        1152980 :         if (dlist_has_next(&pgStatPending, cur))
                               1456                 :        1111307 :             next = dlist_next_node(&pgStatPending, cur);
                               1457                 :                :         else
                               1458                 :          41673 :             next = NULL;
                               1459                 :                : 
                               1460                 :                :         /* if successfully flushed, remove entry */
                               1461         [ +  + ]:        1152980 :         if (did_flush)
                               1462                 :        1152976 :             pgstat_delete_pending_entry(entry_ref);
                               1463                 :                :         else
                               1464                 :              4 :             have_pending = true;
                               1465                 :                : 
                               1466                 :        1152980 :         cur = next;
                               1467                 :                :     }
                               1468                 :                : 
                               1469         [ -  + ]:          44750 :     Assert(dlist_is_empty(&pgStatPending) == !have_pending);
                               1470                 :                : 
                               1471                 :          44750 :     return have_pending;
                               1472                 :                : }
                               1473                 :                : 
                               1474                 :                : 
                               1475                 :                : /* ------------------------------------------------------------
                               1476                 :                :  * Helper / infrastructure functions
                               1477                 :                :  * ------------------------------------------------------------
                               1478                 :                :  */
                               1479                 :                : 
                               1480                 :                : PgStat_Kind
                               1481                 :             98 : pgstat_get_kind_from_str(char *kind_str)
                               1482                 :                : {
  823 michael@paquier.xyz      1483         [ +  + ]:            372 :     for (PgStat_Kind kind = PGSTAT_KIND_BUILTIN_MIN; kind <= PGSTAT_KIND_BUILTIN_MAX; kind++)
                               1484                 :                :     {
                               1485         [ +  + ]:            368 :         if (pg_strcasecmp(kind_str, pgstat_kind_builtin_infos[kind].name) == 0)
 1674 andres@anarazel.de       1486                 :             94 :             return kind;
                               1487                 :                :     }
                               1488                 :                : 
                               1489                 :                :     /* Check the custom set of cumulative stats */
  823 michael@paquier.xyz      1490         [ -  + ]:              4 :     if (pgstat_kind_custom_infos)
                               1491                 :                :     {
  823 michael@paquier.xyz      1492         [ #  # ]:UBC           0 :         for (PgStat_Kind kind = PGSTAT_KIND_CUSTOM_MIN; kind <= PGSTAT_KIND_CUSTOM_MAX; kind++)
                               1493                 :                :         {
                               1494                 :              0 :             uint32      idx = kind - PGSTAT_KIND_CUSTOM_MIN;
                               1495                 :                : 
                               1496   [ #  #  #  # ]:              0 :             if (pgstat_kind_custom_infos[idx] &&
                               1497                 :              0 :                 pg_strcasecmp(kind_str, pgstat_kind_custom_infos[idx]->name) == 0)
                               1498                 :              0 :                 return kind;
                               1499                 :                :         }
                               1500                 :                :     }
                               1501                 :                : 
 1674 andres@anarazel.de       1502         [ +  - ]:CBC           4 :     ereport(ERROR,
                               1503                 :                :             (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               1504                 :                :              errmsg("invalid statistics kind: \"%s\"", kind_str)));
                               1505                 :                :     return PGSTAT_KIND_INVALID; /* avoid compiler warnings */
                               1506                 :                : }
                               1507                 :                : 
                               1508                 :                : static inline bool
  825 michael@paquier.xyz      1509                 :         476222 : pgstat_is_kind_valid(PgStat_Kind kind)
                               1510                 :                : {
  823                          1511   [ +  +  +  - ]:         476222 :     return pgstat_is_kind_builtin(kind) || pgstat_is_kind_custom(kind);
                               1512                 :                : }
                               1513                 :                : 
                               1514                 :                : const PgStat_KindInfo *
 1674 andres@anarazel.de       1515                 :       12943240 : pgstat_get_kind_info(PgStat_Kind kind)
                               1516                 :                : {
  823 michael@paquier.xyz      1517         [ +  + ]:       12943240 :     if (pgstat_is_kind_builtin(kind))
                               1518                 :       10931135 :         return &pgstat_kind_builtin_infos[kind];
                               1519                 :                : 
                               1520         [ +  + ]:        2012105 :     if (pgstat_is_kind_custom(kind))
                               1521                 :                :     {
                               1522                 :        1121213 :         uint32      idx = kind - PGSTAT_KIND_CUSTOM_MIN;
                               1523                 :                : 
                               1524         [ +  + ]:        1121213 :         if (pgstat_kind_custom_infos == NULL ||
                               1525         [ +  + ]:           4997 :             pgstat_kind_custom_infos[idx] == NULL)
                               1526                 :        1119940 :             return NULL;
                               1527                 :           1273 :         return pgstat_kind_custom_infos[idx];
                               1528                 :                :     }
                               1529                 :                : 
                               1530                 :         890892 :     return NULL;
                               1531                 :                : }
                               1532                 :                : 
                               1533                 :                : /*
                               1534                 :                :  * Register a new stats kind.
                               1535                 :                :  *
                               1536                 :                :  * PgStat_Kinds must be globally unique across all extensions. Refer
                               1537                 :                :  * to https://wiki.postgresql.org/wiki/CustomCumulativeStats to reserve a
                               1538                 :                :  * unique ID for your extension, to avoid conflicts with other extension
                               1539                 :                :  * developers. During development, use PGSTAT_KIND_EXPERIMENTAL to avoid
                               1540                 :                :  * needlessly reserving a new ID.
                               1541                 :                :  */
                               1542                 :                : void
                               1543                 :             18 : pgstat_register_kind(PgStat_Kind kind, const PgStat_KindInfo *kind_info)
                               1544                 :                : {
                               1545                 :             18 :     uint32      idx = kind - PGSTAT_KIND_CUSTOM_MIN;
                               1546                 :                : 
                               1547   [ +  -  -  + ]:             18 :     if (kind_info->name == NULL || strlen(kind_info->name) == 0)
  823 michael@paquier.xyz      1548         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1549                 :                :                 (errmsg("failed to register custom cumulative statistics with ID %u", kind),
                               1550                 :                :                  errhint("Provide a non-empty name for the custom cumulative statistics.")));
                               1551                 :                : 
  823 michael@paquier.xyz      1552         [ -  + ]:CBC          18 :     if (!pgstat_is_kind_custom(kind))
  122 michael@paquier.xyz      1553         [ #  # ]:UNC           0 :         ereport(ERROR, (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1554                 :                :                         errhint("Provide a custom cumulative statistics ID between %u and %u.",
                               1555                 :                :                                 PGSTAT_KIND_CUSTOM_MIN, PGSTAT_KIND_CUSTOM_MAX)));
                               1556                 :                : 
  823 michael@paquier.xyz      1557         [ -  + ]:CBC          18 :     if (!process_shared_preload_libraries_in_progress)
  823 michael@paquier.xyz      1558         [ #  # ]:UBC           0 :         ereport(ERROR,
                               1559                 :                :                 (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1560                 :                :                  errdetail("Custom cumulative statistics must be registered while initializing modules in \"%s\".",
                               1561                 :                :                            "shared_preload_libraries")));
                               1562                 :                : 
                               1563                 :                :     /*
                               1564                 :                :      * Check some data for fixed-numbered stats.
                               1565                 :                :      */
  823 michael@paquier.xyz      1566         [ +  + ]:CBC          18 :     if (kind_info->fixed_amount)
                               1567                 :                :     {
                               1568         [ -  + ]:              9 :         if (kind_info->shared_size == 0)
  823 michael@paquier.xyz      1569         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1570                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1571                 :                :                      errhint("Custom cumulative statistics require a shared memory size for fixed-numbered objects.")));
  122 michael@paquier.xyz      1572         [ -  + ]:GNC           9 :         if (kind_info->init_shmem_cb == NULL)
  122 michael@paquier.xyz      1573         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1574                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1575                 :                :                      errhint("Custom cumulative statistics require a \"%s\" callback for fixed-numbered objects.",
                               1576                 :                :                              "init_shmem_cb")));
  122 michael@paquier.xyz      1577         [ -  + ]:GNC           9 :         if (kind_info->reset_all_cb == NULL)
  122 michael@paquier.xyz      1578         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1579                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1580                 :                :                      errhint("Custom cumulative statistics require a \"%s\" callback for fixed-numbered objects.",
                               1581                 :                :                              "reset_all_cb")));
  122 michael@paquier.xyz      1582         [ -  + ]:GNC           9 :         if (kind_info->snapshot_cb == NULL)
  122 michael@paquier.xyz      1583         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1584                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1585                 :                :                      errhint("Custom cumulative statistics require a \"%s\" callback for fixed-numbered objects.",
                               1586                 :                :                              "snapshot_cb")));
  402 michael@paquier.xyz      1587         [ -  + ]:CBC           9 :         if (kind_info->track_entry_count)
  402 michael@paquier.xyz      1588         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1589                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1590                 :                :                      errhint("Custom cumulative statistics cannot use entry count tracking for fixed-numbered objects.")));
   23 michael@paquier.xyz      1591         [ -  + ]:GNC           9 :         if (kind_info->own_hash)
   23 michael@paquier.xyz      1592         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1593                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1594                 :                :                      errhint("Custom cumulative statistics cannot use a dedicated hash table for fixed-numbered objects.")));
   21 michael@paquier.xyz      1595   [ +  -  -  + ]:GNC           9 :         if (kind_info->to_serialized_name || kind_info->from_serialized_name)
   21 michael@paquier.xyz      1596         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1597                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1598                 :                :                      errhint("Custom cumulative statistics cannot use serialized names for fixed-numbered objects.")));
                               1599                 :                :     }
                               1600                 :                :     else
                               1601                 :                :     {
  122 michael@paquier.xyz      1602   [ +  -  -  + ]:GNC           9 :         if (kind_info->pending_size > 0 && kind_info->flush_pending_cb == NULL)
  122 michael@paquier.xyz      1603         [ #  # ]:UNC           0 :             ereport(ERROR,
                               1604                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1605                 :                :                      errhint("Custom cumulative statistics require a \"%s\" callback when pending size is set.",
                               1606                 :                :                              "flush_pending_cb")));
                               1607                 :                :     }
                               1608                 :                : 
                               1609                 :                :     /*
                               1610                 :                :      * If pgstat_kind_custom_infos is not available yet, allocate it.
                               1611                 :                :      */
  823 michael@paquier.xyz      1612         [ +  + ]:CBC          18 :     if (pgstat_kind_custom_infos == NULL)
                               1613                 :                :     {
                               1614                 :              9 :         pgstat_kind_custom_infos = (const PgStat_KindInfo **)
                               1615                 :              9 :             MemoryContextAllocZero(TopMemoryContext,
                               1616                 :                :                                    sizeof(PgStat_KindInfo *) * PGSTAT_KIND_CUSTOM_SIZE);
                               1617                 :                :     }
                               1618                 :                : 
                               1619         [ -  + ]:             18 :     if (pgstat_kind_custom_infos[idx] != NULL &&
  823 michael@paquier.xyz      1620         [ #  # ]:UBC           0 :         pgstat_kind_custom_infos[idx]->name != NULL)
                               1621         [ #  # ]:              0 :         ereport(ERROR,
                               1622                 :                :                 (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1623                 :                :                  errdetail("Custom cumulative statistics \"%s\" already registered with the same ID.",
                               1624                 :                :                            pgstat_kind_custom_infos[idx]->name)));
                               1625                 :                : 
                               1626                 :                :     /* check for existing custom stats with the same name */
  823 michael@paquier.xyz      1627         [ +  + ]:CBC         180 :     for (PgStat_Kind existing_kind = PGSTAT_KIND_CUSTOM_MIN; existing_kind <= PGSTAT_KIND_CUSTOM_MAX; existing_kind++)
                               1628                 :                :     {
                               1629                 :            162 :         uint32      existing_idx = existing_kind - PGSTAT_KIND_CUSTOM_MIN;
                               1630                 :                : 
                               1631         [ +  + ]:            162 :         if (pgstat_kind_custom_infos[existing_idx] == NULL)
                               1632                 :            153 :             continue;
                               1633         [ -  + ]:              9 :         if (!pg_strcasecmp(pgstat_kind_custom_infos[existing_idx]->name, kind_info->name))
  823 michael@paquier.xyz      1634         [ #  # ]:UBC           0 :             ereport(ERROR,
                               1635                 :                :                     (errmsg("failed to register custom cumulative statistics \"%s\" with ID %u", kind_info->name, kind),
                               1636                 :                :                      errdetail("Existing cumulative statistics with ID %u has the same name.", existing_kind)));
                               1637                 :                :     }
                               1638                 :                : 
                               1639                 :                :     /* Register it */
  823 michael@paquier.xyz      1640                 :CBC          18 :     pgstat_kind_custom_infos[idx] = kind_info;
                               1641         [ +  - ]:             18 :     ereport(LOG,
                               1642                 :                :             (errmsg("registered custom cumulative statistics \"%s\" with ID %u",
                               1643                 :                :                     kind_info->name, kind)));
 5494 rhaas@postgresql.org     1644                 :             18 : }
                               1645                 :                : 
                               1646                 :                : /*
                               1647                 :                :  * Stats should only be reported after pgstat_initialize() and before
                               1648                 :                :  * pgstat_shutdown(). This check is put in a few central places to catch
                               1649                 :                :  * violations of this rule more easily.
                               1650                 :                :  */
                               1651                 :                : #ifdef USE_ASSERT_CHECKING
                               1652                 :                : void
 1690 andres@anarazel.de       1653                 :        6163003 : pgstat_assert_is_up(void)
                               1654                 :                : {
                               1655   [ +  -  -  + ]:        6163003 :     Assert(pgstat_is_initialized && !pgstat_is_shutdown);
                               1656                 :        6163003 : }
                               1657                 :                : #endif
                               1658                 :                : 
                               1659                 :                : 
                               1660                 :                : /* ------------------------------------------------------------
                               1661                 :                :  * reading and writing of on-disk stats file
                               1662                 :                :  * ------------------------------------------------------------
                               1663                 :                :  */
                               1664                 :                : 
                               1665                 :                : #define write_chunk_s(fpout, ptr) write_chunk(fpout, ptr, sizeof(*ptr))
                               1666                 :                : #define read_chunk_s(fpin, ptr) read_chunk(fpin, ptr, sizeof(*ptr))
                               1667                 :                : 
                               1668                 :                : /* helpers for pgstat_write_statsfile() */
                               1669                 :                : static void
  113 michael@paquier.xyz      1670                 :         475652 : write_chunk(FILE *fpout, void *ptr, size_t len)
                               1671                 :                : {
                               1672                 :                :     int         rc;
                               1673                 :                : 
 1674 andres@anarazel.de       1674                 :         475652 :     rc = fwrite(ptr, len, 1, fpout);
                               1675                 :                : 
                               1676                 :                :     /* we'll check for errors with ferror once at the end */
                               1677                 :                :     (void) rc;
 1690                          1678                 :         475652 : }
                               1679                 :                : 
                               1680                 :                : /*
                               1681                 :                :  * This function is called in the last process that is accessing the shared
                               1682                 :                :  * stats so locking is not required.
                               1683                 :                :  */
                               1684                 :                : static void
  598 michael@paquier.xyz      1685                 :            798 : pgstat_write_statsfile(void)
                               1686                 :                : {
                               1687                 :                :     FILE       *fpout;
                               1688                 :                :     int32       format_id;
 1674 andres@anarazel.de       1689                 :            798 :     const char *tmpfile = PGSTAT_STAT_PERMANENT_TMPFILE;
                               1690                 :            798 :     const char *statfile = PGSTAT_STAT_PERMANENT_FILENAME;
                               1691                 :                :     dshash_seq_status hstat;
                               1692                 :                :     PgStatShared_HashEntry *ps;
  113 michael@paquier.xyz      1693                 :            798 :     PgStat_StatsFileOp status = STATS_WRITE;
                               1694                 :                : 
 1674 andres@anarazel.de       1695                 :            798 :     pgstat_assert_is_up();
                               1696                 :                : 
                               1697                 :                :     /* should be called only by the checkpointer or single user mode */
  846 michael@paquier.xyz      1698   [ +  +  -  + ]:            798 :     Assert(!IsUnderPostmaster || MyBackendType == B_CHECKPOINTER);
                               1699                 :                : 
                               1700                 :                :     /* we're shutting down, so it's ok to just override this */
 1674 andres@anarazel.de       1701                 :            798 :     pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_NONE;
                               1702                 :                : 
  598 michael@paquier.xyz      1703         [ +  + ]:            798 :     elog(DEBUG2, "writing stats file \"%s\"", statfile);
                               1704                 :                : 
                               1705                 :                :     /*
                               1706                 :                :      * Open the statistics temp file to write out the current values.
                               1707                 :                :      */
 6576 tgl@sss.pgh.pa.us        1708                 :            798 :     fpout = AllocateFile(tmpfile, PG_BINARY_W);
 9267 JanWieck@Yahoo.com       1709         [ -  + ]:            798 :     if (fpout == NULL)
                               1710                 :                :     {
 8507 tgl@sss.pgh.pa.us        1711         [ #  # ]:UBC           0 :         ereport(LOG,
                               1712                 :                :                 (errcode_for_file_access(),
                               1713                 :                :                  errmsg("could not open temporary statistics file \"%s\": %m",
                               1714                 :                :                         tmpfile)));
 9267 JanWieck@Yahoo.com       1715                 :              0 :         return;
                               1716                 :                :     }
                               1717                 :                : 
                               1718                 :                :     /*
                               1719                 :                :      * Write the file header --- currently just a format ID.
                               1720                 :                :      */
 7784 tgl@sss.pgh.pa.us        1721                 :CBC         798 :     format_id = PGSTAT_FILE_FORMAT_ID;
  113 michael@paquier.xyz      1722                 :            798 :     write_chunk_s(fpout, &format_id);
                               1723                 :                : 
                               1724                 :                :     /* Write various stats structs for fixed number of objects */
  823                          1725         [ +  + ]:          26334 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                               1726                 :                :     {
                               1727                 :                :         char       *ptr;
  849                          1728                 :          25536 :         const PgStat_KindInfo *info = pgstat_get_kind_info(kind);
                               1729                 :                : 
  823                          1730   [ +  +  +  + ]:          25536 :         if (!info || !info->fixed_amount)
  849                          1731                 :          19945 :             continue;
                               1732                 :                : 
  823                          1733         [ +  + ]:           5591 :         if (pgstat_is_kind_builtin(kind))
                               1734         [ -  + ]:           5586 :             Assert(info->snapshot_ctl_off != 0);
                               1735                 :                : 
                               1736                 :                :         /* skip if no need to write to file */
  713                          1737         [ -  + ]:           5591 :         if (!info->write_to_file)
  713 michael@paquier.xyz      1738                 :UBC           0 :             continue;
                               1739                 :                : 
  849 michael@paquier.xyz      1740                 :CBC        5591 :         pgstat_build_snapshot_fixed(kind);
  823                          1741         [ +  + ]:           5591 :         if (pgstat_is_kind_builtin(kind))
                               1742                 :           5586 :             ptr = ((char *) &pgStatLocal.snapshot) + info->snapshot_ctl_off;
                               1743                 :                :         else
                               1744                 :              5 :             ptr = pgStatLocal.snapshot.custom_data[kind - PGSTAT_KIND_CUSTOM_MIN];
                               1745                 :                : 
  847                          1746                 :           5591 :         fputc(PGSTAT_FILE_ENTRY_FIXED, fpout);
  113                          1747                 :           5591 :         write_chunk_s(fpout, &kind);
                               1748                 :           5591 :         write_chunk(fpout, ptr, info->shared_data_len);
                               1749                 :                :     }
                               1750                 :                : 
                               1751                 :                :     /*
                               1752                 :                :      * Walk through the stats entries, as long as writes can happen (note that
                               1753                 :                :      * switching to a STATS_DISCARD status is possible while walking through).
                               1754                 :                :      */
   23 michael@paquier.xyz      1755   [ +  +  +  - ]:GNC        1598 :     for (int h = 0; h < pgStatLocal.num_var_hashes && status == STATS_WRITE; h++)
                               1756                 :                :     {
                               1757                 :            800 :         dshash_table *hash = pgStatLocal.var_hashes[h];
                               1758                 :                : 
                               1759                 :            800 :         dshash_seq_init(&hstat, hash, false);
                               1760         [ +  + ]:         232712 :         while ((ps = dshash_seq_next(&hstat)) != NULL)
                               1761                 :                :         {
                               1762                 :                :             PgStatShared_Common *shstats;
                               1763                 :         231912 :             const PgStat_KindInfo *kind_info = NULL;
                               1764                 :                : 
                               1765                 :                :             /*
                               1766                 :                :              * We should not see any "dropped" entries when writing the stats
                               1767                 :                :              * file, as all backends and auxiliary processes should have
                               1768                 :                :              * cleaned up their references before they terminated.
                               1769                 :                :              *
                               1770                 :                :              * However, since we are already shutting down, it is not worth
                               1771                 :                :              * crashing the server over any potential cleanup issues, so we
                               1772                 :                :              * simply skip such entries if encountered.
                               1773                 :                :              */
                               1774         [ -  + ]:         231912 :             Assert(!ps->dropped);
                               1775         [ -  + ]:         231912 :             if (ps->dropped)
   23 michael@paquier.xyz      1776                 :UNC           0 :                 continue;
                               1777                 :                : 
                               1778                 :                :             /*
                               1779                 :                :              * This discards data related to custom stats kinds that are
                               1780                 :                :              * unknown to this process.
                               1781                 :                :              */
   23 michael@paquier.xyz      1782         [ -  + ]:GNC      231912 :             if (!pgstat_is_kind_valid(ps->key.kind))
                               1783                 :                :             {
   23 michael@paquier.xyz      1784         [ #  # ]:UNC           0 :                 elog(WARNING, "found unknown stats entry %u/%u/%" PRIu64,
                               1785                 :                :                      ps->key.kind, ps->key.dboid,
                               1786                 :                :                      ps->key.objid);
                               1787                 :              0 :                 continue;
                               1788                 :                :             }
                               1789                 :                : 
   23 michael@paquier.xyz      1790                 :GNC      231912 :             kind_info = pgstat_get_kind_info(ps->key.kind);
                               1791                 :                :             shstats = (PgStatShared_Common *)
                               1792                 :         231912 :                 dsa_get_address(pgStatLocal.kind_dsa[ps->key.kind], ps->body);
                               1793                 :                : 
                               1794                 :                :             /* if not dropped the valid-entry refcount should exist */
                               1795         [ -  + ]:         231912 :             Assert(pg_atomic_read_u32(&ps->refcount) > 0);
                               1796                 :                : 
                               1797                 :                :             /* skip if no need to write to file */
                               1798         [ +  + ]:         231912 :             if (!kind_info->write_to_file)
                               1799                 :            137 :                 continue;
                               1800                 :                : 
                               1801         [ +  + ]:         231775 :             if (!kind_info->to_serialized_name)
                               1802                 :                :             {
                               1803                 :                :                 /* normal stats entry, identified by PgStat_HashKey */
                               1804                 :         231653 :                 fputc(PGSTAT_FILE_ENTRY_HASH, fpout);
                               1805                 :         231653 :                 write_chunk_s(fpout, &ps->key);
                               1806                 :                :             }
                               1807                 :                :             else
                               1808                 :                :             {
                               1809                 :                :                 /* stats entry identified by name on disk (e.g. slots) */
                               1810                 :                :                 NameData    name;
                               1811                 :                : 
                               1812                 :            122 :                 kind_info->to_serialized_name(&ps->key, shstats, &name);
                               1813                 :                : 
                               1814                 :            122 :                 fputc(PGSTAT_FILE_ENTRY_NAME, fpout);
                               1815                 :            122 :                 write_chunk_s(fpout, &ps->key.kind);
                               1816                 :            122 :                 write_chunk_s(fpout, &name);
                               1817                 :                :             }
                               1818                 :                : 
                               1819                 :                :             /* Write except the header part of the entry */
                               1820                 :         231775 :             write_chunk(fpout,
                               1821                 :                :                         pgstat_get_entry_data(ps->key.kind, shstats),
                               1822                 :                :                         pgstat_get_entry_len(ps->key.kind));
                               1823                 :                : 
                               1824                 :                :             /* Write more data for the entry, if required */
                               1825         [ +  + ]:         231775 :             if (kind_info->to_serialized_data &&
                               1826         [ -  + ]:              4 :                 !kind_info->to_serialized_data(&ps->key, shstats, fpout))
                               1827                 :                :             {
   23 michael@paquier.xyz      1828                 :UNC           0 :                 status = STATS_DISCARD;
                               1829                 :              0 :                 break;
                               1830                 :                :             }
                               1831                 :                :         }
   23 michael@paquier.xyz      1832                 :GNC         800 :         dshash_seq_term(&hstat);
                               1833                 :                :     }
                               1834                 :                : 
                               1835                 :                :     /*
                               1836                 :                :      * No more output to be done. Close the temp file and replace the old
                               1837                 :                :      * pgstat.stat with it.  The ferror() check replaces testing for error
                               1838                 :                :      * after each individual fputc or fwrite (in write_chunk()) above.
                               1839                 :                :      */
  855 michael@paquier.xyz      1840                 :CBC         798 :     fputc(PGSTAT_FILE_ENTRY_END, fpout);
                               1841                 :                : 
  113                          1842         [ -  + ]:            798 :     if (status == STATS_DISCARD)
                               1843                 :                :     {
                               1844                 :                :         /*
                               1845                 :                :          * A to_serialized_data callback failed.  DEBUG2 because the callback
                               1846                 :                :          * already logged the reason.
                               1847                 :                :          */
  113 michael@paquier.xyz      1848         [ #  # ]:UBC           0 :         elog(DEBUG2, "discarding temporary statistics file \"%s\"", tmpfile);
                               1849                 :              0 :         FreeFile(fpout);
                               1850                 :              0 :         unlink(tmpfile);
                               1851                 :                :     }
  113 michael@paquier.xyz      1852         [ -  + ]:CBC         798 :     else if (ferror(fpout))
                               1853                 :                :     {
 7596 tgl@sss.pgh.pa.us        1854         [ #  # ]:UBC           0 :         ereport(LOG,
                               1855                 :                :                 (errcode_for_file_access(),
                               1856                 :                :                  errmsg("could not write temporary statistics file \"%s\": %m",
                               1857                 :                :                         tmpfile)));
 6576                          1858                 :              0 :         FreeFile(fpout);
 6666 magnus@hagander.net      1859                 :              0 :         unlink(tmpfile);
  113 michael@paquier.xyz      1860                 :              0 :         status = STATS_DISCARD;
                               1861                 :                :     }
 6576 tgl@sss.pgh.pa.us        1862         [ -  + ]:CBC         798 :     else if (FreeFile(fpout) < 0)
                               1863                 :                :     {
 8507 tgl@sss.pgh.pa.us        1864         [ #  # ]:UBC           0 :         ereport(LOG,
                               1865                 :                :                 (errcode_for_file_access(),
                               1866                 :                :                  errmsg("could not close temporary statistics file \"%s\": %m",
                               1867                 :                :                         tmpfile)));
 6666 magnus@hagander.net      1868                 :              0 :         unlink(tmpfile);
  113 michael@paquier.xyz      1869                 :              0 :         status = STATS_DISCARD;
                               1870                 :                :     }
  841 michael@paquier.xyz      1871         [ -  + ]:CBC         798 :     else if (durable_rename(tmpfile, statfile, LOG) < 0)
                               1872                 :                :     {
                               1873                 :                :         /* durable_rename already emitted log message */
 6666 magnus@hagander.net      1874                 :UBC           0 :         unlink(tmpfile);
  113 michael@paquier.xyz      1875                 :              0 :         status = STATS_DISCARD;
                               1876                 :                :     }
                               1877                 :                : 
                               1878                 :                :     /* Finish callbacks, if required */
  325 michael@paquier.xyz      1879         [ +  + ]:CBC       26334 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                               1880                 :                :     {
                               1881                 :          25536 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               1882                 :                : 
                               1883   [ +  +  +  + ]:          25536 :         if (kind_info && kind_info->finish)
  113                          1884                 :              5 :             kind_info->finish(status);
                               1885                 :                :     }
                               1886                 :                : }
                               1887                 :                : 
                               1888                 :                : /* helpers for pgstat_read_statsfile() */
                               1889                 :                : static bool
                               1890                 :         489000 : read_chunk(FILE *fpin, void *ptr, size_t len)
                               1891                 :                : {
 1674 andres@anarazel.de       1892                 :         489000 :     return fread(ptr, 1, len, fpin) == len;
                               1893                 :                : }
                               1894                 :                : 
                               1895                 :                : /*
                               1896                 :                :  * Reads in existing statistics file into memory.
                               1897                 :                :  *
                               1898                 :                :  * This function is called in the only process that is accessing the shared
                               1899                 :                :  * stats so locking is not required.
                               1900                 :                :  */
                               1901                 :                : static void
  598 michael@paquier.xyz      1902                 :            914 : pgstat_read_statsfile(void)
                               1903                 :                : {
                               1904                 :                :     FILE       *fpin;
                               1905                 :                :     int32       format_id;
                               1906                 :                :     bool        found;
  113                          1907                 :            914 :     PgStat_StatsFileOp status = STATS_READ;
 1674 andres@anarazel.de       1908                 :            914 :     const char *statfile = PGSTAT_STAT_PERMANENT_FILENAME;
                               1909                 :            914 :     PgStat_ShmemControl *shmem = pgStatLocal.shmem;
                               1910                 :                : 
                               1911                 :                :     /* shouldn't be called from postmaster */
                               1912   [ +  +  -  + ]:            914 :     Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
                               1913                 :                : 
  598 michael@paquier.xyz      1914         [ +  + ]:            914 :     elog(DEBUG2, "reading stats file \"%s\"", statfile);
                               1915                 :                : 
                               1916                 :                :     /*
                               1917                 :                :      * Try to open the stats file. If it doesn't exist, the backends simply
                               1918                 :                :      * returns zero for anything and statistics simply starts from scratch
                               1919                 :                :      * with empty counters.
                               1920                 :                :      *
                               1921                 :                :      * ENOENT is a possibility if stats collection was previously disabled or
                               1922                 :                :      * has not yet written the stats file for the first time.  Any other
                               1923                 :                :      * failure condition is suspicious.
                               1924                 :                :      */
 6666 magnus@hagander.net      1925         [ +  + ]:            914 :     if ((fpin = AllocateFile(statfile, PG_BINARY_R)) == NULL)
                               1926                 :                :     {
 6082 tgl@sss.pgh.pa.us        1927         [ -  + ]:             60 :         if (errno != ENOENT)
 1674 andres@anarazel.de       1928         [ #  # ]:UBC           0 :             ereport(LOG,
                               1929                 :                :                     (errcode_for_file_access(),
                               1930                 :                :                      errmsg("could not open statistics file \"%s\": %m",
                               1931                 :                :                             statfile)));
 1666 andres@anarazel.de       1932                 :CBC          60 :         pgstat_reset_after_failure();
  113 michael@paquier.xyz      1933                 :             60 :         status = STATS_DISCARD;
                               1934                 :             60 :         goto finish;
                               1935                 :                :     }
                               1936                 :                : 
                               1937                 :                :     /*
                               1938                 :                :      * Verify it's of the expected format.
                               1939                 :                :      */
                               1940         [ -  + ]:            854 :     if (!read_chunk_s(fpin, &format_id))
                               1941                 :                :     {
  828 michael@paquier.xyz      1942         [ #  # ]:UBC           0 :         elog(WARNING, "could not read format ID");
                               1943                 :              0 :         goto error;
                               1944                 :                :     }
                               1945                 :                : 
  828 michael@paquier.xyz      1946         [ +  + ]:CBC         854 :     if (format_id != PGSTAT_FILE_FORMAT_ID)
                               1947                 :                :     {
                               1948         [ +  - ]:              1 :         elog(WARNING, "found incorrect format ID %d (expected %d)",
                               1949                 :                :              format_id, PGSTAT_FILE_FORMAT_ID);
 1674 andres@anarazel.de       1950                 :              1 :         goto error;
                               1951                 :                :     }
                               1952                 :                : 
                               1953                 :                :     /*
                               1954                 :                :      * We found an existing statistics file. Read it and put all the stats
                               1955                 :                :      * data into place.
                               1956                 :                :      */
                               1957                 :                :     for (;;)
 9267 JanWieck@Yahoo.com       1958                 :         244029 :     {
 1669 tgl@sss.pgh.pa.us        1959                 :         244882 :         int         t = fgetc(fpin);
                               1960                 :                : 
 1674 andres@anarazel.de       1961   [ +  +  +  - ]:         244882 :         switch (t)
                               1962                 :                :         {
  847 michael@paquier.xyz      1963                 :           5976 :             case PGSTAT_FILE_ENTRY_FIXED:
                               1964                 :                :                 {
                               1965                 :                :                     PgStat_Kind kind;
                               1966                 :                :                     const PgStat_KindInfo *info;
                               1967                 :                :                     char       *ptr;
                               1968                 :                : 
                               1969                 :                :                     /* entry for fixed-numbered stats */
  113                          1970         [ -  + ]:           5976 :                     if (!read_chunk_s(fpin, &kind))
                               1971                 :                :                     {
  828 michael@paquier.xyz      1972         [ #  # ]:UBC           0 :                         elog(WARNING, "could not read stats kind for entry of type %c", t);
  847                          1973                 :              0 :                         goto error;
                               1974                 :                :                     }
                               1975                 :                : 
  847 michael@paquier.xyz      1976         [ -  + ]:CBC        5976 :                     if (!pgstat_is_kind_valid(kind))
                               1977                 :                :                     {
  823 michael@paquier.xyz      1978         [ #  # ]:UBC           0 :                         elog(WARNING, "invalid stats kind %u for entry of type %c",
                               1979                 :                :                              kind, t);
  847                          1980                 :              0 :                         goto error;
                               1981                 :                :                     }
                               1982                 :                : 
  847 michael@paquier.xyz      1983                 :CBC        5976 :                     info = pgstat_get_kind_info(kind);
  791                          1984         [ -  + ]:           5976 :                     if (!info)
                               1985                 :                :                     {
  791 michael@paquier.xyz      1986         [ #  # ]:UBC           0 :                         elog(WARNING, "could not find information of kind %u for entry of type %c",
                               1987                 :                :                              kind, t);
                               1988                 :              0 :                         goto error;
                               1989                 :                :                     }
                               1990                 :                : 
  847 michael@paquier.xyz      1991         [ -  + ]:CBC        5976 :                     if (!info->fixed_amount)
                               1992                 :                :                     {
  823 michael@paquier.xyz      1993         [ #  # ]:UBC           0 :                         elog(WARNING, "invalid fixed_amount in stats kind %u for entry of type %c",
                               1994                 :                :                              kind, t);
  847                          1995                 :              0 :                         goto error;
                               1996                 :                :                     }
                               1997                 :                : 
                               1998                 :                :                     /* Load back stats into shared memory */
  823 michael@paquier.xyz      1999         [ +  + ]:CBC        5976 :                     if (pgstat_is_kind_builtin(kind))
                               2000                 :           5971 :                         ptr = ((char *) shmem) + info->shared_ctl_off +
                               2001                 :           5971 :                             info->shared_data_off;
                               2002                 :                :                     else
                               2003                 :                :                     {
                               2004                 :              5 :                         int         idx = kind - PGSTAT_KIND_CUSTOM_MIN;
                               2005                 :                : 
                               2006                 :              5 :                         ptr = ((char *) shmem->custom_data[idx]) +
                               2007                 :              5 :                             info->shared_data_off;
                               2008                 :                :                     }
                               2009                 :                : 
  113                          2010         [ -  + ]:           5976 :                     if (!read_chunk(fpin, ptr, info->shared_data_len))
                               2011                 :                :                     {
  823 michael@paquier.xyz      2012         [ #  # ]:UBC           0 :                         elog(WARNING, "could not read data of stats kind %u for entry of type %c with size %u",
                               2013                 :                :                              kind, t, info->shared_data_len);
  847                          2014                 :              0 :                         goto error;
                               2015                 :                :                     }
                               2016                 :                : 
  847 michael@paquier.xyz      2017                 :CBC        5976 :                     break;
                               2018                 :                :                 }
  855                          2019                 :         238053 :             case PGSTAT_FILE_ENTRY_HASH:
                               2020                 :                :             case PGSTAT_FILE_ENTRY_NAME:
                               2021                 :                :                 {
                               2022                 :                :                     PgStat_HashKey key;
                               2023                 :                :                     PgStatShared_HashEntry *p;
                               2024                 :                :                     PgStatShared_Common *header;
  325                          2025                 :         238053 :                     const PgStat_KindInfo *kind_info = NULL;
                               2026                 :                :                     dsa_pointer chunk;
                               2027                 :                : 
 1674 andres@anarazel.de       2028         [ -  + ]:         238053 :                     CHECK_FOR_INTERRUPTS();
                               2029                 :                : 
  855 michael@paquier.xyz      2030         [ +  + ]:         238053 :                     if (t == PGSTAT_FILE_ENTRY_HASH)
                               2031                 :                :                     {
                               2032                 :                :                         /* normal stats entry, identified by PgStat_HashKey */
  113                          2033         [ -  + ]:         237964 :                         if (!read_chunk_s(fpin, &key))
                               2034                 :                :                         {
  828 michael@paquier.xyz      2035         [ #  # ]:UBC           0 :                             elog(WARNING, "could not read key for entry of type %c", t);
 1674 andres@anarazel.de       2036                 :              0 :                             goto error;
                               2037                 :                :                         }
                               2038                 :                : 
 1674 andres@anarazel.de       2039         [ -  + ]:CBC      237964 :                         if (!pgstat_is_kind_valid(key.kind))
                               2040                 :                :                         {
  586 peter@eisentraut.org     2041         [ #  # ]:UBC           0 :                             elog(WARNING, "invalid stats kind for entry %u/%u/%" PRIu64 " of type %c",
                               2042                 :                :                                  key.kind, key.dboid,
                               2043                 :                :                                  key.objid, t);
 1674 andres@anarazel.de       2044                 :              0 :                             goto error;
                               2045                 :                :                         }
                               2046                 :                : 
  325 michael@paquier.xyz      2047                 :CBC      237964 :                         kind_info = pgstat_get_kind_info(key.kind);
                               2048         [ -  + ]:         237964 :                         if (!kind_info)
                               2049                 :                :                         {
  560 michael@paquier.xyz      2050         [ #  # ]:UBC           0 :                             elog(WARNING, "could not find information of kind for entry %u/%u/%" PRIu64 " of type %c",
                               2051                 :                :                                  key.kind, key.dboid,
                               2052                 :                :                                  key.objid, t);
                               2053                 :              0 :                             goto error;
                               2054                 :                :                         }
                               2055                 :                : 
   21 michael@paquier.xyz      2056         [ -  + ]:GNC      237964 :                         if (kind_info->fixed_amount)
                               2057                 :                :                         {
   21 michael@paquier.xyz      2058         [ #  # ]:UNC           0 :                             elog(WARNING, "invalid fixed_amount in stats kind for entry %u/%u/%" PRIu64 " of type %c",
                               2059                 :                :                                  key.kind, key.dboid,
                               2060                 :                :                                  key.objid, t);
                               2061                 :              0 :                             goto error;
                               2062                 :                :                         }
                               2063                 :                :                     }
                               2064                 :                :                     else
                               2065                 :                :                     {
                               2066                 :                :                         /* stats entry identified by name on disk (e.g. slots) */
                               2067                 :                :                         PgStat_Kind kind;
                               2068                 :                :                         NameData    name;
                               2069                 :                : 
  113 michael@paquier.xyz      2070         [ -  + ]:CBC          89 :                         if (!read_chunk_s(fpin, &kind))
                               2071                 :                :                         {
  828 michael@paquier.xyz      2072         [ #  # ]:UBC           0 :                             elog(WARNING, "could not read stats kind for entry of type %c", t);
 1674 andres@anarazel.de       2073                 :              0 :                             goto error;
                               2074                 :                :                         }
  113 michael@paquier.xyz      2075         [ -  + ]:CBC          89 :                         if (!read_chunk_s(fpin, &name))
                               2076                 :                :                         {
  823 michael@paquier.xyz      2077         [ #  # ]:UBC           0 :                             elog(WARNING, "could not read name of stats kind %u for entry of type %c",
                               2078                 :                :                                  kind, t);
 1674 andres@anarazel.de       2079                 :              0 :                             goto error;
                               2080                 :                :                         }
 1674 andres@anarazel.de       2081         [ -  + ]:CBC          89 :                         if (!pgstat_is_kind_valid(kind))
                               2082                 :                :                         {
  823 michael@paquier.xyz      2083         [ #  # ]:UBC           0 :                             elog(WARNING, "invalid stats kind %u for entry of type %c",
                               2084                 :                :                                  kind, t);
 1674 andres@anarazel.de       2085                 :              0 :                             goto error;
                               2086                 :                :                         }
                               2087                 :                : 
 1674 andres@anarazel.de       2088                 :CBC          89 :                         kind_info = pgstat_get_kind_info(kind);
  791 michael@paquier.xyz      2089         [ -  + ]:             89 :                         if (!kind_info)
                               2090                 :                :                         {
  791 michael@paquier.xyz      2091         [ #  # ]:UBC           0 :                             elog(WARNING, "could not find information of kind %u for entry of type %c",
                               2092                 :                :                                  kind, t);
                               2093                 :              0 :                             goto error;
                               2094                 :                :                         }
                               2095                 :                : 
 1674 andres@anarazel.de       2096         [ -  + ]:CBC          89 :                         if (!kind_info->from_serialized_name)
                               2097                 :                :                         {
  823 michael@paquier.xyz      2098         [ #  # ]:UBC           0 :                             elog(WARNING, "invalid from_serialized_name in stats kind %u for entry of type %c",
                               2099                 :                :                                  kind, t);
 1674 andres@anarazel.de       2100                 :              0 :                             goto error;
                               2101                 :                :                         }
                               2102                 :                : 
 1674 andres@anarazel.de       2103         [ +  + ]:CBC          89 :                         if (!kind_info->from_serialized_name(&name, &key))
                               2104                 :                :                         {
                               2105                 :                :                             /* skip over data for entry we don't care about */
                               2106         [ -  + ]:              1 :                             if (fseek(fpin, pgstat_get_entry_len(kind), SEEK_CUR) != 0)
                               2107                 :                :                             {
  823 michael@paquier.xyz      2108         [ #  # ]:UBC           0 :                                 elog(WARNING, "could not seek \"%s\" of stats kind %u for entry of type %c",
                               2109                 :                :                                      NameStr(name), kind, t);
 1674 andres@anarazel.de       2110                 :              0 :                                 goto error;
                               2111                 :                :                             }
                               2112                 :                : 
 1674 andres@anarazel.de       2113                 :CBC           1 :                             continue;
                               2114                 :                :                         }
                               2115                 :                : 
                               2116         [ -  + ]:             88 :                         Assert(key.kind == kind);
                               2117                 :                :                     }
                               2118                 :                : 
                               2119                 :                :                     /*
                               2120                 :                :                      * This intentionally doesn't use pgstat_get_entry_ref() -
                               2121                 :                :                      * putting all stats into checkpointer's
                               2122                 :                :                      * pgStatEntryRefHash would be wasted effort and memory.
                               2123                 :                :                      *
                               2124                 :                :                      * Allocate the DSA body before inserting the hash entry.
                               2125                 :                :                      */
   42 michael@paquier.xyz      2126                 :GNC      238052 :                     chunk = pgstat_alloc_entry_body(key.kind);
                               2127         [ -  + ]:         238052 :                     if (chunk == InvalidDsaPointer)
                               2128                 :                :                     {
                               2129                 :                :                         /*
                               2130                 :                :                          * It would be tempting to switch this ERROR to a
                               2131                 :                :                          * WARNING, but it would mean that all the statistics
                               2132                 :                :                          * are discarded when the environment fails on OOM.
                               2133                 :                :                          */
   42 michael@paquier.xyz      2134         [ #  # ]:UNC           0 :                         elog(ERROR, "could not allocate entry %u/%u/%" PRIu64 " of type %c",
                               2135                 :                :                              key.kind, key.dboid,
                               2136                 :                :                              key.objid, t);
                               2137                 :                :                     }
                               2138                 :                : 
   23 michael@paquier.xyz      2139                 :GNC      238052 :                     p = dshash_find_or_insert_extended(pgStatLocal.kind_hash[key.kind],
                               2140                 :                :                                                        &key, &found,
                               2141                 :                :                                                        DSHASH_INSERT_NO_OOM);
   42                          2142         [ -  + ]:         238052 :                     if (!p)
                               2143                 :                :                     {
   23 michael@paquier.xyz      2144                 :UNC           0 :                         dsa_free(pgStatLocal.kind_dsa[key.kind], chunk);
                               2145                 :                : 
                               2146                 :                :                         /*
                               2147                 :                :                          * for the same reason as previously, ERROR not
                               2148                 :                :                          * WARNING
                               2149                 :                :                          */
   42                          2150         [ #  # ]:              0 :                         elog(ERROR, "could not insert entry %u/%u/%" PRIu64 " of type %c",
                               2151                 :                :                              key.kind, key.dboid,
                               2152                 :                :                              key.objid, t);
                               2153                 :                :                     }
                               2154                 :                : 
                               2155                 :                :                     /* don't allow duplicate entries */
   42 michael@paquier.xyz      2156         [ -  + ]:GNC      238052 :                     if (found)
                               2157                 :                :                     {
   23 michael@paquier.xyz      2158                 :UNC           0 :                         dshash_release_lock(pgStatLocal.kind_hash[key.kind], p);
                               2159                 :              0 :                         dsa_free(pgStatLocal.kind_dsa[key.kind], chunk);
   42                          2160         [ #  # ]:              0 :                         elog(WARNING, "found duplicate stats entry %u/%u/%" PRIu64 " of type %c",
                               2161                 :                :                              key.kind, key.dboid,
                               2162                 :                :                              key.objid, t);
                               2163                 :              0 :                         goto error;
                               2164                 :                :                     }
                               2165                 :                : 
   42 michael@paquier.xyz      2166                 :GNC      238052 :                     header = pgstat_init_entry(key.kind, p, chunk);
   23                          2167                 :         238052 :                     dshash_release_lock(pgStatLocal.kind_hash[key.kind], p);
                               2168                 :                : 
  113 michael@paquier.xyz      2169         [ -  + ]:CBC      238052 :                     if (!read_chunk(fpin,
                               2170                 :                :                                     pgstat_get_entry_data(key.kind, header),
                               2171                 :                :                                     pgstat_get_entry_len(key.kind)))
                               2172                 :                :                     {
  586 peter@eisentraut.org     2173         [ #  # ]:UBC           0 :                         elog(WARNING, "could not read data for entry %u/%u/%" PRIu64 " of type %c",
                               2174                 :                :                              key.kind, key.dboid,
                               2175                 :                :                              key.objid, t);
 1674 andres@anarazel.de       2176                 :              0 :                         goto error;
                               2177                 :                :                     }
                               2178                 :                : 
                               2179                 :                :                     /* read more data for the entry, if required */
  325 michael@paquier.xyz      2180         [ +  + ]:CBC      238052 :                     if (kind_info->from_serialized_data)
                               2181                 :                :                     {
                               2182         [ -  + ]:              4 :                         if (!kind_info->from_serialized_data(&key, header, fpin))
                               2183                 :                :                         {
  325 michael@paquier.xyz      2184         [ #  # ]:UBC           0 :                             elog(WARNING, "could not read auxiliary data for entry %u/%u/%" PRIu64 " of type %c",
                               2185                 :                :                                  key.kind, key.dboid,
                               2186                 :                :                                  key.objid, t);
                               2187                 :              0 :                             goto error;
                               2188                 :                :                         }
                               2189                 :                :                     }
                               2190                 :                : 
 1710 akapila@postgresql.o     2191                 :CBC      238052 :                     break;
                               2192                 :                :                 }
  855 michael@paquier.xyz      2193                 :            853 :             case PGSTAT_FILE_ENTRY_END:
                               2194                 :                : 
                               2195                 :                :                 /*
                               2196                 :                :                  * check that PGSTAT_FILE_ENTRY_END actually signals end of
                               2197                 :                :                  * file
                               2198                 :                :                  */
 1664 andres@anarazel.de       2199         [ +  + ]:            853 :                 if (fgetc(fpin) != EOF)
                               2200                 :                :                 {
  828 michael@paquier.xyz      2201         [ +  - ]:              1 :                     elog(WARNING, "could not read end-of-file");
 1664 andres@anarazel.de       2202                 :              1 :                     goto error;
                               2203                 :                :                 }
                               2204                 :                : 
 5008 alvherre@alvh.no-ip.     2205                 :            852 :                 goto done;
                               2206                 :                : 
 5008 alvherre@alvh.no-ip.     2207                 :UBC           0 :             default:
  828 michael@paquier.xyz      2208         [ #  # ]:              0 :                 elog(WARNING, "could not read entry of type %c", t);
 1674 andres@anarazel.de       2209                 :              0 :                 goto error;
                               2210                 :                :         }
                               2211                 :                :     }
                               2212                 :                : 
 5008 alvherre@alvh.no-ip.     2213                 :CBC         854 : done:
                               2214                 :                :     /* First, cleanup the main stats file */
                               2215                 :            854 :     FreeFile(fpin);
                               2216                 :                : 
 1674 andres@anarazel.de       2217         [ +  + ]:            854 :     elog(DEBUG2, "removing permanent stats file \"%s\"", statfile);
                               2218                 :            854 :     unlink(statfile);
                               2219                 :                : 
  113 michael@paquier.xyz      2220                 :            914 : finish:
                               2221                 :                :     /* Finish callbacks, if required */
  325                          2222         [ +  + ]:          30162 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                               2223                 :                :     {
                               2224                 :          29248 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               2225                 :                : 
                               2226   [ +  +  +  + ]:          29248 :         if (kind_info && kind_info->finish)
  113                          2227                 :              6 :             kind_info->finish(status);
                               2228                 :                :     }
                               2229                 :                : 
 1674 andres@anarazel.de       2230                 :            914 :     return;
                               2231                 :                : 
                               2232                 :              2 : error:
                               2233         [ +  - ]:              2 :     ereport(LOG,
                               2234                 :                :             (errmsg("corrupted statistics file \"%s\"", statfile)));
                               2235                 :                : 
 1666                          2236                 :              2 :     pgstat_reset_after_failure();
  113 michael@paquier.xyz      2237                 :              2 :     status = STATS_DISCARD;
                               2238                 :                : 
 1674 andres@anarazel.de       2239                 :              2 :     goto done;
                               2240                 :                : }
                               2241                 :                : 
                               2242                 :                : /*
                               2243                 :                :  * Helper to reset / drop stats after a crash or after restoring stats from
                               2244                 :                :  * disk failed, potentially after already loading parts.
                               2245                 :                :  */
                               2246                 :                : static void
 1666                          2247                 :            273 : pgstat_reset_after_failure(void)
                               2248                 :                : {
                               2249                 :            273 :     TimestampTz ts = GetCurrentTimestamp();
                               2250                 :                : 
                               2251                 :                :     /* reset fixed-numbered stats */
  823 michael@paquier.xyz      2252         [ +  + ]:           9009 :     for (PgStat_Kind kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++)
                               2253                 :                :     {
 1674 andres@anarazel.de       2254                 :           8736 :         const PgStat_KindInfo *kind_info = pgstat_get_kind_info(kind);
                               2255                 :                : 
  823 michael@paquier.xyz      2256   [ +  +  +  + ]:           8736 :         if (!kind_info || !kind_info->fixed_amount)
 1674 andres@anarazel.de       2257                 :           6822 :             continue;
                               2258                 :                : 
                               2259                 :           1914 :         kind_info->reset_all_cb(ts);
                               2260                 :                :     }
                               2261                 :                : 
                               2262                 :                :     /* and drop variable-numbered ones */
                               2263                 :            273 :     pgstat_drop_all_entries();
 1801 akapila@postgresql.o     2264                 :            273 : }
                               2265                 :                : 
                               2266                 :                : /*
                               2267                 :                :  * GUC assign_hook for stats_fetch_consistency.
                               2268                 :                :  */
                               2269                 :                : void
 1275 michael@paquier.xyz      2270                 :           2172 : assign_stats_fetch_consistency(int newval, void *extra)
                               2271                 :                : {
                               2272                 :                :     /*
                               2273                 :                :      * Changing this value in a transaction may cause snapshot state
                               2274                 :                :      * inconsistencies, so force a clear of the current snapshot on the next
                               2275                 :                :      * snapshot build attempt.
                               2276                 :                :      */
                               2277         [ +  + ]:           2172 :     if (pgstat_fetch_consistency != newval)
                               2278                 :            716 :         force_stats_snapshot_clear = true;
                               2279                 :           2172 : }
        

Generated by: LCOV version 2.0-1