/src/postgres/src/backend/utils/activity/pgstat_index.c
Line | Count | Source |
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 | | pgstat_index_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) |
36 | 0 | { |
37 | 0 | Oid dboid; |
38 | 0 | PgStat_TableStatus *lstats; /* pending stats entry */ |
39 | 0 | PgStatShared_Index *shidxstats; |
40 | 0 | PgStat_StatIdxEntry *idxentry; /* index entry of shared stats */ |
41 | 0 | PgStat_StatDBEntry *dbentry; /* pending database entry */ |
42 | |
|
43 | 0 | dboid = entry_ref->shared_entry->key.dboid; |
44 | 0 | lstats = (PgStat_TableStatus *) entry_ref->pending; |
45 | 0 | 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 | 0 | if (pg_memory_is_all_zeros(&lstats->counts, |
52 | 0 | sizeof(struct PgStat_TableCounts))) |
53 | 0 | return true; |
54 | | |
55 | 0 | if (!pgstat_lock_entry(entry_ref, nowait)) |
56 | 0 | return false; |
57 | | |
58 | | /* Add the values to the shared entry. */ |
59 | 0 | idxentry = &shidxstats->stats; |
60 | |
|
61 | 0 | idxentry->numscans += lstats->counts.numscans; |
62 | 0 | if (lstats->counts.numscans) |
63 | 0 | { |
64 | 0 | TimestampTz t = GetCurrentTransactionStopTimestamp(); |
65 | |
|
66 | 0 | if (t > idxentry->lastscan) |
67 | 0 | idxentry->lastscan = t; |
68 | 0 | } |
69 | 0 | idxentry->tuples_returned += lstats->counts.tuples_returned; |
70 | 0 | idxentry->tuples_fetched += lstats->counts.tuples_fetched; |
71 | 0 | idxentry->blocks_fetched += lstats->counts.blocks_fetched; |
72 | 0 | idxentry->blocks_hit += lstats->counts.blocks_hit; |
73 | |
|
74 | 0 | pgstat_unlock_entry(entry_ref); |
75 | | |
76 | | /* The entry was successfully flushed, add the same to database stats */ |
77 | 0 | dbentry = pgstat_prep_database_pending(dboid); |
78 | 0 | dbentry->tuples_returned += lstats->counts.tuples_returned; |
79 | 0 | dbentry->tuples_fetched += lstats->counts.tuples_fetched; |
80 | 0 | dbentry->blocks_fetched += lstats->counts.blocks_fetched; |
81 | 0 | dbentry->blocks_hit += lstats->counts.blocks_hit; |
82 | |
|
83 | 0 | return true; |
84 | 0 | } |
85 | | |
86 | | /* |
87 | | * Callback to delete pending index stats. |
88 | | */ |
89 | | void |
90 | | pgstat_index_delete_pending_cb(PgStat_EntryRef *entry_ref) |
91 | 0 | { |
92 | 0 | PgStat_TableStatus *pending = (PgStat_TableStatus *) entry_ref->pending; |
93 | |
|
94 | 0 | if (pending->relation) |
95 | 0 | pgstat_unlink_relation(pending->relation); |
96 | 0 | } |
97 | | |
98 | | /* |
99 | | * Callback to reset the timestamp on an index stats entry. |
100 | | */ |
101 | | void |
102 | | pgstat_index_reset_timestamp_cb(PgStatShared_Common *header, TimestampTz ts) |
103 | 0 | { |
104 | 0 | ((PgStatShared_Index *) header)->stats.stat_reset_time = ts; |
105 | 0 | } |
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 | | pgstat_fetch_stat_idxentry(Oid relid) |
115 | 0 | { |
116 | 0 | return pgstat_fetch_stat_idxentry_ext(IsSharedRelation(relid), relid, NULL); |
117 | 0 | } |
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 | | pgstat_fetch_stat_idxentry_ext(bool shared, Oid reloid, bool *may_free) |
126 | 0 | { |
127 | 0 | Oid dboid = (shared ? InvalidOid : MyDatabaseId); |
128 | |
|
129 | 0 | return (PgStat_StatIdxEntry *) |
130 | 0 | pgstat_fetch_entry(PGSTAT_KIND_INDEX, dboid, reloid, may_free); |
131 | 0 | } |