Branch data Line data Source code
1 : : /* -------------------------------------------------------------------------
2 : : *
3 : : * pgstat_index.c
4 : : * Implementation of index statistics.
5 : : *
6 : : * This file contains the implementation of index statistics.
7 : : *
8 : : * Copyright (c) 2001-2026, PostgreSQL Global Development Group
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/utils/activity/pgstat_index.c
12 : : * -------------------------------------------------------------------------
13 : : */
14 : :
15 : : #include "postgres.h"
16 : :
17 : : #include "access/xact.h"
18 : : #include "catalog/catalog.h"
19 : : #include "utils/memutils.h"
20 : : #include "utils/pgstat_internal.h"
21 : : #include "utils/rel.h"
22 : : #include "utils/timestamp.h"
23 : :
24 : :
25 : : /*
26 : : * Flush out pending stats for an index entry.
27 : : *
28 : : * If nowait is true and the lock could not be immediately acquired, returns
29 : : * false without flushing the entry. Otherwise returns true.
30 : : *
31 : : * Some of the stats are copied to the corresponding pending database stats
32 : : * entry when successfully flushing.
33 : : */
34 : : bool
35 : 687290 : pgstat_index_flush_cb(PgStat_EntryRef *entry_ref, bool nowait)
36 : : {
37 : : Oid dboid;
38 : : PgStat_RelationStatus *lstats; /* pending stats entry */
39 : : PgStatShared_Index *shidxstats;
40 : : PgStat_StatIdxEntry *idxentry; /* index entry of shared stats */
41 : : PgStat_StatDBEntry *dbentry; /* pending database entry */
42 : :
43 : 687290 : dboid = entry_ref->shared_entry->key.dboid;
44 : 687290 : lstats = (PgStat_RelationStatus *) entry_ref->pending;
45 : 687290 : shidxstats = (PgStatShared_Index *) entry_ref->shared_stats;
46 : :
47 : : /*
48 : : * Ignore entries that didn't accumulate any actual counts, such as
49 : : * indexes that were opened by the planner but not used.
50 : : */
51 [ + + ]: 687290 : if (pg_memory_is_all_zeros(&lstats->idx,
52 : : sizeof(struct PgStat_IndexCounts)))
53 : 74 : return true;
54 : :
55 [ + + ]: 687216 : if (!pgstat_lock_entry(entry_ref, nowait))
56 : 1 : return false;
57 : :
58 : : /* Add the values to the shared entry. */
59 : 687215 : idxentry = &shidxstats->stats;
60 : :
61 : 687215 : idxentry->numscans += lstats->idx.numscans;
62 [ + + ]: 687215 : if (lstats->idx.numscans)
63 : : {
64 : 498502 : TimestampTz t = GetCurrentTransactionStopTimestamp();
65 : :
66 [ + + ]: 498502 : if (t > idxentry->lastscan)
67 : 487257 : idxentry->lastscan = t;
68 : : }
69 : 687215 : idxentry->tuples_returned += lstats->idx.tuples_returned;
70 : 687215 : idxentry->tuples_fetched += lstats->idx.tuples_fetched;
71 : 687215 : idxentry->blocks_fetched += lstats->idx.blocks_fetched;
72 : 687215 : idxentry->blocks_hit += lstats->idx.blocks_hit;
73 : :
74 : 687215 : pgstat_unlock_entry(entry_ref);
75 : :
76 : : /* The entry was successfully flushed, add the same to database stats */
77 : 687215 : dbentry = pgstat_prep_database_pending(dboid);
78 : 687215 : dbentry->tuples_returned += lstats->idx.tuples_returned;
79 : 687215 : dbentry->tuples_fetched += lstats->idx.tuples_fetched;
80 : 687215 : dbentry->blocks_fetched += lstats->idx.blocks_fetched;
81 : 687215 : dbentry->blocks_hit += lstats->idx.blocks_hit;
82 : :
83 : 687215 : return true;
84 : : }
85 : :
86 : : /*
87 : : * Callback to delete pending index stats.
88 : : */
89 : : void
90 : 702739 : pgstat_index_delete_pending_cb(PgStat_EntryRef *entry_ref)
91 : : {
92 : 702739 : PgStat_RelationStatus *pending = (PgStat_RelationStatus *) entry_ref->pending;
93 : :
94 [ + + ]: 702739 : if (pending->relation)
95 : 676299 : pgstat_unlink_relation(pending->relation);
96 : 702739 : }
97 : :
98 : : /*
99 : : * Callback to reset the timestamp on an index stats entry.
100 : : */
101 : : void
102 : 4127 : pgstat_index_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts)
103 : : {
104 : 4127 : ((PgStatShared_Index *) header)->stats.stat_reset_time = ts;
105 : 4127 : }
106 : :
107 : : /*
108 : : * Support function for the SQL-callable pgstat* functions. Returns
109 : : * the collected statistics for one index or NULL. NULL doesn't mean
110 : : * that the index doesn't exist, just that there are no statistics, so the
111 : : * caller is better off to report ZERO instead.
112 : : */
113 : : PgStat_StatIdxEntry *
114 : 195 : pgstat_fetch_stat_idxentry(Oid relid)
115 : : {
116 : 195 : return pgstat_fetch_stat_idxentry_ext(IsSharedRelation(relid), relid, NULL);
117 : : }
118 : :
119 : : /*
120 : : * More efficient version of pgstat_fetch_stat_idxentry(), allowing to specify
121 : : * whether the to-be-accessed index is a shared relation or not. This version
122 : : * also returns whether the caller can pfree() the result if desired.
123 : : */
124 : : PgStat_StatIdxEntry *
125 : 524 : pgstat_fetch_stat_idxentry_ext(bool shared, Oid reloid, bool *may_free)
126 : : {
127 [ - + ]: 524 : Oid dboid = (shared ? InvalidOid : MyDatabaseId);
128 : :
129 : 524 : return (PgStat_StatIdxEntry *)
130 : 524 : pgstat_fetch_entry(PGSTAT_KIND_INDEX, dboid, reloid, may_free);
131 : : }
|