Line data Source code
1 : /* -------------------------------------------------------------------------
2 : *
3 : * pgstat_lock.c
4 : * Implementation of lock statistics.
5 : *
6 : * This file contains the implementation of lock statistics. It is kept
7 : * separate from pgstat.c to enforce the line between the statistics
8 : * access / storage implementation and the details about individual types
9 : * of statistics.
10 : *
11 : * Copyright (c) 2021-2026, PostgreSQL Global Development Group
12 : *
13 : * IDENTIFICATION
14 : * src/backend/utils/activity/pgstat_lock.c
15 : * -------------------------------------------------------------------------
16 : */
17 :
18 : #include "postgres.h"
19 :
20 : #include "utils/pgstat_internal.h"
21 :
22 : static PgStat_PendingLock PendingLockStats;
23 : static bool have_lockstats = false;
24 :
25 : PgStat_Lock *
26 8 : pgstat_fetch_stat_lock(void)
27 : {
28 8 : pgstat_snapshot_fixed(PGSTAT_KIND_LOCK);
29 :
30 8 : return &pgStatLocal.snapshot.lock;
31 : }
32 :
33 : /*
34 : * Simpler wrapper of pgstat_lock_flush_cb()
35 : */
36 : void
37 0 : pgstat_lock_flush(bool nowait)
38 : {
39 0 : (void) pgstat_lock_flush_cb(nowait);
40 0 : }
41 :
42 : /*
43 : * Flush out locally pending lock statistics
44 : *
45 : * If no stats have been recorded, this function returns false.
46 : *
47 : * If nowait is true, this function returns true if the lock could not be
48 : * acquired. Otherwise, return false.
49 : */
50 : bool
51 39215 : pgstat_lock_flush_cb(bool nowait)
52 : {
53 : LWLock *lcktype_lock;
54 : PgStat_LockEntry *lck_shstats;
55 39215 : bool lock_not_acquired = false;
56 :
57 39215 : if (!have_lockstats)
58 38905 : return false;
59 :
60 4030 : for (int i = 0; i <= LOCKTAG_LAST_TYPE; i++)
61 : {
62 3720 : lcktype_lock = &pgStatLocal.shmem->lock.locks[i];
63 3720 : lck_shstats =
64 3720 : &pgStatLocal.shmem->lock.stats.stats[i];
65 :
66 3720 : if (!nowait)
67 3396 : LWLockAcquire(lcktype_lock, LW_EXCLUSIVE);
68 324 : else if (!LWLockConditionalAcquire(lcktype_lock, LW_EXCLUSIVE))
69 : {
70 0 : lock_not_acquired = true;
71 0 : continue;
72 : }
73 :
74 : #define LOCKSTAT_ACC(fld) \
75 : (lck_shstats->fld += PendingLockStats.stats[i].fld)
76 3720 : LOCKSTAT_ACC(waits);
77 3720 : LOCKSTAT_ACC(wait_time);
78 3720 : LOCKSTAT_ACC(fastpath_exceeded);
79 : #undef LOCKSTAT_ACC
80 :
81 3720 : LWLockRelease(lcktype_lock);
82 : }
83 :
84 310 : memset(&PendingLockStats, 0, sizeof(PendingLockStats));
85 :
86 310 : have_lockstats = false;
87 :
88 310 : return lock_not_acquired;
89 : }
90 :
91 :
92 : void
93 1180 : pgstat_lock_init_shmem_cb(void *stats)
94 : {
95 1180 : PgStatShared_Lock *stat_shmem = (PgStatShared_Lock *) stats;
96 :
97 15340 : for (int i = 0; i <= LOCKTAG_LAST_TYPE; i++)
98 14160 : LWLockInitialize(&stat_shmem->locks[i], LWTRANCHE_PGSTATS_DATA);
99 1180 : }
100 :
101 : void
102 242 : pgstat_lock_reset_all_cb(TimestampTz ts)
103 : {
104 3146 : for (int i = 0; i <= LOCKTAG_LAST_TYPE; i++)
105 : {
106 2904 : LWLock *lcktype_lock = &pgStatLocal.shmem->lock.locks[i];
107 2904 : PgStat_LockEntry *lck_shstats = &pgStatLocal.shmem->lock.stats.stats[i];
108 :
109 2904 : LWLockAcquire(lcktype_lock, LW_EXCLUSIVE);
110 :
111 : /*
112 : * Use the lock in the first lock type PgStat_LockEntry to protect the
113 : * reset timestamp as well.
114 : */
115 2904 : if (i == 0)
116 242 : pgStatLocal.shmem->lock.stats.stat_reset_timestamp = ts;
117 :
118 2904 : memset(lck_shstats, 0, sizeof(*lck_shstats));
119 2904 : LWLockRelease(lcktype_lock);
120 : }
121 242 : }
122 :
123 : void
124 757 : pgstat_lock_snapshot_cb(void)
125 : {
126 9841 : for (int i = 0; i <= LOCKTAG_LAST_TYPE; i++)
127 : {
128 9084 : LWLock *lcktype_lock = &pgStatLocal.shmem->lock.locks[i];
129 9084 : PgStat_LockEntry *lck_shstats = &pgStatLocal.shmem->lock.stats.stats[i];
130 9084 : PgStat_LockEntry *lck_snap = &pgStatLocal.snapshot.lock.stats[i];
131 :
132 9084 : LWLockAcquire(lcktype_lock, LW_SHARED);
133 :
134 : /*
135 : * Use the lock in the first lock type PgStat_LockEntry to protect the
136 : * reset timestamp as well.
137 : */
138 9084 : if (i == 0)
139 757 : pgStatLocal.snapshot.lock.stat_reset_timestamp =
140 757 : pgStatLocal.shmem->lock.stats.stat_reset_timestamp;
141 :
142 : /* using struct assignment due to better type safety */
143 9084 : *lck_snap = *lck_shstats;
144 9084 : LWLockRelease(lcktype_lock);
145 : }
146 757 : }
147 :
148 : /*
149 : * Increment counter for lock not acquired with the fast-path, per lock
150 : * type, due to the fast-path slot limit reached.
151 : *
152 : * Note: This function should not be called in performance-sensitive paths,
153 : * like lock acquisitions.
154 : */
155 : void
156 254391 : pgstat_count_lock_fastpath_exceeded(uint8 locktag_type)
157 : {
158 : Assert(locktag_type <= LOCKTAG_LAST_TYPE);
159 254391 : PendingLockStats.stats[locktag_type].fastpath_exceeded++;
160 254391 : have_lockstats = true;
161 254391 : pgstat_report_fixed = true;
162 254391 : }
163 :
164 : /*
165 : * Increment the number of waits and wait time, per lock type.
166 : *
167 : * Note: This function should not be called in performance-sensitive paths,
168 : * like lock acquisitions.
169 : */
170 : void
171 25 : pgstat_count_lock_waits(uint8 locktag_type, long msecs)
172 : {
173 : Assert(locktag_type <= LOCKTAG_LAST_TYPE);
174 25 : PendingLockStats.stats[locktag_type].waits++;
175 25 : PendingLockStats.stats[locktag_type].wait_time += (PgStat_Counter) msecs;
176 25 : have_lockstats = true;
177 25 : pgstat_report_fixed = true;
178 25 : }
|